!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: bytearray.gs,v 1.16 2008-01-09 22:50:08 stever Exp $
!
! Superclass Hierarchy:
!   ByteArray, SequenceableCollection, Collection, Object.
!
!=========================================================================

! class ByteArray is created in bom

removeallmethods ByteArray
removeallclassmethods ByteArray

category: 'For Documentation Installation only'
classmethod: ByteArray
installDocumentation

| doc txt |
doc := GsClassDocumentation newForClass: self.

txt := (GsDocText new) details:
'A ByteArray is a SequenceableCollection whose elements are SmallIntegers with
 a value between zero and 255 inclusive.  Uninitialized ByteArray elements are
 zero.' .
doc documentClassWith: txt.

self description: doc.

%
! fromString:   Gs64 v2.2, changed to allow DoubleByteString arg to fix 36126
category: 'instance creation'
classmethod: ByteArray
fromString: aString

"aString must be a kind of String or DoubleByteString"

<primitive: 653>
aString _validateClasses:#[ String, DoubleByteString].
self _primitiveFailed: #fromString 
%

category: 'Comparing'
method: ByteArray
= aByteArray

"(R) Returns true if all of the following conditions are true, otherwise
  returns false.

 1.  The receiver and aByteArray are of the same class.
 2.  The two Arrays are the same size.
 3.  The corresponding elements of the receiver and aByteArray
     are equal."

<primitive: 613>

^ super = aByteArray.
%

category: 'Copying'
method: ByteArray
copyFrom: index1 to: index2 into: aByteArray startingAt: destIndex

"(R) Copies the elements of the receiver between index1 and index2, inclusive,
 into aByteArray starting at destIndex, overwriting the previous contents.  If
 aByteArray is the same object as the receiver, the source and destination
 blocks may overlap."

<primitive: 231>

aByteArray _validateClass: ByteArray.
^super copyFrom: index1 to: index2 into: aByteArray startingAt: destIndex
%

! fixed 31357
category: 'Copying'
method: ByteArray
insertAll: aByteArray at: anIndex

"(R) Inserts aByteArray into the receiver beginning at anIndex.  The receiver's
 size is modified to become its old size plus the size of aByteArray.

 The argument anIndex must be greater than or equal to 1.  If anIndex is 1
 greater than the size of the receiver, appends aByteArray to the receiver.  If
 anIndex is more than 1 greater than the size of the receiver, generates an
 error."

<primitive: 230>

aByteArray _validateClass: ByteArray.
(anIndex _isInteger)
  ifFalse: [ ^ self _errorNonIntegerIndex: anIndex].
(anIndex < 1 _or: [ anIndex > (self size + 1)]) "out of bounds"
  ifTrue: [ ^ self _errorIndexOutOfRange: anIndex].

^ super insertAll: aByteArray at: anIndex
%

category: 'Adding'
method: ByteArray
addAll: aCollection

"(R) Adds all of the elements of aCollection to the receiver and returns
 aCollection."

"Note: In GemStone 4.1, (1) this method returned the receiver and (2) if the
 argument was a kind of AbstractDictionary, this method added all the
 Associations of the key/value pairs stored in the argument."

| collectionSize |

(self == aCollection) ifTrue: [ ^ self addAll: (aCollection copy) ].

(aCollection isKindOf: ByteArray) ifTrue:[
  collectionSize := aCollection size.
  (collectionSize ~~ 0) ifTrue:[
    self insertAll: aCollection at: (self size + 1)
    ].
  ^ aCollection.
  ].
aCollection do: [:each | self add: each ].
^ aCollection
%

category: 'Comparing'
method: ByteArray
hash

"Returns a positive SmallInteger based on the contents of the receiver."

"Uses a case-sensitive string hash algorithm.
 The algorithm implemented is described in:

 [Pearson 90]
 Pearson, Peter K., Fast Hashing of Variable-Length Text Strings,
 Communications of the ACM 33, 6, (June 1990), 677-680."

<primitive: 31>
self _primitiveFailed: #hash .
self _uncontinuableError
%

category: 'Converting'
method: ByteArray
asHexString

"Returns a String containing a hexadecimal printed representation of the
 contents of the receiver.  For example, the message 'abc' asHexString
 returns the String '616163'.

 The receiver must be a byte format object."

<primitive: 467>
self _validateByteClass: ByteArray .
self _primitiveFailed: #asHexString .
%

category: 'Accessing'
method: ByteArray
charAt: index

"Returns a (single byte) Character located at index in the receiver."

