[PD-cvs] SF.net SVN: pure-data:[10275] trunk/externals/loaders

zmoelnig at users.sourceforge.net zmoelnig at users.sourceforge.net
Wed Sep 3 11:34:51 CEST 2008


Revision: 10275
          http://pure-data.svn.sourceforge.net/pure-data/?rev=10275&view=rev
Author:   zmoelnig
Date:     2008-09-03 09:34:50 +0000 (Wed, 03 Sep 2008)

Log Message:
-----------
added stephen sinclairs "urloader"

Added Paths:
-----------
    trunk/externals/loaders/urloader/
    trunk/externals/loaders/urloader/Makefile
    trunk/externals/loaders/urloader/another.pd
    trunk/externals/loaders/urloader/baseurl.c
    trunk/externals/loaders/urloader/baseurl.h
    trunk/externals/loaders/urloader/md5.c
    trunk/externals/loaders/urloader/md5.h
    trunk/externals/loaders/urloader/pd.index
    trunk/externals/loaders/urloader/test.pd
    trunk/externals/loaders/urloader/unknown.pd
    trunk/externals/loaders/urloader/urlloader.c

Added: trunk/externals/loaders/urloader/Makefile
===================================================================
--- trunk/externals/loaders/urloader/Makefile	                        (rev 0)
+++ trunk/externals/loaders/urloader/Makefile	2008-09-03 09:34:50 UTC (rev 10275)
@@ -0,0 +1,167 @@
+# Makefile
+# based on hexloader Makefile (c) 2007 IOhannes m zm\xF6lnig
+
+# path to pd
+## change this according to your setup!
+PDROOT=../../../pd
+
+# here we find the sources of pd (and evtl. the pd.lib)
+PDSRCDIR=$(PDROOT)/src
+PDLIBDIR=$(PDROOT)/bin
+
+# this is the filename-extension
+# people have to specify it at the cmdline: eg "make pd_linux"
+EXTENSION=$(MAKECMDGOALS)
+
+
+DEFINES=-DPD
+
+# if no filename-extension is supplied by the user
+# try to guess one, based on what "uname" tells us
+UNAME := $(shell uname -s)
+ifeq ($(UNAME),Linux)
+  DEFAULTEXTENSION= pd_linux
+  DEFINES+=-DDL_OPEN
+else
+  ifeq ($(UNAME),Darwin)
+    DEFAULTEXTENSION= pd_darwin
+    DEFINES+=-DDL_OPEN
+  else
+    ifeq (MINGW,$(findstring MINGW,$(UNAME)))
+      DEFAULTEXTENSION=pd_nt
+    else
+      ifeq ($(UNAME),IRIX)
+	UNAMEV := $(shell uname -R)
+	ifeq (6.,$(findstring 6.,$(UNAMEV)))
+	  DEFAULTEXTENSION= pd_irix6
+          DEFINES+=-DDL_OPEN
+	else
+	  DEFAULTEXTENSION= pd_irix5
+          DEFINES+=-DDL_OPEN
+	endif
+      else
+	DEFAULTEXTENSION=help
+      endif
+    endif
+  endif
+endif
+
+# if no extension is given, call "make" again with a guessed extension
+auto:
+	make $(DEFAULTEXTENSION)
+
+# just a stupid fallback
+help: 
+	@echo "choose one command:  make pd_linux (linux), make pd_darwin (osX), make pd_irix5 (IRIX5), make pd_irix6 (IRIX6), make dll (MSVC), make pd_nt (MinWG)"
+
+# delete old build files
+clean:
+	-rm -f *.dll *.pd_* *.o *.obj *~
+
+# we want to compile all C-files we find in the current directory
+SOURCES=$(sort $(filter %.c, $(wildcard *.c)))
+# some C-files maps will become an external with the given filename-extension
+TARGETS=urlloader.pd_linux baseurl.pd_linux
+
+
+# ----------------------- Linux -----------------------
+
+pd_linux: $(TARGETS)
+
+LINUXCFLAGS = $(DEFINES) -funroll-loops -fomit-frame-pointer -fPIC \
+    -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+    -Wno-unused -Wno-parentheses -Wno-switch
+
+ifeq ($(DEBUG),1)
+LINUXCFLAGS += -ggdb
+else
+LINUXCFLAGS += -O2
+endif
+
+LINUXLDFLAGS =  -export_dynamic -shared  -lc -lm
+LINUXLIBS = -lcurl
+
+LINUXINCLUDE =  -I$(PDSRCDIR)
+
+%.pd_linux: %.c
+	$(CC) $(LINUXLDFLAGS) $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.pd_linux $*.c $(LINUXLIBS)
+	strip --strip-unneeded $*.pd_linux
+
+
+
+# ----------------------- Mac OSX -----------------------
+
+pd_darwin: $(TARGETS)
+
+DARWINCFLAGS = $(DEFINES) -O2 -Wall -W -Wshadow -Wstrict-prototypes \
+    -Wno-unused -Wno-parentheses -Wno-switch
+
+DARWININCLUDE = -I$(PDSRCDIR)
+
+DARWINLDFLAGS = -bundle -undefined suppress -flat_namespace
+
+%.pd_darwin: %.c
+	$(CC) $(DARWINCFLAGS) $(DARWININCLUDE) $(DARWINLDFLAGS) -o $*.pd_darwin $*.c
+
+
+# ----------------------- IRIX 5.x -----------------------
+pd_irix5: $(TARGETS)
+
+SGICFLAGS5 = -o32 $(DEFINES) -DSGI -O2
+
+SGIINCLUDE =  -I$(PDSRCDIR)
+
+SGILDFLAGS =  -elf -shared -rdata_shared
+
+%.pd_irix5: %.c
+	$(CC) $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c
+	$(LD) $(SGILDFLAGS) -o $*.pd_irix5 $*.o
+	rm $*.o
+
+
+# ----------------------- IRIX 6.x -----------------------
+pd_irix6: $(TARGETS)
+
+SGICFLAGS6 = $(DEFINES) -DSGI -n32 \
+	-OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \
+	-Ofast=ip32
+
+%.pd_irix6: %.c
+	$(CC) $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c
+	$(LD) $(SGILDFLAGS) -o $*.pd_irix6 $*.o
+	rm $*.o
+
+
+# ----------------------- NT -----------------------
+dll: $(TARGETS)
+
+PDNTCFLAGS = /W3 /WX /DPD /DNT /D__WIN32__ /DMSW /nologo
+
+VC="C:\Programme\Microsoft Visual Studio\Vc98"
+
+PDNTINCLUDE = /I. /I$(PDROOT)\tcl\include /I$(PDSRCDIR)\src /I$(VC)\include
+
+PDNTLDIR = $(VC)\lib
+
+PDNTLIB = $(PDNTLDIR)\libc.lib \
+	$(PDNTLDIR)\oldnames.lib \
+	$(PDNTLDIR)\kernel32.lib \
+	$(PDLIBDIR)\pd.lib 
+
+%.dll: %.c
+	cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
+	link /dll /export:$*_setup $*.obj $(PDNTLIB)
+
+
+pd_nt: $(TARGETS)
+
+MINGWCFLAGS = $(DEFINES) -O2 -funroll-loops -fomit-frame-pointer \
+    -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+    -Wno-unused -Wno-parentheses -Wno-switch -mms-bitfields
+
+MINGWLDFLAGS =  -export_dynamic -shared -lm -lkernel32 -lcoldname -lcrtdll -lpd -L$(PDLIBDIR)
+
+MINGWINCLUDE =  -I$(PDSRCDIR)
+
+%.pd_nt: %.c
+	$(CC) $(MINGWLDFLAGS) $(MINGWCFLAGS) $(MINGWINCLUDE) -o $*.dll $*.c

