Tcl Source Code

Artifact [f428d62d1d]
Login

Artifact f428d62d1d5e6eeb5ae1d5e81a91fe2b86878da3:

Attachment "binary.patch" to ticket [429916ffff] added by hobbs 2001-06-04 08:13:47.
Index: generic/tclBinary.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBinary.c,v
retrieving revision 1.7
diff -b -c -r1.7 tclBinary.c
*** generic/tclBinary.c	2001/04/04 16:07:20	1.7
--- generic/tclBinary.c	2001/06/04 01:11:50
***************
*** 37,42 ****
--- 37,43 ----
  static int		GetFormatSpec _ANSI_ARGS_((char **formatPtr,
  			    char *cmdPtr, int *countPtr));
  static Tcl_Obj *	ScanNumber _ANSI_ARGS_((unsigned char *buffer, int type));
+ static long		ScanLong _ANSI_ARGS_((unsigned char *buffer, int type));
  static int		SetByteArrayFromAny _ANSI_ARGS_((Tcl_Interp *interp,
  			    Tcl_Obj *objPtr));
  static void		UpdateStringOfByteArray _ANSI_ARGS_((Tcl_Obj *listPtr));
***************
*** 1199,1205 ****
--- 1200,1250 ----
  			    }
  			    valuePtr = ScanNumber(buffer+offset, cmd);
  			    offset += size;
+ #if 1
+ 			} else if ((count == BINARY_ALL)
+ 				&& (cmd != 'd') && (cmd != 'f')) {
+ 			    Tcl_HashTable charReuseTable;
+ 			    Tcl_HashEntry *hPtr;
+ 			    int isNew;
+ 			    long elementVal;
+ 
+ 			    /*
+ 			     * Handle the special case of splitting on every
+ 			     * long value.
+ 			     *
+ 			     * Uses a hash table to ensure that each value has
+ 			     * only one Tcl_Obj instance (multiply-referenced)
+ 			     * in the final list.  This is a *major* win when
+ 			     * splitting on a long bytearray (especially in the
+ 			     * megabyte range!) - DKF/MS
+ 			     */
+ 
+ 			    Tcl_InitHashTable(&charReuseTable,
+ 				    TCL_ONE_WORD_KEYS);
+ 			    count = (length - offset) / size;
+ 			    valuePtr = Tcl_NewObj();
+ 			    src = buffer+offset;
+ 			    for (i = 0; i < count; i++) {
+ 				elementVal = ScanLong(src, cmd);
+ 				hPtr = Tcl_CreateHashEntry(&charReuseTable,
+ 					(char *) elementVal, &isNew);
+ 				if (isNew) {
+ 				    /* Don't need to fiddle with refcount... */
+ 				    elementPtr = Tcl_NewLongObj(elementVal);
+ 				    Tcl_SetHashValue(hPtr,
+ 					    (ClientData) elementPtr);
  				} else {
+ 				    elementPtr =
+ 					(Tcl_Obj*) Tcl_GetHashValue(hPtr);
+ 				}
+ 				src += size;
+ 				Tcl_ListObjAppendElement(NULL, valuePtr,
+ 					elementPtr);
+ 			    }
+ 			    Tcl_DeleteHashTable(&charReuseTable);
+ 			    offset += count*size;
+ #endif
+ 			} else {
  			    if (count == BINARY_ALL) {
  				count = (length - offset) / size;
  			    }
***************
*** 1548,1551 ****
--- 1593,1686 ----
  	}
      }
      return NULL;
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * ScanNumber --
+  *
+  *	This routine is called by Tcl_BinaryObjCmd to scan a number
+  *	out of a buffer.
+  *
+  * Results:
+  *	Returns a long representing the scanned number.
+  *
+  * Side effects:
+  *	None.
+  *
+  *----------------------------------------------------------------------
+  */
+ 
+ static long
+ ScanLong(buffer, type)
+     unsigned char *buffer;	/* Buffer to scan number from. */
+     int type;			/* Format character from "binary scan" */
+ {
+     long value;
+ 
+     /*
+      * We cannot rely on the compiler to properly sign extend integer values
+      * when we cast from smaller values to larger values because we don't know
+      * the exact size of the integer types.  So, we have to handle sign
+      * extension explicitly by checking the high bit and padding with 1's as
+      * needed.
+      */
+ 
+     switch (type) {
+ 	case 'c': {
+ 	    /*
+ 	     * Characters need special handling.  We want to produce a
+ 	     * signed result, but on some platforms (such as AIX) chars
+ 	     * are unsigned.  To deal with this, check for a value that
+ 	     * should be negative but isn't.
+ 	     */
+ 
+ 	    value = buffer[0];
+ 	    if (value & 0x80) {
+ 		value |= -0x100;
+ 	    }
+ 	    return (long) value;
+ 	}
+ 	case 's': {
+ 	    value = (long) (buffer[0] + (buffer[1] << 8));
+ 	    goto shortValue;
+ 	}
+ 	case 'S': {
+ 	    value = (long) (buffer[1] + (buffer[0] << 8));
+ 	    shortValue:
+ 	    if (value & 0x8000) {
+ 		value |= -0x10000;
+ 	    }
+ 	    return (long) value;
+ 	}
+ 	case 'i': {
+ 	    value = (long) (buffer[0] 
+ 		    + (buffer[1] << 8)
+ 		    + (buffer[2] << 16)
+ 		    + (buffer[3] << 24));
+ 	    goto intValue;
+ 	}
+ 	case 'I': {
+ 	    value = (long) (buffer[3]
+ 		    + (buffer[2] << 8)
+ 		    + (buffer[1] << 16)
+ 		    + (buffer[0] << 24));
+ 	    intValue:
+ 	    /*
+ 	     * Check to see if the value was sign extended properly on
+ 	     * systems where an int is more than 32-bits.
+ 	     */
+ 
+ 	    if ((value & (((unsigned int)1)<<31)) && (value > 0)) {
+ 		value -= (((unsigned int)1)<<31);
+ 		value -= (((unsigned int)1)<<31);
+ 	    }
+ 	    return (long) value;
+ 	}
+ 	default: {
+ 	    panic("binary scan: uncaught bad format string\n");
+ 	    return 0;
+ 	}
+     }
  }