Fix byte ordering.
authorStefan Vogel <sv@exept.de>
Mon, 20 Feb 2006 17:21:19 +0100
changeset 1602 6ffbb8db78a4
parent 1601 b0dfbe332caf
child 1603 a2a4ce010ef3
Fix byte ordering. Store fields in network byte order internally.
UUID.st
--- a/UUID.st	Mon Feb 20 13:53:54 2006 +0100
+++ b/UUID.st	Mon Feb 20 17:21:19 2006 +0100
@@ -40,8 +40,16 @@
     128-bit Universal Unique Ids (UUIDs) as defined by OpenGroup/DCE
         http://www.opengroup.org/onlinepubs/9629399/apdxa.htm.
 
+    See also RFC4122.
+
     A UUID is unique in time and space (at least until about Year 3400).
 
+    Several fields if the UUID are interpreted as integers, so host/network byte
+    order is relevant. UUIDs are stored in a ByteArray in network byte order (MSB-first),
+    so they may be exported/imported between different machines.
+
+    You can import UUIDs in host byte order using #fromNativeBytes:
+
     [author:]
 
     [instance variables:]
@@ -78,24 +86,33 @@
 !UUID class methodsFor:'instance creation'!
 
 fromBytes:aByteArray
-    ^ self fromBytes:aByteArray msb:(UninterpretedBytes isBigEndian)
-!
+    "set uuid from aByteArray.
+     aByteArray must be 16 bytes in network byte order (MSB-first)"
 
-fromBytes:aByteArray msb:msb
-    |uuid d1 d2 d3|
+    |uuid|
 
     uuid := self new.
     uuid replaceFrom:1 to:16 with:aByteArray.
+    ^ uuid.
 
-    msb ifTrue:[
-        d1 := aByteArray unsignedLongAt:1 bigEndian:msb.
-        uuid unsignedLongAt:1 put:d1 bigEndian:false.
+    "    
+     UUID fromBytes:#[16r01 16r02 16r03 16r04
+                      16r05 16r06 16r07 16r08
+                      16r09 16r10 16r11 16r12
+                      16r13 16r14 16r15 16r16]. 
+    "
+!
 
-        d2 := aByteArray unsignedShortAt:1+4 bigEndian:msb.
-        uuid unsignedShortAt:1+4 put:d2 bigEndian:false.
+fromBytes:aByteArray msb:msb
+    "Set the UUID from aByteArray. UUIDS are stored internally as MSB-first. 
+     So, alway set
+        msb = true      if reading from network or persistent storage"
 
-        d3 := aByteArray unsignedShortAt:1+4+2 bigEndian:msb.
-        uuid unsignedShortAt:1+4+2 put:d3 bigEndian:false.
+    |uuid|
+
+    uuid := self fromBytes:aByteArray.
+    msb ifFalse:[
+        self adjustByteOrder:uuid.
     ].
 
     ^ uuid
@@ -114,6 +131,28 @@
     "
 !
 
+fromNativeBytes:aByteArray
+    "convert bytes to uuid.
+     aByteArray represents a UUID in host byte order 
+     - e.g. an UUID fetched from the Windows OS"
+
+    |uuid|
+
+    uuid := self fromBytes:aByteArray.
+    self isBigEndian ifFalse:[
+        self adjustByteOrder:uuid.
+    ].
+    ^ uuid.
+
+    "    
+     UUID fromNativeBytes:#[16r01 16r02 16r03 16r04
+                              16r05 16r06 16r07 16r08
+                              16r09 16r10 16r11 16r12
+                              16r13 16r14 16r15 16r16]. 
+
+    "
+!
+
 genUUID
     "generate a new UUID"
 