<primitive: 500>

(index _isInteger)
  ifFalse: [^ self _errorNonIntegerIndex: index].

((index <= 0) _or: [ (index > self size) ])
  ifTrue: [^ self _errorIndexOutOfRange: index].

self _validateByteClass: ByteArray .
self _primitiveFailed: #charAt: .
%

category: 'Accessing'
method: ByteArray
doubleByteCharAt: index

"Returns a double-byte Character located at index in the receiver. The most
 significant byte would be the one located at index, the least significant 
 one located at index + 1."

<primitive: 501>

(index _isInteger)
  ifFalse: [^ self _errorNonIntegerIndex: index].

((index <= 0) _or: [ (index >= self size) ])
  ifTrue: [^ self _errorIndexOutOfRange: index].

self _validateByteClass: ByteArray .
self _primitiveFailed: #doubleByteCharAt: .
%

category: 'Accessing'
method: ByteArray
at: index putChar: char

"Stores the codepoint of char in the receiver at index. Stores one byte if
 char is a single byte character, two bytes if it is a double byte 
 character. Returns char."

<primitive: 502>

(index _isInteger)
  ifFalse: [^ self _errorNonIntegerIndex: index].

((index <= 0) _or: [ (index > (self size + 1)) ])
  ifTrue: [^ self _errorIndexOutOfRange: index].

char _validateClass: Character .
self _validateByteClass: ByteArray .
self _primitiveFailed: #at:putChar: .
%

category: 'Removing'
method: ByteArray
removeFrom: startIndex to: stopIndex

"(R) Deletes the elements of the receiver from startIndex to stopIndex.  The
 size of the receiver is decreased by stopIndex - startIndex + 1.

 Both startIndex and stopIndex must be positive integers not larger than the
 size of the receiver, with startIndex <= stopIndex."

<primitive: 386>

(stopIndex < startIndex)
ifTrue:
   [ ^ startIndex _error: #rtErrBadCopyFromTo args: #[stopIndex]].
((stopIndex > self size) _or: [(stopIndex < 1)])
   ifTrue: [ ^ self _errorIndexOutOfRange: stopIndex].
(startIndex < 1)
   ifTrue: [ ^ self _errorIndexOutOfRange: startIndex].
^ self _primitiveFailed: #removeFrom:to:
%

category: 'Private'
method: ByteArray
at: index put: aString fromOffset: stringOffset sizeBytes: numBytes
 "Write a string into the receiver, which must be a byte object (usually
  a ByteArray).  The offset to start writing the receiver is given by the
  at: argument, the object to write (must also be a byte object, usually
  a string) is given by the put: argument.  The fromOffset: argument 
  specifies the offset from within the given string to start copying.
  The sizeBytes argument specifies the width it takes to store the size
  of the string.  The size of the string is stored in the first offset
  of the byte array.  The sizeBytes must one of the following values:
 
  sizeBytes   max string size      Notes
     0        255                  Do not store the size in the byte array
     1        255
     2        65535
     4        4 GB - 1
     8        max legal object size - 8.
  Returns the receiver."

<primitive: 622>
self _primitiveFailed: #at:put:fromOffset:sizeBytes:.
%

category: 'Private'
method: ByteArray
at: index put: aNumber signed: aBool width: aWidthInBytes

"Store the big-endian represention of an aNumber into
 the specified position in the receiver.
 aWidthInBytes is allowed to be 1,2,3,4 or 8 if aNumber is
 an Integer .
 aWidthInBytes is allowed to be 4 , or 8 if aNumber is
 a BinaryFloat  , in which case the absolute value of aWidthInBytes
 specifies the width to be stored and aBool is ignored.
 If representation of an Integer requires more than aWidthInBytes ,
 the primitive will fail. 
 If coercion of a BinaryFloat to a 4 byte C float would produce
 loss of exponent bits, the primitive will fail.   
 If coercion of a BinaryFloat to a 4 byte C float would cause loss
 of precision that would convert a non-zero value to zero , 
 the primitive will fail .
 "

<primitive: 618>
self _primitiveFailed: #at:put:signed:width: .
%
category: 'Private'
method: ByteArray
at: index signed: aBool width: aWidthInBytes

"Retrieve a Number stored in  big-endian represention ,
 from the specified position and width in the receiver.
 aWidthInBytes of 1,2,3,4 or 8  retrieves an Integer.
 aWidthInBytes of -4 or -8 retrieves a SmallDouble or Float,
 and aBool is ignored.  "