Added: trunk/externals/loaders/urloader/another.pd
===================================================================
--- trunk/externals/loaders/urloader/another.pd	                        (rev 0)
+++ trunk/externals/loaders/urloader/another.pd	2008-09-03 09:34:50 UTC (rev 10275)
@@ -0,0 +1,7 @@
+#N canvas 1 44 450 300 10;
+#X obj 35 50 inlet;
+#X obj 35 96 outlet;
+#X obj 35 73 * 2;
+#X text 141 50 Another patch on the web.;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;

Added: trunk/externals/loaders/urloader/baseurl.c
===================================================================
--- trunk/externals/loaders/urloader/baseurl.c	                        (rev 0)
+++ trunk/externals/loaders/urloader/baseurl.c	2008-09-03 09:34:50 UTC (rev 10275)
@@ -0,0 +1,58 @@
+/* Copyright (c) 2008 Steve Sinclair <radarsat1 at gmail.com>
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," that comes with Pd.  
+ */
+
+/*
+ * This code provides a canvas with a base URL to inform the baseurl
+ * where to look.
+ */
+
+
+#ifdef __WIN32__
+# define MSW
+#endif
+
+#include "m_pd.h"
+
+#if (PD_MINOR_VERSION >= 40)
+
+#include "s_stuff.h"
+#include "g_canvas.h"
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "baseurl.h"
+
+typedef void (*t_baseurl_setup)(void);
+
+/* definitions taken from s_loader.c  */
+typedef int (*loader_t)(t_canvas *canvas, char *classname);
+void sys_register_loader(loader_t loader);
+void class_set_extern_dir(t_symbol *s);
+
+/* ==================================================== */
+
+static t_class *baseurl_class;
+
+static char *version = "0.0.1";
+
+#endif /* PD_MINOR_VERSION>=40 */
+
+static void*baseurl_new(t_symbol *s, int argc, t_atom *argv)
+{
+  t_baseurl *x = (t_baseurl*)pd_new(baseurl_class);
+  SETSYMBOL(&x->url, argv[0].a_w.w_symbol);
+  return (x);
+}
+
+void baseurl_setup(void)
+{
+  post("baseurl %s",version);  
+  post("\twritten by Steve Sinclair");
+  post("\tcompiled on "__DATE__" at "__TIME__ " ");
+  post("\tcompiled against Pd version %d.%d.%d.%s", PD_MAJOR_VERSION, PD_MINOR_VERSION, PD_BUGFIX_VERSION, PD_TEST_VERSION);
+
+  baseurl_class = class_new(gensym("baseurl"), (t_newmethod)baseurl_new, 0, sizeof(t_baseurl), CLASS_NOINLET, A_GIMME, 0);
+}

Added: trunk/externals/loaders/urloader/baseurl.h
===================================================================
--- trunk/externals/loaders/urloader/baseurl.h	                        (rev 0)
+++ trunk/externals/loaders/urloader/baseurl.h	2008-09-03 09:34:50 UTC (rev 10275)
@@ -0,0 +1,15 @@
+/* Copyright (c) 2008 Steve Sinclair <radarsat1 at gmail.com>
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," that comes with Pd.  
+ */
+
+#ifndef BASEURL_H
+#define BASEURL_H
+
+typedef struct _baseurl
+{
+  t_object x_obj;
+  t_atom url;
+} t_baseurl;
+
+#endif // BASEURL_H

