diff src/md5.c @ 249:83b3d10dcba9 r20-5b23

Import from CVS: tag r20-5b23
author cvs
date Mon, 13 Aug 2007 10:19:09 +0200
parents 8eaf7971accc
children 11cf20601dec
line wrap: on
line diff
--- a/src/md5.c	Mon Aug 13 10:18:22 2007 +0200
+++ b/src/md5.c	Mon Aug 13 10:19:09 2007 +0200
@@ -24,13 +24,17 @@
  */
 
 /* Synched up with: Not in FSF. */
-/* This file has been Mule-ized.  See comment at Fmd5(), though. */
+/* This file has been Mule-ized. */
 
 #include <config.h>
 #include "lisp.h"
 
 #include "buffer.h"
 #include "insdel.h"
+#include "lstream.h"
+#ifdef MULE
+#include "mule-coding.h"
+#endif
 
 typedef unsigned char *POINTER;/* POINTER defines a generic pointer type */
 typedef unsigned short int UINT2;/* UINT2 defines a two byte word */
@@ -355,24 +359,19 @@
 /* XEmacs interface code. */
 Lisp_Object Qmd5;
 
-/* #### There could be potential problems here with Mule.  I don't
-   know enough about the uses of MD5 to be able to tell for sure
-   whether this is a problem.  The basic potential problem is that
-   the hash value will be computed based on the internal representation
-   of the buffer; this would likely cause problems if the string
-   contains extended characters, because the extended characters
-   will get sent over the wire in an external form that is different
-   from their internal representation, and thus their MD5 hash would
-   be different. */
-
-DEFUN ("md5", Fmd5, 1, 3, 0, /*
+DEFUN ("md5", Fmd5, 1, 5, 0, /*
 Return the MD5 (a secure message digest algorithm) of an object.
 OBJECT is either a string or a buffer.
 Optional arguments START and END denote buffer positions for computing the
-hash of a portion of OBJECT.
+hash of a portion of OBJECT.  The optional CODING argument specifies the coding
+system the text is to be represented in while computing the digest.  This only
+has meaning with MULE, and defaults to the current format of the data.
+If ERROR-ME-NOT is nil, report an error if the coding system can't be
+determined.  Else assume binary coding if all else fails.
 */
-       (object, start, end))
+       (object, start, end, coding, error_me_not))
 {
+  /* This function can GC */
   MD_CTX context;
   unsigned char digest[16];
   unsigned char thehash[32];
@@ -384,31 +383,126 @@
     {
       MDUpdate (&context, (CONST unsigned char *) "", 0);
     }
-  else if (BUFFERP (object))
-    {
-      struct buffer *b = decode_buffer (object, 1);
-      Bufpos begv, endv;
-      Lisp_Object string;
-
-      /* Figure out where we need to get info from */
-      get_buffer_range_char (b, start, end, &begv, &endv, GB_ALLOW_NIL);
-
-      /* Get the string data from the buffer */
-      string = make_string_from_buffer (b, begv, endv - begv);
-
-    /* Compute the digest */
-      MDUpdate (&context, (unsigned char *) XSTRING_DATA (string),
-		XSTRING_LENGTH (string));
-    }
   else
     {
-      Bytecount len, bstart, bend;
-      CHECK_STRING (object);
-      get_string_range_byte (object, start, end, &bstart, &bend,
-			     GB_HISTORICAL_STRING_BEHAVIOR);
-      len = bend - bstart;
-      MDUpdate (&context, ((unsigned char *) XSTRING_DATA (object)
-			   + bstart), len);
+      Lisp_Object instream, outstream;
+      Lstream *istr, *ostr;
+      static Extbyte_dynarr *conversion_out_dynarr;
+      char tempbuf[1024]; /* some random amount */
+      struct gcpro gcpro1, gcpro2;
+#ifdef MULE
+      Lisp_Object conv_out_stream, coding_system;
+      Lstream *costr;
+      struct gcpro gcpro3;
+#endif
+
+      if (!conversion_out_dynarr)
+	conversion_out_dynarr = Dynarr_new (Extbyte);
+      else
+	Dynarr_reset (conversion_out_dynarr);
+
+      /* set up the in stream */
+      if (BUFFERP (object))
+	{
+	  struct buffer *b = decode_buffer (object, 1);
+	  Bufpos begv, endv;
+	  /* Figure out where we need to get info from */
+	  get_buffer_range_char (b, start, end, &begv, &endv, GB_ALLOW_NIL);
+
+	  instream = make_lisp_buffer_input_stream (b, begv, endv, 0);
+	}
+      else
+	{
+	  Bytecount bstart, bend;
+	  CHECK_STRING (object);
+	  get_string_range_byte (object, start, end, &bstart, &bend,
+				 GB_HISTORICAL_STRING_BEHAVIOR);
+	  instream = make_lisp_string_input_stream (object, bstart, bend);
+	}
+      istr = XLSTREAM (instream);
+
+#ifdef MULE
+      /* Find out what format the buffer will be saved in, so we can make
+	 the digest based on what it will look like on disk */
+      if (NILP(coding))
+	{
+	  if (BUFFERP(object)) 
+	    {
+	      /* Use the file coding for this buffer by default */
+	      coding_system = XBUFFER(object)->buffer_file_coding_system;
+	    }
+	  else
+	    {
+	      /* attempt to autodetect the coding of the string.  Note: this VERY hit-and-miss */
+	      enum eol_type eol = EOL_AUTODETECT;
+	      coding_system = Fget_coding_system(Qundecided);
+	      determine_real_coding_system(istr, &coding_system, &eol);
+	    }
+	  if (NILP(coding_system)) 
+	    coding_system = Fget_coding_system(Qbinary);
+	  else
+	    {
+	      coding_system = Ffind_coding_system (coding_system);
+	      if (NILP(coding_system))
+		coding_system = Fget_coding_system(Qbinary);
+	    }
+	}
+      else
+	{
+	  coding_system = Ffind_coding_system (coding);
+	  if (NILP(coding_system))
+	    if (NILP(error_me_not))
+	      signal_simple_error("No such coding system", coding);
+	    else
+	      coding_system = Fget_coding_system(Qbinary); /* default to binary */
+	}
+#endif
+      
+      /* setup the out stream */
+      outstream = make_dynarr_output_stream((unsigned_char_dynarr *)conversion_out_dynarr);
+      ostr = XLSTREAM (outstream);
+#ifdef MULE
+      /* setup the conversion stream */
+      conv_out_stream = make_encoding_output_stream (ostr, coding_system);
+      costr = XLSTREAM (conv_out_stream);
+      GCPRO3 (instream, outstream, conv_out_stream);
+#else
+      GCPRO2 (instream, outstream);
+#endif
+
+      /* Get the data while doing the conversion */
+      while (1) {
+	int size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf));
+	if (!size_in_bytes)
+	  break;
+	/* It does seem the flushes are necessary... */
+#ifdef MULE
+	Lstream_write (costr, tempbuf, size_in_bytes);
+	Lstream_flush (costr);
+#else
+	Lstream_write (ostr, tempbuf, size_in_bytes);
+#endif
+	Lstream_flush (ostr);
+
+	/* Update the digest */
+	
+	MDUpdate (&context, (unsigned char *)Dynarr_atp(conversion_out_dynarr, 0), 
+		  Dynarr_length(conversion_out_dynarr));
+	/* reset the dynarr */
+	Lstream_rewind(ostr);
+      }
+      Lstream_close (istr);
+#ifdef MULE
+      Lstream_close (costr);
+#endif
+      Lstream_close (ostr);
+
+      UNGCPRO;
+      Lstream_delete (istr);
+      Lstream_delete (ostr);
+#ifdef MULE
+      Lstream_delete (costr);
+#endif
     }
 
   MDFinal (digest, &context);