<primitive: 619>
self _primitiveFailed: #at:signed:width: .
%

category: 'Private'
method: ByteArray
at: index sizeBytes: anInt stringSize: anIntOrNil
 "Read a string from the receiver into a new string and return the new
  string.  The offset to start writing the receiver is given by the
  at: argument. The sizeBytes argument specifies the width (in bytes) it takes to
  store the size of the string.  In this case, it is assumed the size
  of the string is stored in the first sizeBytes of the receiver. The
  stringSize: argument should be nil in this case, which means read the 
  string size from the byte array.  If the stringSize: argument is not nil,
  it means the size is not encoded in the string and the caller is
  passing in the string size.
  Returns the new string object created from reading"

<primitive: 623>
self _primitiveFailed: #at:sizeBytes:stringSize:.
%

category: 'Private-Accessing'
method: ByteArray
dateTime32At: startIndex

"retrieves a DateTime that was stored with seconds resolution 
 in big-endian byte order."

^ self dateTimeAt: startIndex width: 4 
%
category: 'Private-Accessing'
method: ByteArray
dateTime32NativeAt: startIndex

"retrieves a DateTime that was stored with seconds resolution
 in the gem process's native byte order.  
 Provided for compatiblity and renamed from dateTimeAsUnsigned32At: "

^ self dateTimeAt: startIndex width: -4 
%

category: 'Private-Accessing'
method: ByteArray
dateTime64At: startIndex

"retrieves a DateTime that was stored with millisecond resolution.
 in big-endian byte order"
 
^ self dateTimeAt: startIndex width: 8 
%

category: 'Private-Accessing'
method: ByteArray
dateTimeAt: startIndex width: anInt 

"values for anInt:
   -4   second resolution (4 bytes) in gem process native byte order
    4   second resolution (4 bytes) in big-endian byte order
    8   millisecond resolution (8 bytes) in big-endian byte order"

<primitive: 621>
self _primitiveFailed: #dateTimeAt:width: .
%

category: 'Private-Accessing'
method: ByteArray
shortStringAt: startIndex

^self at: startIndex sizeBytes:  1 stringSize: nil
%
category: 'Private-Accessing'
method: ByteArray
signed16At: startIndex

^self at: startIndex signed: true width: 2
%
category: 'Private-Accessing'
method: ByteArray
signed24At: startIndex

^self at: startIndex signed: true width: 3
%
category: 'Private-Accessing'
method: ByteArray
signed32At: startIndex

^self at: startIndex signed: true width: 4
%
category: 'Private-Accessing'
method: ByteArray
signed64At: startIndex

^self at: startIndex signed: true width: 8
%
category: 'Private-Accessing'
method: ByteArray
signed8At: startIndex

^self at: startIndex signed: true width: 1
%
category: 'Private-Accessing'
method: ByteArray
string4gAt: startIndex

^self at: startIndex sizeBytes: 4 stringSize: nil
%
category: 'Private-Accessing'
method: ByteArray
string64kAt: startIndex

^self at: startIndex sizeBytes: 2 stringSize: nil
%
category: 'Private-Accessing'
method: ByteArray
stringOfSize: anInt at: startIndex

^self at: startIndex sizeBytes:  0 stringSize: anInt
%
category: 'Private-Accessing'
method: ByteArray
unsigned16At: startIndex

^self at: startIndex signed: false width: 2
%
category: 'Private-Accessing'
method: ByteArray
unsigned24At: startIndex

^self at: startIndex signed: false width: 3
%
category: 'Private-Accessing'
method: ByteArray
unsigned32At: startIndex

^self at: startIndex signed: false width: 4
%
category: 'Private-Accessing'
method: ByteArray
unsigned64At: startIndex

^self at: startIndex signed: false width: 8
%
category: 'Private-Accessing'
method: ByteArray
unsigned8At: startIndex

^self at: startIndex signed: false width: 1
%
category: 'Private-Accessing'
method: ByteArray
floatAt: startIndex

"extract a 4 byte float from the receiver, the result will 
 be a SmallDouble."

^self at: startIndex signed: false width: -4
%
category: 'Private-Accessing'
method: ByteArray
doubleAt: startIndex

"extract an 8 byte float from the receiver, the result will 
 be either a SmallDouble or a Float. "

^self at: startIndex signed: false width: -8
%

category: 'Private-Accessing'
method: ByteArray
unsigned64At: startIndex

^self at: startIndex signed: false width: 8
%

category: 'Private-Updating'
method: ByteArray
dateTime32At: startIndex put: aDateTime