@@ -144,7 +183,6 @@
     ] do:[
         s := aStringOrStream readStream.
         uuid := self new.
-        offs := 1.
 
         s skipSeparators.
         s peek == ${ ifTrue:[s next].
@@ -152,24 +190,26 @@
 
         t := s next:8.
         d := Integer readFrom:t radix:16 onError:[^ errorBlock value].
-        uuid unsignedLongAt:1 put:d bigEndian:false.
-        offs := offs + 4.
+        uuid unsignedLongAt:1 put:d bigEndian:true.
+        offs := 5.
 
-        s next.
+        s next.         "skip $-"
 
         1 to:2 do:[:i |
             t := s next:4.
             d := Integer readFrom:t radix:16 onError:[^ errorBlock value].
-            uuid unsignedShortAt:offs put:d bigEndian:false.
+            uuid unsignedShortAt:offs put:d bigEndian:true.
             offs := offs + 2.
-            s next.
+            s next.     "skip $-"
         ].
 
-        t := s next:4.
-        d := Integer readFrom:t radix:16 onError:[^ errorBlock value].
-        uuid unsignedShortAt:offs put:d bigEndian:true.
-        offs := offs + 2.
-        s next.
+        1 to:2 do:[:i |
+            t := s next:2.
+            d := Integer readFrom:t radix:16 onError:[^ errorBlock value].
+            uuid at:offs put:d.
+            offs := offs + 1.
+        ].
+        s next.         "skip $-"
 
         1 to:6 do:[:i |
             t := s next:2.
@@ -196,6 +236,21 @@
 
 !UUID class methodsFor:'helpers'!
 
+adjustByteOrder:aByteArray
+    "change the byte order of the uuid"
+
+    |d|
+
+    d := aByteArray unsignedLongAt:1 bigEndian:false.
+    aByteArray unsignedLongAt:1 put:d bigEndian:true.
+
+    d := aByteArray unsignedShortAt:1+4 bigEndian:false.
+    aByteArray unsignedShortAt:1+4 put:d bigEndian:true.
+
+    d := aByteArray unsignedShortAt:1+4+2 bigEndian:false.
+    aByteArray unsignedShortAt:1+4+2 put:d bigEndian:true.
+!
+
 getDtssUtcTime
     "return the DTSS based time in 100 nsec intervals
      DTSS UTC base time is October 15, 1582.
@@ -238,53 +293,77 @@
 
 !UUID methodsFor:'accessing'!
 
-clockSeqAndReserved
+clockSeqHiAndReserved
+    ^ self at:9
+!
 
-    ^ self unsignedShortAt:9 bigEndian:false
+clockSeqLow
+    ^ self at:10
 !
 
 node
-
-    ^ self copyFrom:10 to:16
+    ^ self copyFrom:11 to:16
 !
 
 timeHighAndVersion
-
-    ^ self unsignedShortAt:7 bigEndian:false
+    ^ self unsignedShortAt:7 bigEndian:true
 !
 
 timeLow
-
-    ^ self unsignedLongAt:1 bigEndian:false
+    ^ self unsignedLongAt:1 bigEndian:true
 !
 
 timeMid
-
-    ^ self unsignedShortAt:5 bigEndian:false
+    ^ self unsignedShortAt:5 bigEndian:true
 ! !
 
 !UUID methodsFor:'converting'!
 
 asBytes
-    ^ self asBytesMSB:(UninterpretedBytes isBigEndian)
-!
+    "convert this UUID to a ByteArray in network byte order (MSB-first)"
 
-asBytesMSB:msb
-    |bytes d1 d2 d3|
+    |bytes|
 
     bytes := ByteArray new:16.
     bytes replaceFrom:1 to:16 with:self.
+    ^ bytes
 
-    msb ifTrue:[
-        d1 := self unsignedLongAt:1 bigEndian:false.
-        d2 := self unsignedShortAt:1+4 bigEndian:false.
-        d3 := self unsignedShortAt:1+4+2 bigEndian:false.
+    "
+     |bytes|
+        
+     bytes := #[16r01 16r02 16r03 16r04
+                      16r05 16r06 16r07 16r08
+                      16r09 16r10 16r11 16r12
+                      16r13 16r14 16r15 16r16].
+     (UUID fromBytes:bytes) asBytes ~= bytes ifTrue:[self halt] 
+    "
+!
 
-        bytes unsignedLongAt:1 put:d1 bigEndian:true.
-        bytes unsignedShortAt:1+4 put:d2 bigEndian:true.
-        bytes unsignedShortAt:1+4+2 put:d3 bigEndian:true.
+asBytesMSB:msb
+    "convert this UUID to a ByteArray.
+     If msb == false, it is converted into LSB-first byte oredering"
+
+    |bytes|
+
+    bytes := self asBytes.
+
+    msb ifFalse:[
+        self class adjustByteOrder:bytes.
     ].
     ^ bytes
+!
+
+asNativeBytes
+    "convert this uuid to a ByteArray in host byte order.
+     Use this only to pass the UUID to the OS (Windows)"
+
+    |bytes|
+
+    bytes := self asBytes.
+    self class isBigEndian ifFalse:[
+        self class adjustByteOrder:bytes.
+    ].
+    ^ bytes.
 ! !
 
 !UUID methodsFor:'generating uuids'!
@@ -350,30 +429,22 @@
 !
 
 printOn:aStream
-    |offs d tmpStream|
+    |d tmpStream|
 
     tmpStream := '' writeStream.
 
-    d := self unsignedLongAt:1 bigEndian:false.
-    d printOn:tmpStream base:16 size:8 fill:$0.
-
+    self timeLow printOn:tmpStream base:16 size:8 fill:$0.
+    tmpStream nextPut:$-.
+    self timeMid printOn:tmpStream base:16 size:4 fill:$0.
+    tmpStream nextPut:$-.
+    self timeHighAndVersion printOn:tmpStream base:16 size:4 fill:$0.
+    tmpStream nextPut:$-.
+    self clockSeqHiAndReserved printOn:tmpStream base:16 size:2 fill:$0.
+    self clockSeqLow printOn:tmpStream base:16 size:2 fill:$0.
     tmpStream nextPut:$-.
 
-    offs := 5.
-    2 timesRepeat:[
-        d := self unsignedShortAt:offs bigEndian:false.
-        offs := offs + 2.
-        d printOn:tmpStream base:16 size:4 fill:$0.
-        tmpStream nextPut:$-.
-    ].
-    d := self unsignedShortAt:offs bigEndian:true.
-    offs := offs + 2.
-    d printOn:tmpStream base:16 size:4 fill:$0.
-    tmpStream nextPut:$-.
-
-    6 timesRepeat:[
-        d := self at:offs.
-        offs := offs + 1.
+    11 to:16 do:[:idx|
+        d := self at:idx.
         d printOn:tmpStream base:16 size:2 fill:$0.
     ].
 
@@ -383,7 +454,7 @@
 !UUID class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic2/UUID.st,v 1.15 2006-02-20 12:53:54 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/UUID.st,v 1.16 2006-02-20 16:21:19 stefan Exp $'
 ! !
 
 UUID initialize!