Index: generic/tclBinary.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBinary.c,v
retrieving revision 1.29
diff -c -r1.29 tclBinary.c
*** generic/tclBinary.c	10 Aug 2006 12:15:30 -0000	1.29
--- generic/tclBinary.c	28 Sep 2006 21:26:05 -0000
***************
*** 14,19 ****
--- 14,20 ----
   */
  
  #include "tclInt.h"
+ #include "tclTomMath.h"
  
  #include <math.h>
  
***************
*** 26,31 ****
--- 27,39 ----
  #define BINARY_NOCOUNT -2	/* No count was specified in format. */
  
  /*
+  * The following flags may be ORed together and returned by GetFormatSpec
+  */
+ 
+ #define BINARY_SIGNED 0		/* Field to be read as signed data */
+ #define BINARY_UNSIGNED 1	/* Field to be read as unsigned data */
+ 
+ /*
   * The following defines the maximum number of different (integer) numbers
   * placed in the object cache by 'binary scan' before it bails out and
   * switches back to Plan A (creating a new object for each value.)
***************
*** 54,62 ****
  			    Tcl_Obj *src, unsigned char **cursorPtr);
  static void		FreeByteArrayInternalRep(Tcl_Obj *objPtr);
  static int		GetFormatSpec(char **formatPtr, char *cmdPtr,
! 			    int *countPtr);
  static Tcl_Obj *	ScanNumber(unsigned char *buffer, int type,
! 			    Tcl_HashTable **numberCachePtr);
  static int		SetByteArrayFromAny(Tcl_Interp *interp,
  			    Tcl_Obj *objPtr);
  static void		UpdateStringOfByteArray(Tcl_Obj *listPtr);
--- 62,70 ----
  			    Tcl_Obj *src, unsigned char **cursorPtr);
  static void		FreeByteArrayInternalRep(Tcl_Obj *objPtr);
  static int		GetFormatSpec(char **formatPtr, char *cmdPtr,
! 			    int *countPtr, int *flagsPtr);
  static Tcl_Obj *	ScanNumber(unsigned char *buffer, int type,
! 			    int flags, Tcl_HashTable **numberCachePtr);
  static int		SetByteArrayFromAny(Tcl_Interp *interp,
  			    Tcl_Obj *objPtr);
  static void		UpdateStringOfByteArray(Tcl_Obj *listPtr);
***************
*** 563,568 ****
--- 571,577 ----
      char cmd;			/* Current format character. */
      int count;			/* Count associated with current format
  				 * character. */
+     int flags;			/* Format field flags */
      char *format;		/* Pointer to current position in format
  				 * string. */
      Tcl_Obj *resultPtr = NULL;	/* Object holding result buffer. */