"Stores the DateTime with seconds resolution in big-endian byte order
 WARNING, this truncates the DateTime to seconds resolution, 
 throwing away the milliseconds.  
 "

^ self dateTimeAt: startIndex put: aDateTime width: 4
%

category: 'Private-Updating'
method: ByteArray
dateTime32NativeAt: startIndex put: aDateTime

"Stores the DateTime with seconds resolution and gem process native
 byte order.
 WARNING, this truncates the DateTime to seconds resolution,
 throwing away the milliseconds.  Provided for compatibility and
 renamed from dateTimeAsUnsigned32At:put:  "

^ self dateTimeAt: startIndex put: aDateTime width: -4
%


category: 'Private-Updating'
method: ByteArray
dateTime64At: startIndex put: aDateTime

"Stores the DateTime with full millisecond resolution in big-endian
 byte order."

^ self dateTimeAt: startIndex put: aDateTime width: 8
%

category: 'Private-Updating'
method: ByteArray
dateTimeAt: startIndex put: aDateTime width: anInt

"values for anInt:
   -4   second resolution (4 bytes) in gem process native byte order
    4   second resolution (4 bytes) in big-endian byte order
    8   millisecond resolution (8 bytes) in big-endian byte order"
<primitive: 620>
self _primitiveFailed: #dateTimeAt:put:width:
%

category: 'Private-Updating'
method: ByteArray
shortStringAt: startIndex put: aString fromOffset: stringOffset 
	^self at: startIndex put: aString fromOffset: stringOffset sizeBytes: 1
%
category: 'Private-Updating'
method: ByteArray
signed16At: startIndex put: anUnsignedInt

^self at: startIndex put: anUnsignedInt signed: true width: 2
%
category: 'Private-Updating'
method: ByteArray
signed24At: startIndex put: anUnsignedInt

^self at: startIndex put: anUnsignedInt signed: true width: 3
%
category: 'Private-Updating'
method: ByteArray
signed32At: startIndex put: anUnsignedInt

^self at: startIndex put: anUnsignedInt signed: true width: 4
%
category: 'Private-Updating'
method: ByteArray
signed64At: startIndex put: anUnsignedInt

^self at: startIndex put: anUnsignedInt signed: true width: 8
%
category: 'Private-Updating'
method: ByteArray
signed8At: startIndex put: anUnsignedInt

^self at: startIndex put: anUnsignedInt signed: true width: 1
%
category: 'Private-Updating'
method: ByteArray
string4gAt: startIndex put: aString fromOffset: stringOffset 
	^self at: startIndex put: aString fromOffset: stringOffset sizeBytes: 4
%
category: 'Private-Updating'
method: ByteArray
string64kAt: startIndex put: aString fromOffset: stringOffset 
	^self at: startIndex put: aString fromOffset: stringOffset sizeBytes: 2
%
category: 'Private-Updating'
method: ByteArray
stringAt: startIndex put: aString fromOffset: stringOffset 
	^self at: startIndex put: aString fromOffset: stringOffset sizeBytes: 0
%
category: 'Private-Updating'
method: ByteArray
unsigned16At: startIndex put: anUnsignedInt

^self at: startIndex put: anUnsignedInt signed: false width: 2
%
category: 'Private-Updating'
method: ByteArray
unsigned24At: startIndex put: anUnsignedInt

^self at: startIndex put: anUnsignedInt signed: false width: 3
%
category: 'Private-Updating'
method: ByteArray
unsigned32At: startIndex put: anUnsignedInt

^self at: startIndex put: anUnsignedInt signed: false width: 4
%
category: 'Private-Updating'
method: ByteArray
unsigned64At: startIndex put: anUnsignedInt

^self at: startIndex put: anUnsignedInt signed: false width: 8
%
category: 'Private-Updating'
method: ByteArray
doubleAt: startIndex put: aBinaryFloat

"aBinaryFloat must be a kind of BinaryFloat."

^self at: startIndex put: aBinaryFloat signed: false width: 8
%
category: 'Private-Updating'
method: ByteArray
floatAt: startIndex put: aBinaryFloat

"aBinaryFloat must be a kind of BinaryFloat, representable as
 a 4 byte IEEE float without loss of exponent bits. 
 If coercion of a BinaryFloat to a 4 byte float would produce
 loss of exponent bits, the primitive will fail.   
 If coercion of a BinaryFloat to a 4 byte float would cause loss
 of precision that would convert a non-zero value to zero , 
 the primitive will fail ."