Added: trunk/externals/loaders/urloader/md5.c
===================================================================
--- trunk/externals/loaders/urloader/md5.c	                        (rev 0)
+++ trunk/externals/loaders/urloader/md5.c	2008-09-03 09:34:50 UTC (rev 10275)
@@ -0,0 +1,452 @@
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+   according to the definition of MD5 in RFC 1321 from April 1992.
+   Copyright (C) 1995, 1996, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+   NOTE: The canonical source of this file is maintained with the GNU C
+   Library.  Bugs can be reported to bug-glibc at prep.ai.mit.edu.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Ulrich Drepper <drepper at gnu.ai.mit.edu>, 1995.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "md5.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
+
+#ifdef _LIBC
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+#  define WORDS_BIGENDIAN 1
+# endif
+/* We need to keep the namespace clean so define the MD5 function
+   protected using leading __ .  */
+# define md5_init_ctx __md5_init_ctx
+# define md5_process_block __md5_process_block
+# define md5_process_bytes __md5_process_bytes
+# define md5_finish_ctx __md5_finish_ctx
+# define md5_read_ctx __md5_read_ctx
+# define md5_stream __md5_stream
+# define md5_buffer __md5_buffer
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n)							\
+    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+#define BLOCKSIZE 4096
+#if BLOCKSIZE % 64 != 0
+# error "invalid BLOCKSIZE"
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
+
+
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
+void
+md5_init_ctx (struct md5_ctx *ctx)
+{
+  ctx->A = 0x67452301;
+  ctx->B = 0xefcdab89;
+  ctx->C = 0x98badcfe;
+  ctx->D = 0x10325476;
+
+  ctx->total[0] = ctx->total[1] = 0;
+  ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF.  The result
+   must be in little endian byte order.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+void *
+md5_read_ctx (const struct md5_ctx *ctx, void *resbuf)
+{
+  ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+  ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+  ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+  ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+
+  return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+   prolog according to the standard and write the result to RESBUF.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+void *
+md5_finish_ctx (struct md5_ctx *ctx, void *resbuf)
+{
+  /* Take yet unprocessed bytes into account.  */
+  md5_uint32 bytes = ctx->buflen;
+  size_t pad;
+
+  /* Now count remaining bytes.  */
+  ctx->total[0] += bytes;
+  if (ctx->total[0] < bytes)
+    ++ctx->total[1];
+
+  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+  memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
+  *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+  *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+							(ctx->total[0] >> 29));
+
+  /* Process last bytes.  */
+  md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+  return md5_read_ctx (ctx, resbuf);
+}
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+int
+md5_stream (FILE *stream, void *resblock)
+{
+  struct md5_ctx ctx;
+  char buffer[BLOCKSIZE + 72];
+  size_t sum;
+
+  /* Initialize the computation context.  */
+  md5_init_ctx (&ctx);
+
+  /* Iterate over full file contents.  */
+  while (1)
+    {
+      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
+	 computation function processes the whole buffer so that with the
+	 next round of the loop another block can be read.  */
+      size_t n;
+      sum = 0;
+
+      /* Read block.  Take care for partial reads.  */
+      while (1)
+	{
+	  n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+	  sum += n;
+
+	  if (sum == BLOCKSIZE)
+	    break;
+
+	  if (n == 0)
+	    {
+	      /* Check for the error flag IFF N == 0, so that we don't
+		 exit the loop after a partial read due to e.g., EAGAIN
+		 or EWOULDBLOCK.  */
+	      if (ferror (stream))
+		return 1;
+	      goto process_partial_block;
+	    }
+
+	  /* We've read at least one byte, so ignore errors.  But always
+	     check for EOF, since feof may be true even though N > 0.
+	     Otherwise, we could end up calling fread after EOF.  */
+	  if (feof (stream))
+	    goto process_partial_block;
+	}
+
+      /* Process buffer with BLOCKSIZE bytes.  Note that
+			BLOCKSIZE % 64 == 0
+       */
+      md5_process_block (buffer, BLOCKSIZE, &ctx);
+    }
+
+ process_partial_block:;
+
+  /* Process any remaining bytes.  */
+  if (sum > 0)
+    md5_process_bytes (buffer, sum, &ctx);
+
+  /* Construct result in desired memory.  */
+  md5_finish_ctx (&ctx, resblock);
+  return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+void *
+md5_buffer (const char *buffer, size_t len, void *resblock)
+{
+  struct md5_ctx ctx;
+
+  /* Initialize the computation context.  */
+  md5_init_ctx (&ctx);
+
+  /* Process whole buffer but last len % 64 bytes.  */
+  md5_process_bytes (buffer, len, &ctx);
+
+  /* Put result in desired memory area.  */
+  return md5_finish_ctx (&ctx, resblock);
+}
+
+
+void
+md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+  /* When we already have some bits in our internal buffer concatenate
+     both inputs first.  */
+  if (ctx->buflen != 0)
+    {
+      size_t left_over = ctx->buflen;
+      size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+      memcpy (&ctx->buffer[left_over], buffer, add);
+      ctx->buflen += add;
+
+      if (ctx->buflen > 64)
+	{
+	  md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
+
+	  ctx->buflen &= 63;
+	  /* The regions in the following copy operation cannot overlap.  */
+	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+		  ctx->buflen);
+	}
+
+      buffer = (const char *) buffer + add;
+      len -= add;
+    }
+
+  /* Process available complete blocks.  */
+  if (len >= 64)
+    {
+#if !_STRING_ARCH_unaligned
+# define alignof(type) offsetof (struct { char c; type x; }, x)
+# define UNALIGNED_P(p) (((size_t) p) % alignof (md5_uint32) != 0)
+      if (UNALIGNED_P (buffer))
+	while (len > 64)
+	  {
+	    md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
+	    buffer = (const char *) buffer + 64;
+	    len -= 64;
+	  }
+      else
+#endif
+	{
+	  md5_process_block (buffer, len & ~63, ctx);
+	  buffer = (const char *) buffer + (len & ~63);
+	  len &= 63;
+	}
+    }
+
+  /* Move remaining bytes in internal buffer.  */
+  if (len > 0)
+    {
+      size_t left_over = ctx->buflen;
+
+      memcpy (&ctx->buffer[left_over], buffer, len);
+      left_over += len;
+      if (left_over >= 64)
+	{
+	  md5_process_block (ctx->buffer, 64, ctx);
+	  left_over -= 64;
+	  memcpy (ctx->buffer, &ctx->buffer[64], left_over);
+	}
+      ctx->buflen = left_over;
+    }
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+   and defined in the RFC 1321.  The first function is a little bit optimized
+   (as found in Colin Plumbs public domain implementation).  */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+   It is assumed that LEN % 64 == 0.  */
+
+void
+md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+  md5_uint32 correct_words[16];
+  const md5_uint32 *words = buffer;
+  size_t nwords = len / sizeof (md5_uint32);
+  const md5_uint32 *endp = words + nwords;
+  md5_uint32 A = ctx->A;
+  md5_uint32 B = ctx->B;
+  md5_uint32 C = ctx->C;
+  md5_uint32 D = ctx->D;
+
+  /* First increment the byte count.  RFC 1321 specifies the possible
+     length of the file up to 2^64 bits.  Here we only compute the
+     number of bytes.  Do a double word increment.  */
+  ctx->total[0] += len;
+  if (ctx->total[0] < len)
+    ++ctx->total[1];
+
+  /* Process all bytes in the buffer with 64 bytes in each round of
+     the loop.  */
+  while (words < endp)
+    {
+      md5_uint32 *cwp = correct_words;
+      md5_uint32 A_save = A;
+      md5_uint32 B_save = B;
+      md5_uint32 C_save = C;
+      md5_uint32 D_save = D;
+
+      /* First round: using the given function, the context and a constant
+	 the next context is computed.  Because the algorithms processing
+	 unit is a 32-bit word and it is determined to work on words in
+	 little endian byte order we perhaps have to change the byte order
+	 before the computation.  To reduce the work for the next steps
+	 we store the swapped words in the array CORRECT_WORDS.  */
+
+#define OP(a, b, c, d, s, T)						\
+      do								\
+        {								\
+	  a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;		\
+	  ++words;							\
+	  CYCLIC (a, s);						\
+	  a += b;							\
+        }								\
+      while (0)
+
+      /* It is unfortunate that C does not provide an operator for
+	 cyclic rotation.  Hope the C compiler is smart enough.  */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+      /* Before we start, one word to the strange constants.
+	 They are defined in RFC 1321 as
+
+	 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+
+	 Here is an equivalent invocation using Perl:
+
+	 perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}'
+       */
+
+      /* Round 1.  */
+      OP (A, B, C, D,  7, 0xd76aa478);
+      OP (D, A, B, C, 12, 0xe8c7b756);
+      OP (C, D, A, B, 17, 0x242070db);
+      OP (B, C, D, A, 22, 0xc1bdceee);
+      OP (A, B, C, D,  7, 0xf57c0faf);
+      OP (D, A, B, C, 12, 0x4787c62a);
+      OP (C, D, A, B, 17, 0xa8304613);
+      OP (B, C, D, A, 22, 0xfd469501);
+      OP (A, B, C, D,  7, 0x698098d8);
+      OP (D, A, B, C, 12, 0x8b44f7af);
+      OP (C, D, A, B, 17, 0xffff5bb1);
+      OP (B, C, D, A, 22, 0x895cd7be);
+      OP (A, B, C, D,  7, 0x6b901122);
+      OP (D, A, B, C, 12, 0xfd987193);
+      OP (C, D, A, B, 17, 0xa679438e);
+      OP (B, C, D, A, 22, 0x49b40821);
+
+      /* For the second to fourth round we have the possibly swapped words
+	 in CORRECT_WORDS.  Redefine the macro to take an additional first
+	 argument specifying the function to use.  */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T)					\
+      do								\
+	{								\
+	  a += f (b, c, d) + correct_words[k] + T;			\
+	  CYCLIC (a, s);						\
+	  a += b;							\
+	}								\
+      while (0)
+
+      /* Round 2.  */
+      OP (FG, A, B, C, D,  1,  5, 0xf61e2562);
+      OP (FG, D, A, B, C,  6,  9, 0xc040b340);
+      OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+      OP (FG, B, C, D, A,  0, 20, 0xe9b6c7aa);
+      OP (FG, A, B, C, D,  5,  5, 0xd62f105d);
+      OP (FG, D, A, B, C, 10,  9, 0x02441453);
+      OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+      OP (FG, B, C, D, A,  4, 20, 0xe7d3fbc8);
+      OP (FG, A, B, C, D,  9,  5, 0x21e1cde6);
+      OP (FG, D, A, B, C, 14,  9, 0xc33707d6);
+      OP (FG, C, D, A, B,  3, 14, 0xf4d50d87);
+      OP (FG, B, C, D, A,  8, 20, 0x455a14ed);
+      OP (FG, A, B, C, D, 13,  5, 0xa9e3e905);
+      OP (FG, D, A, B, C,  2,  9, 0xfcefa3f8);
+      OP (FG, C, D, A, B,  7, 14, 0x676f02d9);
+      OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+      /* Round 3.  */
+      OP (FH, A, B, C, D,  5,  4, 0xfffa3942);
+      OP (FH, D, A, B, C,  8, 11, 0x8771f681);
+      OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+      OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+      OP (FH, A, B, C, D,  1,  4, 0xa4beea44);
+      OP (FH, D, A, B, C,  4, 11, 0x4bdecfa9);
+      OP (FH, C, D, A, B,  7, 16, 0xf6bb4b60);
+      OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+      OP (FH, A, B, C, D, 13,  4, 0x289b7ec6);
+      OP (FH, D, A, B, C,  0, 11, 0xeaa127fa);
+      OP (FH, C, D, A, B,  3, 16, 0xd4ef3085);
+      OP (FH, B, C, D, A,  6, 23, 0x04881d05);
+      OP (FH, A, B, C, D,  9,  4, 0xd9d4d039);
+      OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+      OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+      OP (FH, B, C, D, A,  2, 23, 0xc4ac5665);
+
+      /* Round 4.  */
+      OP (FI, A, B, C, D,  0,  6, 0xf4292244);
+      OP (FI, D, A, B, C,  7, 10, 0x432aff97);
+      OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+      OP (FI, B, C, D, A,  5, 21, 0xfc93a039);
+      OP (FI, A, B, C, D, 12,  6, 0x655b59c3);
+      OP (FI, D, A, B, C,  3, 10, 0x8f0ccc92);
+      OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+      OP (FI, B, C, D, A,  1, 21, 0x85845dd1);
+      OP (FI, A, B, C, D,  8,  6, 0x6fa87e4f);
+      OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+      OP (FI, C, D, A, B,  6, 15, 0xa3014314);
+      OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+      OP (FI, A, B, C, D,  4,  6, 0xf7537e82);
+      OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+      OP (FI, C, D, A, B,  2, 15, 0x2ad7d2bb);
+      OP (FI, B, C, D, A,  9, 21, 0xeb86d391);
+
+      /* Add the starting values of the context.  */
+      A += A_save;
+      B += B_save;
+      C += C_save;
+      D += D_save;
+    }
+
+  /* Put checksum in context given as argument.  */
+  ctx->A = A;
+  ctx->B = B;
+  ctx->C = C;
+  ctx->D = D;
+}