***************
*** 608,614 ****
  	length = 0;
  	while (*format != '\0') {
  	    str = format;
! 	    if (!GetFormatSpec(&format, &cmd, &count)) {
  		break;
  	    }
  	    switch (cmd) {
--- 617,624 ----
  	length = 0;
  	while (*format != '\0') {
  	    str = format;
! 	    flags = 0;
! 	    if (!GetFormatSpec(&format, &cmd, &count, &flags)) {
  		break;
  	    }
  	    switch (cmd) {
***************
*** 770,776 ****
  	cursor = buffer;
  	maxPos = cursor;
  	while (*format != 0) {
! 	    if (!GetFormatSpec(&format, &cmd, &count)) {
  		break;
  	    }
  	    if ((count == 0) && (cmd != '@')) {
--- 780,787 ----
  	cursor = buffer;
  	maxPos = cursor;
  	while (*format != 0) {
! 	    flags = 0;
! 	    if (!GetFormatSpec(&format, &cmd, &count, &flags)) {
  		break;
  	    }
  	    if ((count == 0) && (cmd != '@')) {
***************
*** 1028,1034 ****
  	offset = 0;
  	while (*format != '\0') {
  	    str = format;
! 	    if (!GetFormatSpec(&format, &cmd, &count)) {
  		goto done;
  	    }
  	    switch (cmd) {
--- 1039,1046 ----
  	offset = 0;
  	while (*format != '\0') {
  	    str = format;
! 	    flags = 0;
! 	    if (!GetFormatSpec(&format, &cmd, &count, &flags)) {
  		goto done;
  	    }
  	    switch (cmd) {
***************
*** 1240,1246 ****
  		    if ((length - offset) < size) {
  			goto done;
  		    }
! 		    valuePtr = ScanNumber(buffer+offset, cmd, &numberCachePtr);
  		    offset += size;
  		} else {
  		    if (count == BINARY_ALL) {
--- 1252,1258 ----
  		    if ((length - offset) < size) {
  			goto done;
  		    }
! 		    valuePtr = ScanNumber(buffer+offset, cmd, flags, &numberCachePtr);
  		    offset += size;
  		} else {
  		    if (count == BINARY_ALL) {
***************
*** 1252,1258 ****
  		    valuePtr = Tcl_NewObj();
  		    src = buffer+offset;
  		    for (i = 0; i < count; i++) {
! 			elementPtr = ScanNumber(src, cmd, &numberCachePtr);
  			src += size;
  			Tcl_ListObjAppendElement(NULL, valuePtr, elementPtr);
  		    }
--- 1264,1270 ----
  		    valuePtr = Tcl_NewObj();
  		    src = buffer+offset;
  		    for (i = 0; i < count; i++) {
! 			elementPtr = ScanNumber(src, cmd, flags, &numberCachePtr);
  			src += size;
  			Tcl_ListObjAppendElement(NULL, valuePtr, elementPtr);
  		    }
***************
*** 1373,1379 ****
  GetFormatSpec(
      char **formatPtr,		/* Pointer to format string. */
      char *cmdPtr,		/* Pointer to location of command char. */
!     int *countPtr)		/* Pointer to repeat count value. */
  {
      /*
       * Skip any leading blanks.
--- 1385,1392 ----
  GetFormatSpec(
      char **formatPtr,		/* Pointer to format string. */
      char *cmdPtr,		/* Pointer to location of command char. */
!     int *countPtr,		/* Pointer to repeat count value. */
!     int *flagsPtr)		/* Pointer to field flags */
  {
      /*
       * Skip any leading blanks.
***************
*** 1397,1402 ****
--- 1410,1419 ----
  
      *cmdPtr = **formatPtr;
      (*formatPtr)++;
+     if (**formatPtr == 'u') {
+ 	(*formatPtr)++;
+ 	(*flagsPtr) |= BINARY_UNSIGNED;
+     }
      if (**formatPtr == '*') {
  	(*formatPtr)++;
  	(*countPtr) = BINARY_ALL;
***************
*** 1778,1783 ****
--- 1795,1801 ----
  ScanNumber(
      unsigned char *buffer,	/* Buffer to scan number from. */
      int type,			/* Format character from "binary scan" */
+     int flags,			/* Format field flags */
      Tcl_HashTable **numberCachePtrPtr)
  				/* Place to look for cache of scanned
  				 * value objects, or NULL if too many
***************
*** 1794,1799 ****
--- 1812,1818 ----
       * 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.
+      * This practice is disabled if the BINARY_UNSIGNED flag is set.
       */
  
      switch (type) {
***************
*** 1806,1813 ****
  	 */
  
  	value = buffer[0];
! 	if (value & 0x80) {
! 	    value |= -0x100;
  	}
  	goto returnNumericObject;
  
--- 1825,1834 ----
  	 */
  
  	value = buffer[0];
! 	if (!(flags & BINARY_UNSIGNED)) {
! 	    if (value & 0x80) {
! 		value |= -0x100;
! 	    }
  	}
  	goto returnNumericObject;
  
***************
*** 1824,1831 ****
  	} else {
  	    value = (long) (buffer[1] + (buffer[0] << 8));
  	}
! 	if (value & 0x8000) {
! 	    value |= -0x10000;
  	}
  	goto returnNumericObject;
  
--- 1845,1854 ----
  	} else {
  	    value = (long) (buffer[1] + (buffer[0] << 8));
  	}
! 	if (!(flags & BINARY_UNSIGNED)) {
! 	    if (value & 0x8000) {
! 		value |= -0x10000;
! 	    }
  	}
  	goto returnNumericObject;
  
***************
*** 1851,1861 ****
  	/*
  	 * 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);
  	}
  
      returnNumericObject:
--- 1874,1890 ----
  	/*
  	 * Check to see if the value was sign extended properly on systems
  	 * where an int is more than 32-bits.
+ 	 * We avoid caching unsigned integers as we cannot distinguish between
+ 	 * 32bit signed and unsigned in the hash (short and char are ok).
  	 */
  
! 	if ((flags & BINARY_UNSIGNED)) {
! 	    return Tcl_NewWideIntObj((unsigned long)value);
! 	} else {
! 	    if ((value & (((unsigned int)1)<<31)) && (value > 0)) {
! 		value -= (((unsigned int)1)<<31);
! 		value -= (((unsigned int)1)<<31);
! 	    }
  	}
  
      returnNumericObject:
***************
*** 1920,1926 ****
  		    | (((Tcl_WideUInt) buffer[1]) << 48)
  		    | (((Tcl_WideUInt) buffer[0]) << 56);
  	}
! 	return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue);
  
  	/*
  	 * Do not cache double values; they are already too large to use as
--- 1949,1964 ----
  		    | (((Tcl_WideUInt) buffer[1]) << 48)
  		    | (((Tcl_WideUInt) buffer[0]) << 56);
  	}
! 	if (flags & BINARY_UNSIGNED) {
! 	    Tcl_Obj *bigObj = NULL;
! 	    mp_int big;
! 
! 	    TclBNInitBignumFromWideUInt(&big, uwvalue);
! 	    bigObj = Tcl_NewBignumObj(&big);
! 	    return bigObj;
! 	} else {
! 	    return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue);
! 	}
  
  	/*
  	 * Do not cache double values; they are already too large to use as
Index: tests/binary.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/binary.test,v
retrieving revision 1.28
diff -c -r1.28 binary.test
*** tests/binary.test	5 Apr 2006 15:17:39 -0000	1.28
--- tests/binary.test	28 Sep 2006 21:26:06 -0000
***************
*** 905,910 ****
--- 905,934 ----
      set arg2 bar
      list [binary scan \x70\x87\x05 c2c* arg1 arg2] $arg1 $arg2
  } {2 {112 -121} 5}
+ test binary-26.11 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1}
+     list [binary scan \x52\xa3 cu* arg1] $arg1
+ } {1 {82 163}}
+ test binary-26.12 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1}
+     list [binary scan \x52\xa3 cu arg1] $arg1
+ } {1 82}
+ test binary-26.13 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1}
+     list [binary scan \xff cu arg1] $arg1
+ } {1 255}
+ test binary-26.14 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1 arg2}
+     set arg1 foo
+     set arg2 bar
+     list [binary scan \x80\x80 cuc arg1 arg2] $arg1 $arg2
+ } {2 128 -128}
+ test binary-26.15 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1 arg2}
+     set arg1 foo
+     set arg2 bar
+     list [binary scan \x80\x80 ccu arg1 arg2] $arg1 $arg2
+ } {2 -128 128}
  
  test binary-27.1 {Tcl_BinaryObjCmd: scan} {
      list [catch {binary scan abc s} msg] $msg
***************
*** 945,950 ****
--- 969,990 ----
      set arg2 bar
      list [binary scan \x52\xa3\x53\x54\x05 s2c* arg1 arg2] $arg1 $arg2
  } {2 {-23726 21587} 5}
+ test binary-27.10 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1}
+     list [binary scan \x52\xa3\x53\x54 su* arg1] $arg1
+ } {1 {41810 21587}}
+ test binary-27.11 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1 arg2}
+     set arg1 foo
+     set arg2 bar
+     list [binary scan \xff\xff\xff\xff sus arg1 arg2] $arg1 $arg2
+ } {2 65535 -1}
+ test binary-27.12 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1 arg2}
+     set arg1 foo
+     set arg2 bar
+     list [binary scan \xff\xff\xff\xff ssu arg1 arg2] $arg1 $arg2
+ } {2 -1 65535}
  
  test binary-28.1 {Tcl_BinaryObjCmd: scan} {
      list [catch {binary scan abc S} msg] $msg
***************
*** 985,990 ****
--- 1025,1038 ----
      set arg2 bar
      list [binary scan \x52\xa3\x53\x54\x05 S2c* arg1 arg2] $arg1 $arg2
  } {2 {21155 21332} 5}
+ test binary-28.10 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1}
+     list [binary scan \x52\xa3\x53\x54 Su* arg1] $arg1
+ } {1 {21155 21332}}
+ test binary-28.11 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1}
+     list [binary scan \xa3\x52\x54\x53 Su* arg1] $arg1
+ } {1 {41810 21587}}
  
  test binary-29.1 {Tcl_BinaryObjCmd: scan} {
      list [catch {binary scan abc i} msg] $msg
***************
*** 1025,1030 ****
--- 1073,1090 ----
      set arg2 bar
      list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04\x05 i2c* arg1 arg2] $arg1 $arg2
  } {2 {1414767442 67305985} 5}
+ test binary-29.10 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1 arg2}
+     list [binary scan \xff\xff\xff\xff\xff\xff\xff\xff iui arg1 arg2] $arg1 $arg2
+ } {2 4294967295 -1}
+ test binary-29.11 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1 arg2}
+     list [binary scan \xff\xff\xff\xff\xff\xff\xff\xff iiu arg1 arg2] $arg1 $arg2
+ } {2 -1 4294967295}
+ test binary-29.12 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1 arg2}
+     list [binary scan \x80\x00\x00\x00\x00\x00\x00\x80 iuiu arg1 arg2] $arg1 $arg2
+ } {2 128 2147483648}
  
  test binary-30.1 {Tcl_BinaryObjCmd: scan} {
      list [catch {binary scan abc I} msg] $msg
***************
*** 1065,1070 ****
--- 1125,1142 ----
      set arg2 bar
      list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04\x05 I2c* arg1 arg2] $arg1 $arg2
  } {2 {1386435412 16909060} 5}
+ test binary-30.10 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1 arg2}
+     list [binary scan \xff\xff\xff\xff\xff\xff\xff\xff IuI arg1 arg2] $arg1 $arg2
+ } {2 4294967295 -1}
+ test binary-30.11 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1 arg2}
+     list [binary scan \xff\xff\xff\xff\xff\xff\xff\xff IIu arg1 arg2] $arg1 $arg2
+ } {2 -1 4294967295}
+ test binary-30.12 {Tcl_BinaryObjCmd: scan} {
+     catch {unset arg1 arg2}
+     list [binary scan \x80\x00\x00\x00\x00\x00\x00\x80 IuIu arg1 arg2] $arg1 $arg2
+ } {2 2147483648 128}
  
  test binary-31.1 {Tcl_BinaryObjCmd: scan} {
      list [catch {binary scan abc f} msg] $msg
***************
*** 1384,1389 ****
--- 1456,1481 ----
      catch {unset arg1}
      list [binary scan \x01\x01\x01\x02\x81\x01\x01\x01\x01\x82\x01\x01\x01\x01\x82\x01\x01\x01\x01\x81 I5 arg1] $arg1
  } {1 {16843010 -2130640639 25297153 16876033 16843137}}
+ test binary-39.6 {ScanNumber: no sign extension} {
+     catch {unset arg1}
+     list [binary scan \x52\xa3 cu2 arg1] $arg1
+ } {1 {82 163}}
+ test binary-39.7 {ScanNumber: no sign extension} {
+     catch {unset arg1}
+     list [binary scan \x01\x02\x01\x81\x82\x01\x81\x82 su4 arg1] $arg1
+ } {1 {513 33025 386 33409}}
+ test binary-39.8 {ScanNumber: no sign extension} {
+     catch {unset arg1}
+     list [binary scan \x01\x02\x01\x81\x82\x01\x81\x82 Su4 arg1] $arg1
+ } {1 {258 385 33281 33154}}
+ test binary-39.9 {ScanNumber: no sign extension} {
+     catch {unset arg1}
+     list [binary scan \x01\x01\x01\x02\x81\x01\x01\x01\x01\x82\x01\x01\x01\x01\x82\x01\x01\x01\x01\x81 iu5 arg1] $arg1
+ } {1 {33620225 16843137 16876033 25297153 2164326657}}
+ test binary-39.10 {ScanNumber: no sign extension} {
+     catch {unset arg1}
+     list [binary scan \x01\x01\x01\x02\x81\x01\x01\x01\x01\x82\x01\x01\x01\x01\x82\x01\x01\x01\x01\x81 Iu5 arg1] $arg1
+ } {1 {16843010 2164326657 25297153 16876033 16843137}}
  
  test binary-40.3 {ScanNumber: NaN} \
      -body {
***************
*** 1463,1468 ****
--- 1555,1580 ----
      binary scan [binary format W [expr {wide(3) << 31}]] W x
      set x
  } 6442450944
+ test binary-43.5 {Tcl_BinaryObjCmd: scan wide int} {} {
+     catch {unset arg1}
+     list [binary scan \x80[string repeat \x00 7] W arg1] $arg1
+ } {1 -9223372036854775808}
+ test binary-43.6 {Tcl_BinaryObjCmd: scan unsigned wide int} {} {
+     catch {unset arg1}
+     list [binary scan \x80[string repeat \x00 7] Wu arg1] $arg1
+ } {1 9223372036854775808}
+ test binary-43.7 {Tcl_BinaryObjCmd: scan unsigned wide int} {} {
+     catch {unset arg1}
+     list [binary scan [string repeat \x00 7]\x80 wu arg1] $arg1
+ } {1 9223372036854775808}
+ test binary-43.8 {Tcl_BinaryObjCmd: scan unsigned wide int} {} {
+     catch {unset arg1 arg2}
+     list [binary scan \x80[string repeat \x00 7]\x80[string repeat \x00 7] WuW arg1 arg2] $arg1 $arg2
+ } {2 9223372036854775808 -9223372036854775808}
+ test binary-43.9 {Tcl_BinaryObjCmd: scan unsigned wide int} {} {
+     catch {unset arg1 arg2}
+     list [binary scan [string repeat \x00 7]\x80[string repeat \x00 7]\x80 wuw arg1 arg2] $arg1 $arg2
+ } {2 9223372036854775808 -9223372036854775808}
  
  test binary-45.1 {Tcl_BinaryObjCmd: combined wide int handling} {
      binary scan [binary format sws 16450 -1 19521] c* x