^self at: startIndex put: aBinaryFloat signed: false width: 4
%

category: 'Private-Updating'
method: ByteArray
unsigned8At: startIndex put: anUnsignedInt

^self at: startIndex put: anUnsignedInt signed: false width: 1
%
! fixed 31356
category: 'Private-Updating'
method: ByteArray
_deleteNoShrinkFrom: startIndex to: endIndex anchorTailSize: aSize

"Deletes bytes from startIndex to endIndex by sliding bytes
 from endIndex+1 to aSize-1 to the left and filling with zeros.
 The bytes from  (self size - aSize) to (self size) are not altered. 
 The size of the receiver is not changed.  
 The size of the receiver must be <= 65536 ."

<primitive: 626>

(startIndex _isInteger)
  ifFalse: [ ^ self _errorNonIntegerIndex: startIndex].
(endIndex _isInteger)
  ifFalse: [ ^ self _errorNonIntegerIndex: endIndex].
(aSize _isInteger)
  ifFalse: [ ^ self _errorNonIntegerIndex: aSize].
self size > 65536 ifTrue:[ self error:'receiver size > 65536' ].
startIndex < 1 ifTrue:[ self _errorIndexOutOfRange:startIndex  ] .
(endIndex < startIndex _or:[ endIndex > self size] ) ifTrue:[ self _errorIndexOutOfRange: endIndex].
(aSize < 0 _or:[ endIndex > (self size - aSize)]) ifTrue:[ aSize _error: #rtErrArgOutOfRange ].
self _primitiveFailed: #_deleteNoShrinkFrom:to:anchorTailSize:.
%

! fixed 31356
category: 'Private-Updating'
method: ByteArray
_reverseDeleteNoShrinkFrom: startIndex to: endIndex anchorHeadSize: aSize

"Deletes bytes from startIndex to endIndex.  startIndex must be > aSize,
 and the bytes from 1 to aSize  are not altered.
 The bytes from aSize + 1 to startIndex - are shifted to the right by
 the distance (endIndex - startIndex + 1), and the bytes from (aSize + 1)
 to (endIndex - (startIndex - aSize) +1) are zeroed. 
 The size of the receiver is not changed.  
 The size of the receiver must be <= 65536 ."

<primitive: 627>

(startIndex _isInteger)
  ifFalse: [ ^ self _errorNonIntegerIndex: startIndex].
(endIndex _isInteger)
  ifFalse: [ ^ self _errorNonIntegerIndex: endIndex].
(aSize _isInteger)
  ifFalse: [ ^ self _errorNonIntegerIndex: aSize].
self size > 65536 ifTrue:[ self error:'receiver size > 65536' ].
startIndex < 1 ifTrue:[ self _errorIndexOutOfRange:startIndex  ] .
(endIndex < 1 _or:[ endIndex > self size]) ifTrue:[ self _errorIndexOutOfRange:endIndex ].
startIndex < aSize ifTrue:[ self error:'startIndex < aSize' ].
(self size - aSize) < endIndex ifTrue:[ aSize _error: #rtErrArgOutOfRange ].
self _primitiveFailed: #_reverseDeleteNoShrinkFrom:to:anchorHeadSize: .
%

category: 'Private-Comparing'
method: ByteArray
compareStringAt: startIndex to: aString startingAt: stringIndex sizeBytes: numSizeBytes useCase: aBool

"  Compare a string encoded in the receiver (aByteArray) to the given string
  starting at the offset specified in the given string.  If sizeBytes not
  zero, the byte array is assumed to have the size of the encoded string
  encoded in the first numSizeBytes bytes.  If sizeBytes is zero, the size 
  has not been encoded in the byteArray and the entire length of the second 
  string is compared.  numSizeBytes must be 0, 1, 2, 4, or 8.
  <aBool> determines if the comparision is case sensitive.
  Returns true if the strings match, false otherwise."
<primitive: 624>
self _primitiveFailed: #compareStringAt:to:startingAt:sizeBytes:useCase:.
%

category: 'Private-Comparing'
method: ByteArray
compareStringAt: startIndex to: aString startingAt: stringIndex sizeBytes: numSizeBytes

"  Compare a string encoded in the receiver (aByteArray) to the given string
  starting at the offset specified in the given string.  If sizeBytes not
  zero, the byte array is assumed to have the size of the encoded string
  encoded in the first numSizeBytes bytes.  If sizeBytes is zero, the size 
  has not been encoded in the byteArray and the entire length of the second 
  string is compared.  numSizeBytes must be 0, 1, 2, 4, or 8.
  Returns true if the strings match, false otherwise."
        ^self compareStringAt: startIndex to: aString startingAt: stringIndex sizeBytes: numSizeBytes useCase: true
%

category: 'Private-Comparing'
method: ByteArray
at: anIndex equals: aString

^self compareStringAt: anIndex to: aString startingAt: 1 sizeBytes: 0 useCase: true
   "size is not encoded, compare entire <aString>"
%

category: 'Private-Comparing'
method: ByteArray
at: anIndex equals: aString useCase: aBool

^self compareStringAt: anIndex to: aString startingAt: 1 sizeBytes: 0 useCase: aBool
   "size is not encoded, compare entire <aString>"
%

category: 'Private-Comparing'
method: ByteArray
compareShortStringAt: startIndex to: aString startingAt: stringIndex

^self compareStringAt: startIndex to: aString startingAt: stringIndex sizeBytes: 1 useCase: true
   "size is encoded in first byte of receiver"
%

category: 'Private-Comparing'
method: ByteArray
compareCaseInsensitiveShortStringAt: startIndex to: aString startingAt: stringIndex
"  Compare a string encoded in the receiver (aByteArray) to the given string
  starting at the offset specified in the given string.  The byte array is assumed
  to have the size of the encoded string encoded in the first 1 byte.
  Returns true if the strings are case insensitive match, false otherwise."

^self compareStringAt: startIndex to: aString startingAt: stringIndex sizeBytes: 1 useCase: false
    "size is encoded in first byte of receiver"
%

category: 'Private-Comparing'
method: ByteArray
compareShortStringAt: startIndex to: aString startingAt: stringIndex useCase: aBool

^self compareStringAt: startIndex to: aString startingAt: stringIndex sizeBytes: 1 useCase: aBool
   "size is encoded in first byte of receiver"
%

category: 'Private-Comparing'
method: ByteArray
shortStringAt: anIndex compareWith: aByteObject startingAt: stringOffset opCode: anOpCode
 "Compares, in order starting at anIndex, if the contents of the receiver
  are less than/greater than the contents of aByteObject, starting at stringOffset.
  The first byte of the receiver is assumed to be the size of the string 
  held in the receiver.  GemStone character precedence is adhered to.
  The argument string must be a small object.
op code == 0 means less than
op code == 1 means greater than"

<primitive: 625>
self _primitiveFailed: #shortStringAt:compareWith:startingAt:opCode:
%

category: 'Private-Comparing'
method: ByteArray
shortStringAt: anIndex greaterThan: aByteObject startingAt: stringOffset

 " Checks, in order starting at anIndex, if the contents of the receiver
  are greater than the contents of aByteObject, starting at stringOffset.
  The first byte of the receiver is assumed to be the size of the string 
  held in the receiver.  
 GemStone character precedence is adhered to.
  The argument string must be a small object."

^self shortStringAt: anIndex compareWith: aByteObject startingAt: stringOffset opCode: 1
%

category: 'Private-Comparing'
method: ByteArray
shortStringAt: anIndex lessThan: aByteObject startingAt: stringOffset

 " Checks, in order starting at anIndex, if the contents of the receiver
  are less than the contents of aByteObject, starting at stringOffset.
  The first byte of the receiver is assumed to be the size of the string 
  held in the receiver.  
 GemStone character precedence is adhered to.
  The argument string must be a small object."

^self shortStringAt: anIndex compareWith: aByteObject startingAt: stringOffset opCode: 0
%

category: 'Private-Comparing'
method: ByteArray
compareString4gAt: startIndex to: aString startingAt: stringIndex

^self compareStringAt: startIndex to: aString startingAt: stringIndex sizeBytes: 4
  "size is encoded in first byte of receiver"
%

category: 'Private-Comparing'
method: ByteArray
compareString64kAt: startIndex to: aString startingAt: stringIndex

^self compareStringAt: startIndex to: aString startingAt: stringIndex sizeBytes: 2
   "size is encoded in first byte of receiver"
%

category: 'Private-Updating'
method: ByteArray
deleteIndexKeyAt: anIndex

<primitive: 630>
self _primitiveFailed: #deleteIndexKeyAt: .
%

!################################################
! Start of new methods for GemStone 2G release
!################################################

category: 'Encoded OOPs'
method: ByteArray
at: aSmallInt putOopValueOfObject: anObject
"Store the 8 byte OOP of anObject in the receiver.  
 aSmallInt is an offset in the receiver where the bytes are to be stored.
 The receiver is grown if needed (use aSmallInt one past end to append)"
<primitive: 633>
aSmallInt _validateClass: SmallInteger .
aSmallInt < 1 ifTrue:[self _errorIndexOutOfRange: aSmallInt].
aSmallInt > (self size + 1) ifTrue:[self _errorIndexOutOfRange: aSmallInt].
self _primitiveFailed: #at:putOopValueOfObject:
%

category: 'Encoded OOPs'
method: ByteArray
at: aSmallInt putOldOopValueOfObject: anObject
"Store the 4 byte Gs64 v1.1 OOP of anObject in the receiver.  
 aSmallInt is an offset in the receiver where the bytes are to be stored.
 The receiver is grown if needed (use aSmallInt one past end to append)
 anObject cannot be a special object, and it's oopNumber must be < 2 billion."

<primitive: 634>
aSmallInt _validateClass: SmallInteger .
aSmallInt < 1 ifTrue:[self _errorIndexOutOfRange: aSmallInt].
aSmallInt > (self size + 1) ifTrue:[self _errorIndexOutOfRange: aSmallInt].
self _primitiveFailed: #at:putOldOopValueOfObject:
%

category: 'Encoded OOPs'
method: ByteArray
nextPutOopOfObject: anObject
"Extend the receiver by 8 bytes and add the 8 byte OOP of anObject."

^self at: self size + 1 putOopValueOfObject: anObject
%

category: 'Encoded OOPs'
method: ByteArray
nextPutOldOopOfObject: anObject
"Extend the receiver by 4 bytes and add the 4 byte OOP of anObject.
 anObject cannot be a special object, and it's oopNumber must be < 2 billion."

^self at: self size + 1 putOldOopValueOfObject: anObject
%

category: 'Encoded OOPs'
method: ByteArray
getObjectWithOopValueAt: anOffset
"Answer the object with the OOP stored in 8 bytes of the receiver 
 at the given offset.
 Returns nil if the object identifier
 encoded at anOffset does not exist or is an invalid object identifier."

<primitive: 635>
anOffset _validateClass: SmallInteger.
(anOffset < 1) ifTrue:[self _errorIndexOutOfRange: anOffset].
(anOffset > (self _basicSize - (self class bytesPerOop - 1)))
  ifTrue:[self _errorIndexOutOfRange: anOffset].
self _primitiveFailed: #getObjectWithOopValueAt:
%

category: 'Encoded OOPs'
method: ByteArray
getObjectWithOldOopValueAt: anOffset
"Answer the object with the OOP stored in 4 bytes of the receiver
 at the given offset.
 Returns nil if the object does not exist or is an invalid object identifier."
<primitive: 636>
anOffset _validateClass: SmallInteger.
(anOffset < 1) ifTrue:[self _errorIndexOutOfRange: anOffset].
(anOffset > (self _basicSize - (self class bytesPerOop - 1)))
  ifTrue:[self _errorIndexOutOfRange: anOffset].
self _primitiveFailed: #getObjectWithOldOopValueAt:
%


category: 'Encoded OOPs'
method: ByteArray
put: anInt objectsWithOopValueAt: anOffset into: anArray
"Extract a given number of objects from the OOPs stored in the receiver 
 starting at the given offset. Each OOP extracted occupies 8 bytes
 in the receiver. Store the objects into the specified Array object.  
 A nil is stored in the array for each object which does not exist.
 The specified Array is set to size 0 at the start of the operation."

1 to: anInt do:[:j | | obj |
  obj := self getObjectWithOopValueAt: j .
  anArray at: j put: obj .
  ].
anArray size: anInt .
^ self
%

category: 'Encoded OOPs'
method: ByteArray
put: anInt objectsWithOldOopValueAt: anOffset into: anArray
"Extract a given number of objects from the OOPs stored in the receiver 
 starting at the given offset. Each OOP extracted occupies 4 bytes
 in the receiver. Store the objects into the specified Array object.  
 A nil is stored in the array for each object which does not exist.
 The specified Array is set to size 0 at the start of the operation."

1 to: anInt do:[:j | | obj |
  obj := self getObjectWithOldOopValueAt: j .
  anArray at: j put: obj .
  ].
anArray size: anInt .
^ self
%

category: 'Encoded OOPs'
method: ByteArray
putObjectsWithOopValuesAtIndices: anArrayOfOffsets into: anArray
"For each offset stored in anArrayOfOffsets, extract the OOP from the 
 receiver stored at that offset.  Then store the object with that OOP in
 anArray.  A nil is stored in anArray for each object which does not exist.
 Each OOP extracted occupies 8 bytes in the receiver.
 The specified Array is set to size 0 at the start of the operation."

| limit |
limit := anArrayOfOffsets size .
1 to: limit do:[:j | | obj |
   obj := self getObjectWithOopValueAt: (anArrayOfOffsets at: j) .
   anArray at: j put: obj .
  ].
anArray size: limit .
^ self
%

category: 'Encoded OOPs'
method: ByteArray
putObjectsWithOldOopValuesAtIndices: anArrayOfOffsets into: anArray
"For each offset stored in anArrayOfOffsets, extract the OOP from the 
 receiver stored at that offset.  Then store the object with that OOP in
 anArray.  A nil is stored in anArray for each object which does not exist.
 Each OOP extracted occupies 4 bytes in the receiver.
 The specified Array is set to size 0 at the start of the operation."

| limit |
limit := anArrayOfOffsets size .
1 to: limit do:[:j | | obj |
   obj := self getObjectWithOldOopValueAt: (anArrayOfOffsets at: j) .
   anArray at: j put: obj .
  ].
anArray size: limit .
^ self
%

category: 'Encoded OOPs'
method: ByteArray
at: startIndex putAllOopsOfObjects: anArray
"Store the OOP of each object contained in anArray into 8 bytes of the receiver
 starting at startIndex.  The receiver is grown as necessary."
| idx | 
idx := startIndex .
1 to: anArray size do:[:j |
  self at: idx putOopValueOfObject: (anArray at: j ).
  idx := idx + 8 .
  ]. 
^ self
%

category: 'Encoded OOPs'
method: ByteArray
nextPutAllOopsOfObjects: anArray
"For each object in anArray, append the 8 byte OOP to the receiver.
 The receiver is grown by 8 bytes for every object contained in
 anArray."

^ self at: self size + 1 putAllOopsOfObjects: anArray
%

category: 'Encoded OOPs'
method: ByteArray
at: startIndex putAllOldOopsOfObjects: anArray
"Store the OOP of each object contained in anArray into 4 bytes of the receiver
 starting at startIndex.  The receiver is grown as necessary."
| idx | 
idx := startIndex .
1 to: anArray size do:[:j |
  self at: idx putOldOopValueOfObject: (anArray at: j ).
  idx := idx + 4 .
  ]. 
^ self
%

category: 'Encoded OOPs'
method: ByteArray
nextPutAllOldOopsOfObjects: anArray
"For each object in anArray, append the 4 byte OOP to the receiver.
 The receiver is grown by 4 bytes for every object contained in
 anArray."

^ self at: self size + 1 putAllOldOopsOfObjects: anArray
%

category: 'Encoded OOPs'
classmethod: ByteArray
bytesPerOop
"Number of bytes consumed by OopType in C."
^ 8
%
category: 'Encoded OOPs'
classmethod: ByteArray
oldBytesPerOop
"Number of bytes consumed by Gs64 v1.1 OopType in C."
^ 4
%

category: 'Compression'
method: ByteArray
_compressBytes
"Returns an instance of the class of the receiver with the
 body of the result being a compressed version of the body
 of the receiver. Only the raw compressed data is stored in
 the body of the result, so a crc check is expected to be
 performed externally."

<primitive: 647>
self _primitiveFailed: #_compressBytes .
%
category: 'Compression'
method: ByteArray
_decompressBytes
"Returns an instance of the class of the receiver with the
 body of the result being an uncompressed version of the body
 of the receiver. Only the raw compressed data is uncompressed,
 so a crc check is expected to be performed externalled"

<primitive: 648>
self _primitiveFailed: #_decompressBytes .
%
category: 'Compression'
method: ByteArray
_computeCRC32: crc
"Compute the crc32 value for the receiver, given the starting value.
 The crc32 value for a given receiver should be the same both before
 and after compression."

<primitive: 649>
self _primitiveFailed: #_computeCRC32: .
%

category: 'Encoding'
method: ByteArray
md5sum 
 
"Return the 128bit MD5 checksum of the receiver as a LargePositiveInteger.

 Computation is per RFC 1321 , http://www.ietf.org/rfc/rfc1321.txt,
 using L. Peter Deutsch's C implementation from
 http://sourceforge.net/projects/libmd5-rfc/"

<primitive: 666>
self _primitiveFailed: #md5sum 
%

