UninterpretedBytes.st
branchjv
changeset 19431 3e697e4bcbf5
parent 19412 1e842c25e51e
parent 19415 524cb9f19895
child 19478 1f5aa87f6170
--- a/UninterpretedBytes.st	Wed Mar 23 07:50:28 2016 +0000
+++ b/UninterpretedBytes.st	Thu Mar 24 07:05:30 2016 +0100
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 1993 by Claus Gittinger
               All Rights Reserved
@@ -743,7 +745,7 @@
 longLongAt:index
     "return the 8-bytes starting at index as a signed Integer.
      The index is a smalltalk index (i.e. 1-based).
-     The value is retrieved in the machineÄs natural byte order.
+     The value is retrieved in the machineÄs natural byte order.
      This may be worth a primitive."
 
     ^ self signedInt64At:index MSB:IsBigEndian
@@ -997,10 +999,9 @@
 signedLongAt:index
     "return the 4-bytes starting at index as a signed Integer.
      The index is a smalltalk index (i.e. 1-based).
-     The value is retrieved in the machines natural byte order.
-     This may be worth a primitive."
-
-    ^ self longAt:index
+     The value is retrieved in the machine's natural byte order."
+
+    ^ self signedInt32At:index
 
     "
      |b|
@@ -1013,11 +1014,11 @@
 !
 
 signedLongAt:index put:newValue
-    "store a 4-bytes value starting at index.
+    "store a 4-bytes signed value starting at index.
      The index is a smalltalk index (i.e. 1-based).
-     The value is in the machines natural byte order."
-
-    ^ self longAt:index put:newValue
+     The value is in the machine's natural byte order."
+
+    ^ self signedInt32At:index put:newValue
 
     "
      |b|
@@ -1095,7 +1096,7 @@
      The value is stored MSB-first, if the msb-arg is true;
      LSB-first otherwise."
 
-    ^ self int16At:byteIndex put:anInteger MSB:msb
+    ^ self signedInt16At:byteIndex put:anInteger MSB:msb
 
     "
      |b|
@@ -1439,11 +1440,11 @@
 
 uint32At:zeroBasedIndex
     "return the 4-bytes starting at index as (unsigned) Integer.
-     The index is a C index (i.e. 0-based).
+     WARNING: The index is a C index (i.e. 0-based).
      The value is retrieved in the machine's natural byte order.
-     Similar to unsignedLongAt:, except for the index base"
-
-    ^ self unsignedLongAt:zeroBasedIndex+1
+     Similar to unsignedInt32At:, except for the index base"
+
+    ^ self unsignedInt32At:zeroBasedIndex+1
 
     "
      |b|
@@ -1457,11 +1458,11 @@
 
 uint32At:zeroBasedIndex put:anInteger
     "set the 4-bytes starting at index to the value given by (unsigned) Integer.
-     The index is a C index (i.e. 0-based).
-     The value is stored in the machines natural byte order.
-     Similar to unsignedLongAt:put:, except for the index base"
-
-    ^ self unsignedLongAt:zeroBasedIndex+1 put:anInteger
+     WARNING: The index is a C index (i.e. 0-based).
+     The value is stored in the machine's natural byte order.
+     Similar to unsignedInt32At:put:, except for the index base"
+
+    ^ self unsignedInt32At:zeroBasedIndex+1 put:anInteger
 
     "
      |b|
@@ -1912,7 +1913,7 @@
     "return the 8-bytes starting at index as a Float.
      The index is a smalltalk index (i.e. 1-based).
      Notice, that (currently) ST/X Floats are what Doubles are in ST-80.
-     Notice also, that the bytes are expected to be in this machines
+     Notice also, that the bytes are expected to be in this machine's
      float representation - if the bytearray originated from another
      machine, some conversion is usually needed."
 