Added: trunk/externals/loaders/urloader/md5.h
===================================================================
--- trunk/externals/loaders/urloader/md5.h	                        (rev 0)
+++ trunk/externals/loaders/urloader/md5.h	2008-09-03 09:34:50 UTC (rev 10275)
@@ -0,0 +1,136 @@
+/* Declaration of functions and data types used for MD5 sum computing
+   library functions.
+   Copyright (C) 1995-1997,1999-2005 Free Software Foundation, Inc.
+
+   NOTE: The canonical source of this file is maintained with the GNU C
+   Library.  Bugs can be reported to bug-glibc at prep.ai.mit.edu.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#if HAVE_STDINT_H || _LIBC
+# include <stdint.h>
+#endif
+
+#ifndef __GNUC_PREREQ
+# if defined __GNUC__ && defined __GNUC_MINOR__
+#  define __GNUC_PREREQ(maj, min) \
+	((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+# else
+#  define __GNUC_PREREQ(maj, min) 0
+# endif
+#endif
+
+#ifndef __THROW
+# if defined __cplusplus && __GNUC_PREREQ (2,8)
+#  define __THROW	throw ()
+# else
+#  define __THROW
+# endif
+#endif
+
+#ifndef __attribute__
+# if ! __GNUC_PREREQ (2,8) || __STRICT_ANSI__
+#  define __attribute__(x)
+# endif
+#endif
+
+#ifndef _LIBC
+# define __md5_buffer md5_buffer
+# define __md5_finish_ctx md5_finish_ctx
+# define __md5_init_ctx md5_init_ctx
+# define __md5_process_block md5_process_block
+# define __md5_process_bytes md5_process_bytes
+# define __md5_read_ctx md5_read_ctx
+# define __md5_stream md5_stream
+#endif
+
+typedef uint32_t md5_uint32;
+
+/* Structure to save state of computation between the single steps.  */
+struct md5_ctx
+{
+  md5_uint32 A;
+  md5_uint32 B;
+  md5_uint32 C;
+  md5_uint32 D;
+
+  md5_uint32 total[2];
+  md5_uint32 buflen;
+  char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
+extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW;
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is necessary that LEN is a multiple of 64!!! */
+extern void __md5_process_block (const void *buffer, size_t len,
+				 struct md5_ctx *ctx) __THROW;
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is NOT required that LEN is a multiple of 64.  */
+extern void __md5_process_bytes (const void *buffer, size_t len,
+				 struct md5_ctx *ctx) __THROW;
+
+/* Process the remaining bytes in the buffer and put result from CTX
+   in first 16 bytes following RESBUF.  The result is always in little
+   endian byte order, so that a byte-wise output yields to the wanted
+   ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF be correctly
+   aligned for a 32 bits value.  */
+extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW;
+
+
+/* Put result from CTX in first 16 bytes following RESBUF.  The result is
+   always in little endian byte order, so that a byte-wise output yields
+   to the wanted ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW;
+
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+extern int __md5_stream (FILE *stream, void *resblock) __THROW;
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+extern void *__md5_buffer (const char *buffer, size_t len,
+			   void *resblock) __THROW;
+
+#endif /* md5.h */

Added: trunk/externals/loaders/urloader/pd.index
===================================================================
--- trunk/externals/loaders/urloader/pd.index	                        (rev 0)
+++ trunk/externals/loaders/urloader/pd.index	2008-09-03 09:34:50 UTC (rev 10275)
@@ -0,0 +1,2 @@
+4a3a52f1d881ce91a6e8ba09671a6852  another.pd
+b9faccc63257b5ced1f91f21ed8adfa3  unknown.pd

Added: trunk/externals/loaders/urloader/test.pd
===================================================================
--- trunk/externals/loaders/urloader/test.pd	                        (rev 0)
+++ trunk/externals/loaders/urloader/test.pd	2008-09-03 09:34:50 UTC (rev 10275)
@@ -0,0 +1,13 @@
+#N canvas 592 253 450 300 10;
+#X text 28 24 Test for URL loader;
+#X obj 28 56 baseurl http://localhost/pd;
+#X obj 32 140 unknown;
+#X floatatom 32 111 5 0 0 0 - - -;
+#X floatatom 32 171 5 0 0 0 - - -;
+#X obj 135 139 another;
+#X floatatom 135 112 5 0 0 0 - - -;
+#X floatatom 135 171 5 0 0 0 - - -;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;

Added: trunk/externals/loaders/urloader/unknown.pd
===================================================================
--- trunk/externals/loaders/urloader/unknown.pd	                        (rev 0)
+++ trunk/externals/loaders/urloader/unknown.pd	2008-09-03 09:34:50 UTC (rev 10275)
@@ -0,0 +1,5 @@
+#N canvas 1 44 450 300 10;
+#X text 46 35 This is a PD patch.;
+#X obj 210 36 inlet;
+#X obj 210 89 outlet;
+#X connect 1 0 2 0;

Added: trunk/externals/loaders/urloader/urlloader.c
===================================================================
--- trunk/externals/loaders/urloader/urlloader.c	                        (rev 0)
+++ trunk/externals/loaders/urloader/urlloader.c	2008-09-03 09:34:50 UTC (rev 10275)
@@ -0,0 +1,509 @@
+/* Copyright (c) 2008 Steve Sinclair <radarsat1 at gmail.com>
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," that comes with Pd.  
+ */
+
+/*
+ * this code adds an external "loader" to Miller S. Puckette's "pure data",
+ * which allows the loading of libraries/externals from internet URLs
+ *
+ * the infrastructure of this file is based on hcsteiner's "libdir" loader
+ */
+
+
+#ifdef __WIN32__
+# define MSW
+#endif
+
+#include "m_pd.h"
+
+#if (PD_MINOR_VERSION >= 40)
+
+#include "s_stuff.h"
+#include "g_canvas.h"
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "baseurl.h"
+#include <curl/curl.h>
+
+#include <stdint.h>
+#include "md5.h"
+#include "md5.c"
+
+typedef void (*t_urlloader_setup)(void);
+
+/* definitions taken from s_loader.c  */
+typedef int (*loader_t)(t_canvas *canvas, char *classname);
+void sys_register_loader(loader_t loader);
+void class_set_extern_dir(t_symbol *s);
+
+/* taken from m_class.c */
+int pd_setloadingabstraction(t_symbol *sym);
+void canvas_popabstraction(t_canvas *x);
+
+/* ==================================================== */
+
+#define CACHE_TIMEOUT_SECONDS 100
+
+typedef struct _urlloader
+{
+  t_object x_obj;
+} t_urlloader;
+static t_class *urlloader_class;
+
+static char *version = "0.0.1";
+
+typedef struct _list
+{
+    struct _list *next;
+} t_list;
+
+typedef struct _url_object
+{
+    t_list list;
+    t_symbol *name;
+    char md5[16];
+} t_url_object;
+
+typedef struct _url
+{
+    t_list list;
+    t_symbol *url;
+    t_url_object *objects;
+} t_url;
+static t_url *baseurl_list = NULL;
+
+char cachedir[MAXPDSTRING]="";
+#define FILEPERM (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
+#define DIRPERM (FILEPERM|S_IXUSR|S_IXGRP|S_IXOTH)
+char *get_cache_dir(void)
+{
+    if (cachedir[0]==0) {
+        strcpy(cachedir, getenv("HOME"));
+        strcat(cachedir, "/.pd/cache");
+    }
+
+    return cachedir;
+}
+
+FILE* create_and_open(const char *filename, const char *mode)
+{
+    char str[MAXPDSTRING], *ss=str;
+    const char *sf=filename;
+    struct stat st;
+    while (*sf) {
+        do {
+            *ss = *sf;
+            ss++;
+            sf++;
+        } while (*sf && *sf != '/');
+        *ss = 0;
+
+        if (stat(str, &st)<0) {
+            if (*sf) {
+                if (mkdir(str, DIRPERM)<0) {
+                    post("[urlloader] Error creating %s", str);
+                    return 0;
+                }
+            }
+            else
+                return fopen(str, mode);
+        }
+        else if (!*sf)
+            return fopen(str, mode);
+    }
+
+    return 0;
+}
+
+/** Return the full path to a filename in the cache */
+void cache_path(char path[MAXPDSTRING], t_url *u, const char *filename)
+{
+    char *s;
+    strncpy(path, get_cache_dir(), MAXPDSTRING);
+#ifdef WIN32
+    strncat(path, "\\", MAXPDSTRING);
+#else
+    strncat(path, "/", MAXPDSTRING);
+#endif
+    s = path + strlen(path);
+    strncat(path, u->url->s_name, MAXPDSTRING);
+    while (*s) {
+        if (*s == '/') *s = '_';
+        s++;
+    }
+#ifdef WIN32
+    strncat(path, "\\", MAXPDSTRING);
+#else
+    strncat(path, "/", MAXPDSTRING);
+#endif
+    strncat(path, filename, MAXPDSTRING);
+}
+
+/** Open a file from the cache or download it first if needed. */
+FILE* download_and_open_from_cache(t_url *u, const char *filename, const char *mode)
+{
+    char str_url[MAXPDSTRING];
+    char cache_name[MAXPDSTRING];
+    struct stat st;
+
+    cache_path(cache_name, u, filename);
+
+    if (stat(cache_name, &st)<0
+        || ((time(NULL)-st.st_mtime) > CACHE_TIMEOUT_SECONDS))
+    { 
+        CURL *c = curl_easy_init();
+        FILE *f=0;
+        if (!c) {
+            post("[urlloader] Error initializing curl.");
+            return 0;
+        }
+
+        f = create_and_open(cache_name, "wb");
+        if (!f) {
+            post("[urlloader] Error opening %s for write.", cache_name);
+            return 0;
+        }
+
+        /* Download the index file */
+        snprintf(str_url, MAXPDSTRING, "%s/%s", u->url->s_name, filename);
+        curl_easy_setopt(c, CURLOPT_URL, str_url);
+        curl_easy_setopt(c, CURLOPT_WRITEDATA, f);
+        if (curl_easy_perform(c)) {
+            post("[urlloader] Error downloading %s", str_url);
+        }
+        curl_easy_cleanup(c);
+
+        post("[urlloader] Downloaded %s to %s", str_url, cache_name);
+
+        fclose(f);
+    }
+
+    if (mode)
+        return fopen(cache_name, mode);
+    else
+        // indicate success without opening the file
+        return (FILE*)1;
+}
+
+/** Append an item to a struct beginning with a t_list.
+ *  If allowdup is false (0), second item must be a t_symbol*.
+ *  If duplicate, returns the item without modifying it. */
+void *list_append(void *list, void *item, int size, int allowdup)
+{
+    t_list** l = list;
+    t_symbol *s1, *s2;
+    if (!*l) {
+        *l = getbytes(size);
+    }
+    else {
+        while (*l) {
+            if (!allowdup) {
+                s1 = *(t_symbol**)(((char*)*l)+sizeof(t_list));
+                s2 = *(t_symbol**)(((char*)item)+sizeof(t_list));
+                if (s1==s2 || strcmp(s1->s_name, s2->s_name)==0)
+                    return *l;
+            }
+            if (!(*l)->next)
+                break;
+            l = &(*l)->next;
+        }
+        (*l)->next = getbytes(size);
+        l = &(*l)->next;
+    }
+
+    if (*l) {
+        memcpy(*l, item, size);
+        (*l)->next = 0;
+    }
+
+    return *l;
+}
+
+t_url *url_add(t_atom *url)
+{
+    t_url u;
+    u.url = url->a_w.w_symbol;
+    u.objects = 0;
+    return list_append(&baseurl_list, &u, sizeof(t_url), 0);
+}
+
+void url_parse_index_line(t_url *u, char* line)
+{
+    char *s = line, *name, hex[3];
+    int i=0;
+    t_url_object o;
+    while ((*s==' ' || *s=='\t') && *s) {s++;}   /* skip whitespace */
+    if (!*s) return;
+    while (!(*s==' ' || *s=='\t') && *s) {       /* remember MD5 sum */
+        hex[0] = *s; s++;
+        hex[1] = *s; s++;
+        hex[2] = 0;
+        o.md5[i++] = strtol(hex, 0, 16);
+    }
+    if (!*s) return;
+    while ((*s==' ' || *s=='\t') && *s) {s++;}   /* skip whitespace */
+    if (!*s) return;
+    name = s;
+    while (!(*s==' ' || *s=='\t') && *s) {s++;}  /* skip md5sum for now */
+    *s = 0;
+
+    o.name = gensym(name);
+    list_append(&u->objects, &o, sizeof(t_url_object), 0);
+}
+
+/** Download index for a given URL. */
+int url_update_index(t_url *u)
+{
+    char buffer[MAXPDSTRING], *line=buffer;
+    int bufpos=0;
+
+    // open and read the downloaded or cached file.
+    FILE *f = download_and_open_from_cache(u, "pd.index", "rb");
+    if (!f) {
+        post("[urlloader] Error opening index for %s", u->url->s_name);
+        return -1;
+    }
+
+    post("[urlloader] Index for %s opened.", u->url->s_name);
+    while (!feof(f)) {
+        int sz = fread(buffer+bufpos, 1, 256, f);
+        int end = bufpos + sz;
+        while (bufpos < end) {
+            while (buffer[bufpos]!='\n' && buffer[bufpos]!='\r'
+                   && bufpos < end)
+                ++bufpos;
+            if (bufpos < end || feof(f)) {
+                buffer[bufpos] = 0;
+                url_parse_index_line(u, line);
+                ++bufpos;
+                line = buffer+bufpos;
+            }
+        }
+    }
+
+    fclose(f);
+    return 0;
+}
+
+/** Download any indexes that are missing. */
+static int cache_update_index(void)
+{
+    t_url *u;
+    int rc;
+
+    u = baseurl_list;
+    while (u) {
+        rc = 0;
+        if (u->objects == NULL)
+            rc = url_update_index(u);
+        if (rc) {
+            post("[urlloader] Error updating index for %s", u->url->s_name);
+            return rc;
+        }
+        u = (t_url*)u->list.next;
+    }
+
+    return 0;
+}
+
+/** Search all objects in the canvas and its owner for baseurl objects.
+ *  Add the found object URLs to the global list of t_urls.
+ */
+static void canvas_find_baseurls(t_canvas *canvas)
+{
+    t_gobj *o = canvas->gl_list;
+    while (o) {
+        if (strcmp(class_getname(o->g_pd),"baseurl")==0)
+            url_add(&((t_baseurl*)o)->url);
+        o = o->g_next;
+    }
+    if (canvas->gl_owner)
+        canvas_find_baseurls(canvas->gl_owner);
+}
+
+/** Find a given class name in the global t_url list. */
+static t_url* url_find_class(char *classname, t_url_object **object)
+{
+    t_url *u = baseurl_list;
+    t_url_object *o;
+    while (u) {
+        o = u->objects;
+        while (o) {
+            char *ext = strstr(o->name->s_name, ".pd");
+            if (!ext) continue;
+            if (strncmp(o->name->s_name, classname,
+                        ext - o->name->s_name)==0)
+                break;
+            o = (t_url_object*)o->list.next;
+        }
+        if (o) break;
+        u = (t_url*)u->list.next;
+    }
+    if (object) *object = o;
+    return u;
+}
+
+/** Load an abstraction specified by an absolute path name. */
+int canvas_load_from_absolute_path(t_canvas *canvas, t_symbol *classname,
+                                   char *path, char *ext)
+{
+    char dirbuf[MAXPDSTRING], *nameptr;
+    t_pd *current = s__X.s_thing;
+    int fd=-1;
+
+    fd = canvas_open(canvas, path, ext,
+                     dirbuf, &nameptr, MAXPDSTRING, 0);
+
+    if (fd < 0)
+        return 0;
+    
+    close(fd);
+    if (!pd_setloadingabstraction(classname)) {
+        canvas_setargs(0, 0);  /* TODO argc, argv */
+        binbuf_evalfile(gensym(nameptr), gensym(dirbuf));
+        if (s__X.s_thing != current)
+            canvas_popabstraction((t_canvas *)(s__X.s_thing));
+        canvas_setargs(0, 0);
+    }
+    else {
+        error("%s: can't load abstraction within itself\n", classname);
+        return 0;
+    }
+
+    return 1;
+}
+
+/**
+ * the loader
+ *
+ * @param canvas the context of the object to be created
+ * @param classname the name of the object (external, library) to be created
+ * @return 1 on success, 0 on failure
+ */
+static int urlloader_loader(t_canvas *canvas, char *classname)
+{
+  int result=0;
+  t_url *u;
+  t_url_object *o;
+  char class_filename[MAXPDSTRING];
+  char class_cachepath[MAXPDSTRING];
+  char tmpstr[MAXPDSTRING];
+  FILE *f;
+
+  static int already_loading=0;
+  if(already_loading)return 0;
+  already_loading=1;
+
+  /* loader */
+  post("[urlloader] Asked to load %s for canvas %s", classname, canvas->gl_name->s_name);
+  canvas_find_baseurls(canvas);
+  cache_update_index();
+
+  post("[urlloader] Known URLs:");
+  u = baseurl_list;
+  while (u) {
+      post("[urlloader] %s", u->url->s_name);
+      o = u->objects;
+      while (o) {
+          post("[urlloader] - %s", o->name->s_name);
+          o = (t_url_object*)o->list.next;
+      }
+      u = (t_url*)u->list.next;
+  }
+
+  u = url_find_class(classname, &o);
+  if (!(u && o)) {
+      already_loading=0;
+      return result;
+  }
+
+  post("[urlloader] Found: %s.pd at %s", classname, u->url->s_name);
+
+  snprintf(class_filename, MAXPDSTRING, "%s.pd", classname);
+  if (f=download_and_open_from_cache(u, class_filename, "rb"))
+  {
+      char resblock[16];
+      int okay=1, i;
+      if (md5_stream(f, resblock)) {
+          post("[urlloader] Error generating MD5 sum for %s", class_filename);
+          result = 0;
+          already_loading = 0;
+          fclose(f);
+          return result;
+      }
+      fclose(f);
+
+      for (i=0; i<16; i++)
+          okay &= (resblock[i]==o->md5[i]);
+      if (!okay) {
+          post("[urlloader] MD5 error for %s", class_filename);
+          result = 0;
+          already_loading = 0;
+          return result;
+      }
+
+      // download GPG signature
+      snprintf(tmpstr, MAXPDSTRING, "%s.asc", class_filename);
+      if (!download_and_open_from_cache(u, tmpstr, 0)) {
+          post("[urlloader] Error downloading GPG signature for %s",
+               class_filename);
+          result = 0;
+          already_loading = 0;
+          return result;
+      }
+
+      // check GPG signature
+      cache_path(class_cachepath, u, classname);
+      snprintf(tmpstr, MAXPDSTRING, "gpg --verify %s.pd.asc %s.pd",
+               class_cachepath, class_cachepath);
+      if (system(tmpstr)) {
+          post("[urlloader] Error verifying GPG signature for %s",
+               class_filename);
+          result = 0;
+          already_loading = 0;
+          return result;
+      }
+           
+
+      // load pd patch
+      canvas_load_from_absolute_path(canvas, gensym(classname),
+                                     class_cachepath, ".pd");
+      result = 1;
+  }
+
+  already_loading=0;
+  return result;
+}
+
+#endif /* PD_MINOR_VERSION>=40 */
+
+static void*urlloader_new(t_symbol *s, int argc, t_atom *argv)
+{
+  t_urlloader*x = (t_urlloader*)pd_new(urlloader_class);
+  return (x);
+}
+
+void urlloader_setup(void)
+{
+  /* relies on t.grill's loader functionality, fully added in 0.40 */
+  post("url loader %s",version);  
+  post("\twritten by Steve Sinclair");
+  post("\tcompiled on "__DATE__" at "__TIME__ " ");
+  post("\tcompiled against Pd version %d.%d.%d.%s", PD_MAJOR_VERSION, PD_MINOR_VERSION, PD_BUGFIX_VERSION, PD_TEST_VERSION);
+
+  curl_global_init(CURL_GLOBAL_ALL);
+
+#if (PD_MINOR_VERSION >= 40)
+  sys_register_loader(urlloader_loader);
+#else
+  error("to function, this needs to be compiled against Pd 0.40 or higher,\n");
+  error("\tor a version that has sys_register_loader()");
+#endif
+
+  urlloader_class = class_new(gensym("urlloader"), (t_newmethod)urlloader_new, 0, sizeof(t_urlloader), CLASS_NOINLET, A_GIMME, 0);
+}


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Pd-cvs mailing list