@@ -1928,9 +1929,9 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(index)) - 1;
-
-            if ((idx+(sizeof(double)-1)) < sz) {
+            INT idx = __intVal(index) - 1;
+
+            if ((idx >= 0) && ((idx+(sizeof(double)-1)) < sz)) {
                 cp += idx;
                 /*
                  * aligned
@@ -1991,7 +1992,7 @@
      starting at index.
      The index is a smalltalk index (i.e. 1-based).
      Notice, that (currently) ST/X Floats are what Doubles are in ST-80.
-     Notice also, that the bytes are expected to be in this machines
+     Notice also, that the bytes are expected to be in this machine's
      float representation - if the bytearray originated from another
      machine, some conversion is usually needed."
 
@@ -2007,9 +2008,9 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(index)) - 1;
-
-            if ((idx+(sizeof(double)-1)) < sz) {
+            INT idx = __intVal(index) - 1;
+
+            if ((idx >= 0) && ((idx+(sizeof(double)-1)) < sz)) {
                 cp += idx;
                 /*
                  * aligned
@@ -2045,7 +2046,7 @@
      starting at index.
      The index is a smalltalk index (i.e. 1-based).
      Notice, that (currently) ST/X Floats are what Doubles are in ST-80.
-     Notice also, that the bytes are expected to be in this machines
+     Notice also, that the bytes are expected to be in this machine's
      float representation - if the bytearray originated from another
      machine, some conversion is usually needed."
 
@@ -2071,7 +2072,7 @@
      Notice, that (currently) ST/X Floats are what Doubles are in ST-80;
      therefore this method reads a 4-byte float from the byteArray and returns
      a float object which keeps an 8-byte double internally.
-     Notice also, that the bytes are expected to be in this machines
+     Notice also, that the bytes are expected to be in this machine's
      float representation and order - if the bytearray originated from another
      machine, some conversion is usually needed."
 
@@ -2087,9 +2088,9 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(index)) - 1;
-
-            if ((idx+(sizeof(float)-1)) < sz) {
+            INT idx = __intVal(index) - 1;
+
+            if ((idx >= 0) && ((idx+(sizeof(float)-1)) < sz)) {
                 cp += idx;
                 /*
                  * aligned
@@ -2119,7 +2120,7 @@
      Notice, that (currently) ST/X Floats are what Doubles are in ST-80;
      therefore this method reads a 4-byte float from the byteArray and returns
      a float object which keeps an 8-byte double internally.
-     Notice also, that the bytes are expected to be in this machines
+     Notice also, that the bytes are expected to be in this machine's
      float representation and order - if the bytearray originated from another
      machine, some conversion is usually needed."
 
@@ -2160,9 +2161,9 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(index)) - 1;
-
-            if ((idx+(sizeof(float)-1)) < sz) {
+            INT idx = __intVal(index) - 1;
+
+            if ((idx >= 0) && ((idx+(sizeof(float)-1)) < sz)) {
                 cp += idx;
                 /*
                  * aligned
@@ -2224,7 +2225,7 @@
      number format."
 
     "
-     currently, we assume that the machines native number format is already
+     currently, we assume that the machine's native number format is already
      IEEE format - we need some more code here whenever ST/X is ported
      to an IBM 370 or old VAX etc.
      To date, all supported systems use IEEE float numbers, so there should be
@@ -2244,7 +2245,7 @@
      (i.e. 8 bytes are stored)."
 
     "
-     currently, we assume that the machines native number format is already
+     currently, we assume that the machine's native number format is already
      IEEE format - we need some more code here whenever ST/X is ported
      to an IBM 370 or old VAX etc.
      To date, all supported systems use IEEE float numbers, so there should be
@@ -2264,7 +2265,7 @@
      number format."
 
     "
-     currently, we assume that the machines native number format is already
+     currently, we assume that the machine's native number format is already
      IEEE format - we need some more code here whenever ST/X is ported
      to an IBM 370 or old VAX etc.
      To date, all supported systems use IEEE float numbers, so there should be
@@ -2285,7 +2286,7 @@
      order 4 bytes of the precision is lost."
 
     "
-     currently, we assume that the machines native number format is already
+     currently, we assume that the machine's native number format is already
      IEEE format - we need some more code here whenever ST/X is ported
      to an IBM 370 or old VAX etc.
      To date, all supported systems use IEEE float numbers, so there should be
@@ -2499,10 +2500,10 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__smallIntegerVal(index)) - 1;
+            INT idx = __smallIntegerVal(index) - 1;
             char *pointer;
 
-            if ((idx+(sizeof(pointer)-1)) < sz) {
+            if ((idx >= 0) && ((idx+(sizeof(pointer)-1)) < sz)) {
                 cp += idx;
                 /*
                  * aligned
@@ -2549,7 +2550,7 @@
     "set the pointer starting at index from the integer or externalAddress value.
      The index is a smalltalk index (i.e. 1-based).
      Only aligned accesses are allowed.
-     The value is either an ExternalAddress or ExternalBytes"
+     The value is either an ExternalAddress, ExternalBytes or an Integer"
 
 %{
     OBJ *pointer;
@@ -2576,9 +2577,9 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__smallIntegerVal(index)) - 1;
-
-            if ((idx+(sizeof(pointer)-1)) < sz) {
+            INT idx = __smallIntegerVal(index) - 1;
+
+            if ((idx >= 0) && ((idx+(sizeof(pointer)-1)) < sz)) {
                 cp += idx;
                 /*
                  * aligned
@@ -2607,7 +2608,7 @@
 !
 
 pointerValueAt:index
-    "get a pointer starting at index as Integer.
+    "get a pointer value starting at index as unsigned integer.
      The index is a smalltalk index (i.e. 1-based).
      Only aligned accesses are allowed."
 
@@ -2618,10 +2619,10 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__smallIntegerVal(index)) - 1;
+            INT idx = __smallIntegerVal(index) - 1;
             char *pointer;
 
-            if ((idx+(sizeof(pointer)-1)) < sz) {
+            if ((idx >= 0) && ((idx+(sizeof(pointer)-1)) < sz)) {
                 cp += idx;
                 /*
                  * aligned
@@ -2671,9 +2672,9 @@
      The value is retrieved in the machine's natural byte order,
      therefore, this should only be used for byte-data which is
      only used inside this machine.
-     To setup data packets which are to be sent to other machines,
-     or stored into a file, always use longAt:MSB: and specify
-     a definite byteOrder."
+     To setup binary data packets which are to be sent to other machines,
+     or stored into a file, always use the corresponding xxx:MSB: method
+     and specify a definite byteOrder."
 
     |w|
 
@@ -2687,43 +2688,76 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(byteIndex)) - 1;
-
-            if ((idx+(sizeof(int)-1)) < sz) {
+            INT idx = __intVal(byteIndex) - 1;
+
+            if ((idx >= 0) && ((idx+(4-1)) < sz)) {
+                int iVal;
+
                 cp += idx;
 #if defined(__i386__)
                 /*
-                 * aligned or not, we dont care (i386 can do both)
+                 * aligned or not, we don't care (i386 can do both)
                  */
                 {
-                    int iVal = ((int *)cp)[0];
-
+                    iVal = ((int *)cp)[0];
                     RETURN (__MKINT(iVal));
                 }
 #else
+# if defined(__x86_64__)
                 /*
-                 * aligned
+                 * aligned or not, we don't care (i386 can do both)
+                 */
+                {
+                    iVal = ((int *)cp)[0];
+                    RETURN (__mkSmallInteger(iVal));
+                }
+# else
+                /*
+                 * aligned ?
                  */
                 if (((INT)cp & (sizeof(int)-1)) == 0) {
-                    int iVal = ((int *)cp)[0];
-
-# if __POINTER_SIZE__ == 8
+                    iVal = ((int *)cp)[0];
+                } else {
+#  ifdef __LSBFIRST__
+                    iVal = cp[0] & 0xFF;
+                    iVal += (cp[1] & 0xFF)<<8;
+                    iVal += (cp[2] & 0xFF)<<16;
+                    iVal += (cp[3] & 0xFF)<<24;
+#  else
+#   ifdef __MSBFIRST__
+                    iVal = cp[0] & 0xFF;
+                    iVal = (iVal<<8)+(cp[1] & 0xFF);
+                    iVal = (iVal<<8)+(cp[2] & 0xFF);
+                    iVal = (iVal<<8)+(cp[3] & 0xFF);
+#   else
+                    {
+                        union {
+                            int i;
+                            char c[4];
+                        } u;
+                        u.c[0] = cp[0]; 
+                        u.c[1] = cp[1]; 
+                        u.c[2] = cp[2]; 
+                        u.c[3] = cp[3];
+                        iVal = u.i;
+                    }
+#   endif
+#  endif
+
+#  if __POINTER_SIZE__ == 8
                     RETURN (__mkSmallInteger(iVal));
-# else
+#  else
                     RETURN (__MKINT(iVal));
+#  endif
+                }
 # endif
-                }
 #endif
             }
         }
     }
 %}.
 
-    w := self unsignedLongAt:byteIndex.
-    (w > (16r7FFFFFFF)) ifTrue:[
-        ^ w - (16r100000000)
-    ].
-    ^ w
+    ^ self signedInt32At:byteIndex MSB:IsBigEndian.
 
     "
      |b|
@@ -2760,12 +2794,11 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(byteIndex)) - 1;
+            INT idx = __intVal(byteIndex) - 1;
             int iVal;
 
             cp += idx;
-
-            if ((idx+(sizeof(int)-1)) < sz) {
+            if ((idx >= 0) && ((idx+(sizeof(int)-1)) < sz)) {
 
                 if (msb == true) {
 #if defined(__MSBFIRST__)
@@ -2816,25 +2849,7 @@
     }
 %}.
 
-    "/ fallBack code - non ByteArray-like receiver
-    "/ or funny byteIndex
-
-    i := byteIndex.
-    msb ifFalse:[
-        bLL := self byteAt:i.
-        bLH := self byteAt:(i+1).
-        bHL := self byteAt:(i+2).
-        bHH := self byteAt:(i+3).
-    ] ifTrue:[
-        bHH := self byteAt:i.
-        bHL := self byteAt:(i+1).
-        bLH := self byteAt:(i+2).
-        bLL := self byteAt:(i+3).
-    ].
-    ival := (bHH bitShift:8) + bHL.
-    ival := (ival bitShift:8) + bLH.
-    val := (ival bitShift:8) + bLL.
-
+    val := self unsignedInt32At:byteIndex MSB:msb.
     (val > (16r7FFFFFFF)) ifTrue:[
         ^ val - (16r100000000)
     ].
@@ -2870,8 +2885,6 @@
 signedInt32At:byteIndex put:anInteger MSB:msb
     "set the 4-bytes starting at byteIndex from the signed Integer value.
      The byteIndex is a smalltalk index (i.e. 1-based).
-     The value is stored in the machines natural byte order.
-     This may be worth a primitive.
 
      This is the ST80 version of #signedDoubleWordAt:put:"
 
@@ -2887,9 +2900,9 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(byteIndex)) - 1;
-
-            if ((idx+3) < sz) {
+            INT idx = __intVal(byteIndex) - 1;
+
+            if ((idx >= 0) && ((idx+3) < sz)) {
                 cp += idx;
 
                 if (__isSmallInteger(anInteger)) {
@@ -2960,7 +2973,7 @@
 unsignedInt32At:byteIndex
     "return the 4-bytes starting at index as an (unsigned) Integer.
      The index is a smalltalk index (i.e. 1-based).
-     The value is retrieved in the machines natural byte order."
+     The value is retrieved in the machine's natural byte order."
 
     ^ self unsignedInt32At:byteIndex MSB:IsBigEndian
 
@@ -2998,10 +3011,10 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(byteIndex)) - 1;
+            INT idx = __intVal(byteIndex) - 1;
             unsigned int iVal;
 
-            if ((idx+(sizeof(int)-1)) < sz) {
+            if ((idx >= 0) && ((idx+(sizeof(int)-1)) < sz)) {
                 cp += idx;
 
                 if (msb == true) {
@@ -3103,16 +3116,73 @@
 !
 
 unsignedInt32At:byteIndex put:anInteger MSB:msb
-    "set the 4-bytes starting at index from the (unsigned) integer value.
-     The index is a smalltalk index (i.e. 1-based).
-     The value must be in the range 0 to 16rFFFFFFFF.
-     The value is stored MSB-first if msb is true; LSB-first otherwise."
-
-    |i "{ Class: SmallInteger }" 
-     b1 "{ Class: SmallInteger }"
-     b2 "{ Class: SmallInteger }"
-     b3 "{ Class: SmallInteger }"
-     b4 "{ Class: SmallInteger }"|
+    "set the 4-bytes starting at byteIndex from the unsigned Integer value.
+     The byteIndex is a smalltalk index (i.e. 1-based).
+
+     This is the ST80 version of #doubleWordAt:put:"
+
+    |v i b1 b2 b3 b4|
+
+%{
+    /*
+     * handle the most common case fast ...
+     */
+    if (__isSmallInteger(byteIndex)) {
+        unsigned char *cp;
+        INT sz;
+
+        __fetchBytePointerAndSize__(self, &cp, &sz);
+        if (cp) {
+            INT idx = __intVal(byteIndex) - 1;
+
+            if ((idx >= 0) && ((idx+3) < sz)) {
+                cp += idx;
+
+                if (__isSmallInteger(anInteger)) {
+                    INT __v = __intVal(anInteger);
+
+# if __POINTER_SIZE__ == 8
+                    if ((__v < 0) || (__v > 0xFFFFFFFF)) {
+                        goto badArg;
+                    }
+# endif
+                    if (((INT)cp & 3) == 0) {
+                        /*
+                         * aligned
+                         */
+                        if (
+# ifdef __LSBFIRST__
+                            (msb == false)
+# else
+#  ifdef __MSBFIRST__
+                            (msb == true)
+#  else
+                            (0)
+#  endif
+# endif
+                        ) {
+                            ((int *)cp)[0] = (int)__v;
+                            RETURN (anInteger);
+                        }
+                    }
+                    if (msb == false) {
+                        cp[0] = __v & 0xFF;
+                        cp[1] = (__v>>8) & 0xFF;
+                        cp[2] = (__v>>16) & 0xFF;
+                        cp[3] = (__v>>24) & 0xFF;
+                    } else {
+                        cp[0] = (__v>>24) & 0xFF;
+                        cp[1] = (__v>>16) & 0xFF;
+                        cp[2] = (__v>>8) & 0xFF;
+                        cp[3] = __v & 0xFF;
+                    }
+                    RETURN (anInteger);
+                }
+            }
+        }
+    }
+  badArg: ;
+%}.
 
     ((anInteger < 0) or:[anInteger > 16rFFFFFFFF]) ifTrue:[
         ^ self elementBoundsError:anInteger
@@ -3138,14 +3208,16 @@
 
     "
      |b|
-     b := ByteArray new:8.
-     b doubleWordAt:1 put:16r04030201 MSB:true.
-     b doubleWordAt:5 put:16r04030201 MSB:false.
-     b inspect
-    "
-
-    "Modified: / 21.1.1998 / 17:43:34 / cg"
-    "Modified: / 5.3.1998 / 11:42:17 / stefan"
+     b := ByteArray new:4.
+     b signedInt32At:1 put:-1.
+     (b unsignedInt32At:1) printStringRadix:16 
+    "
+    "
+     |b|
+     b := ByteArray new:4.
+     b unsignedInt32At:1 put:16rFFFFFFFF.
+     (b signedInt32At:1) 
+    "
 ! !
 
 !UninterpretedBytes methodsFor:'accessing-shorts (16bit)'!
@@ -3153,8 +3225,7 @@
 signedInt16At:byteIndex
     "return the 2-bytes starting at index as a signed Integer.
      The index is a smalltalk index (i.e. 1-based).
-     The value is retrieved in the machines natural byte order.
-     This may be worth a primitive."
+     The value is retrieved in the machine's natural byte order."
 
     ^ (self unsignedInt16At:byteIndex) signExtendedShortValue
 
@@ -3190,9 +3261,9 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(byteIndex)) - 1;
-
-            if ((idx+(2-1)) < sz) {
+            INT idx = __intVal(byteIndex) - 1;
+
+            if ((idx >= 0) && ((idx+(2-1)) < sz)) {
                 short sVal;
 
                 cp += idx;
@@ -3258,9 +3329,9 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(byteIndex)) - 1;
-
-            if ((idx+1) < sz) {
+            INT idx = __intVal(byteIndex) - 1;
+
+            if ((idx >= 0) && ((idx+1) < sz)) {
                 cp += idx;
 
                 if (__isSmallInteger(anInteger)) {
@@ -3308,8 +3379,7 @@
 unsignedInt16At:index
     "return the 2-bytes starting at index as an (unsigned) Integer.
      The index is a smalltalk index (i.e. 1-based).
-     The value is retrieved in the machine's natural byte order
-     Subclasses may redefine this for better performance."
+     The value is retrieved in the machine's natural byte order"
 
     ^ self unsignedInt16At:index MSB:IsBigEndian
 !
@@ -3336,11 +3406,11 @@
 
         __fetchBytePointerAndSize__(self, &cp, &sz);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(byteIndex)) - 1;
-
-            if ((idx+(2-1)) < sz) {
+            INT idx = __intVal(byteIndex) - 1;
+
+            if ((idx >= 0) && ((idx+(2-1)) < sz)) {
                 int iVal;
-
+printf("1\n");
                 cp += idx;
                 if (msb == false) {
 #if defined(__i386__) || (defined(__LSBFIRST__) && defined(UNALIGNED_FETCH_OK))
@@ -3366,13 +3436,21 @@
         ^ (b1 bitShift:8) + b2
     ].
     ^ (b2 bitShift:8) + b1
+
+    "
+     #[ 16rFF 16r00 ] unsignedInt16At:1 MSB:true
+     #[ 16rFF 16r00 ] unsignedInt16At:1 MSB:false
+
+     #[ 16rFF 16r00 ] unsignedInt16At:2 MSB:true
+     #[ 16rFF 16r00 ] unsignedInt16At:2 MSB:false
+    "
 !
 
 unsignedInt16At:index put:anInteger
     "set the 2-bytes starting at index from the (unsigned) Integer value.
      The index is a smalltalk index (i.e. 1-based).
      The stored value must be in the range 0 .. 16rFFFF.
-     The value is stored in the machines natural byteorder."
+     The value is stored in the machine's natural byteorder."
 
     ^ self unsignedInt16At:index put:anInteger MSB:IsBigEndian
 
@@ -3409,9 +3487,9 @@
         __fetchBytePointerAndSize__(self, &cp, &sz);
         // printf("cp=%"_lx_"\n", (INT)cp);
         if (cp) {
-            unsigned INT idx = ((unsigned INT)__intVal(byteIndex)) - 1;
-
-            if ((idx+1) < sz) {
+            INT idx = __intVal(byteIndex) - 1;
+
+            if ((idx >= 0) && ((idx+1) < sz)) {
                 cp += idx;
 
                 if (__isSmallInteger(anInteger)) {
@@ -3604,14 +3682,22 @@
      maximum number of characters (bytes).
      The index is a smalltalk index (i.e. 1-based)."
 
-    |bytes idx|
-
-    bytes := self copyFrom:index to:(index + count - 1).
-    idx := bytes indexOf:0.
-    idx ~~ 0 ifTrue:[ bytes := bytes copyTo:idx-1 ].
+    |bytes endIndex idx|
+
+    endIndex := self indexOf:0 startingAt:index.
+    endIndex == 0 ifTrue:[
+        endIndex := self size + 1
+    ].
+    endIndex := (endIndex min: (index + count)) - 1.
+    bytes := self copyFrom:index to:endIndex.
     ^ bytes asString
 
-    "Created: 9.9.1996 / 15:28:34 / cg"
+    "
+     #[ 1 2 3 4 5 6 7 8 ] zeroByteStringAt:2 maximumSize:10
+     #[ 1 2 3 4 5 0 6 7 8 ] zeroByteStringAt:2 maximumSize:10
+     #[ 1 2 3 4 5 0 6 7 8 ] zeroByteStringAt:2 maximumSize:3
+     #[ 1 2 3 4 5 0 6 7 8 ] zeroByteStringAt:2 maximumSize:4
+    "
 ! !
 
 !UninterpretedBytes methodsFor:'converting'!
@@ -4169,6 +4255,26 @@
      #[1 2 3 4 5] copyReverse
      #[1 2 3 4] copyReverse
     "
+!
+
+swapBytes
+    "swap bytes (of int16s) inplace -
+     Expects that the receiver has an even number of bytes;
+     if not, only the pairs excluding the last byte are swapped"
+
+    |b1 lastIndex "{ Class: SmallInteger }"|
+
+    lastIndex := self size-1.
+    1 to:lastIndex by:2 do:[:idx |
+        b1 := self byteAt:idx.
+        self byteAt:idx put:(self byteAt:idx+1).
+        self byteAt:idx+1 put:b1.
+    ].
+
+    "
+     #[1 2 3 4 5] swapBytes
+     #[1 2 3 4] swapBytes
+    "
 ! !