class: ExternalStream
authorStefan Vogel <sv@exept.de>
Tue, 20 Aug 2013 15:46:15 +0200
changeset 15655 a044910b6f38
parent 15654 e4bfb1d6b3df
child 15656 82aca5063e96
class: ExternalStream added: #nextPutUtf16: changed: #nextPutShort:MSB:
ExternalStream.st
--- a/ExternalStream.st	Tue Aug 20 15:46:05 2013 +0200
+++ b/ExternalStream.st	Tue Aug 20 15:46:15 2013 +0200
@@ -4197,8 +4197,8 @@
     self argumentMustBeInteger
 !
 
-nextPutShort:aNumber MSB:msbFlag
-    "Write the argument, aNumber as a short (two bytes). If msbFlag is
+nextPutShort:anIntegerOrCharacter MSB:msbFlag
+    "Write the argument, anIntegerOrCharacter as a short (two bytes). If msbFlag is
      true, data is written most-significant byte first; otherwise least
      first.
      Works in both binary and text modes."
@@ -4206,8 +4206,8 @@
 %{
     int num;
     union {
-	char bytes[2];
-	short shortVal;
+        char bytes[2];
+        short shortVal;
     } u;
 
     FILEPOINTER f;
@@ -4219,48 +4219,54 @@
      || (__INST(handleType) == @symbol(filePointer))
      || (__INST(handleType) == @symbol(socketFilePointer))
      || (__INST(handleType) == @symbol(pipeFilePointer))) {
-	if (((fp = __INST(handle)) != nil)
-	    && (__INST(mode) != @symbol(readonly))
-	    && __isSmallInteger(aNumber)
-	) {
-	    num = __intVal(aNumber);
-	    if (msbFlag == true) {
+        if (((fp = __INST(handle)) != nil)
+            && (__INST(mode) != @symbol(readonly))
+        ) {
+            if (__isSmallInteger(anIntegerOrCharacter)) {
+                num = __intVal(anIntegerOrCharacter);
+            } else if (__isCharacter(anIntegerOrCharacter)) {
+                num = __smallIntegerVal(__characterVal(anIntegerOrCharacter));
+            } else
+                goto out;
+
+            if (msbFlag == true) {
 #if defined(__MSBFIRST__)
-		u.shortVal = num;
+                u.shortVal = num;
 #else
-		u.bytes[0] = (num >> 8) & 0xFF;
-		u.bytes[1] = num & 0xFF;
+                u.bytes[0] = (num >> 8) & 0xFF;
+                u.bytes[1] = num & 0xFF;
 #endif
-	    } else {
+            } else {
 #if defined(__LSBFIRST__)
-		u.shortVal = num;
+                u.shortVal = num;
 #else
-		u.bytes[1] = (num >> 8) & 0xFF;
-		u.bytes[0] = num & 0xFF;
+                u.bytes[1] = (num >> 8) & 0xFF;
+                u.bytes[0] = num & 0xFF;
 #endif
-	    }
-
-	    f = __FILEVal(fp);
-	    if (_buffered = (__INST(buffered) == true)) {
-		__WRITING__(f)
-	    }
-	    __WRITEBYTES__(cnt, f, u.bytes, 2, _buffered, __INST(handleType));
-
-	    if (cnt == 2) {
-		if (__isSmallInteger(__INST(position))) {
-		    INT np = __intVal(__INST(position)) + 2;
-		    OBJ t;
-
-		    t = __MKINT(np); __INST(position) = t; __STORE(self, t);
-		} else {
-		    __INST(position) = nil; /* i.e. do not know */
-		}
-		RETURN ( self );
-	    }
-	    __INST(position) = nil; /* i.e. do not know */
-	    __INST(lastErrorNumber) = __mkSmallInteger(__threadErrno);
-	}
+            }
+
+            f = __FILEVal(fp);
+            if (_buffered = (__INST(buffered) == true)) {
+                __WRITING__(f)
+            }
+            __WRITEBYTES__(cnt, f, u.bytes, 2, _buffered, __INST(handleType));
+
+            if (cnt == 2) {
+                if (__isSmallInteger(__INST(position))) {
+                    INT np = __intVal(__INST(position)) + 2;
+                    OBJ t;
+
+                    t = __MKINT(np); __INST(position) = t; __STORE(self, t);
+                } else {
+                    __INST(position) = nil; /* i.e. do not know */
+                }
+                RETURN ( self );
+            }
+            __INST(position) = nil; /* i.e. do not know */
+            __INST(lastErrorNumber) = __mkSmallInteger(__threadErrno);
+        }
     }
+out:;
 %}.
     lastErrorNumber notNil ifTrue:[self writeError. ^ self.].
     handle isNil ifTrue:[self errorNotOpen. ^ self].
@@ -5747,11 +5753,11 @@
      This is needed, so that you can do ('something' asUnicode16String errorPrintCR)"
 
     aString do:[:eachCharacter|
-	self nextPutUtf8:eachCharacter.
+        self nextPutUtf8:eachCharacter.
     ].
 
     "
-	'Bönnigheim' asUnicode16String errorPrintCR
+        'Bönnigheim' asUnicode16String errorPrintCR
     "
 !
 
@@ -5759,16 +5765,49 @@
     "normal streams can not handle multi-byte characters, so convert them to utf8"
 
     self nextPutUtf8:aCharacter.
+!
+
+nextPutUtf16:aCharacter
+    "append my UTF-16 representation to the argument, aStream.
+     UTF-16 can encode only characters with code points between 0 to 16r10FFFF."
+
+    |codePoint|
+
+    codePoint := aCharacter codePoint.
+    (codePoint <= 16rD7FF
+      or:[codePoint >= 16rE000 and:[codePoint <= 16rFFFF]]) ifTrue:[
+        self nextPutShort:codePoint MSB:true.
+    ] ifFalse:[codePoint <= 16r10FFFF ifTrue:[
+        |highBits lowBits|
+
+        codePoint := codePoint - 16r100000.
+        highBits := codePoint bitShift:-10.
+        lowBits := codePoint bitAnd:16r3FF.
+        self nextPutShort:highBits+16rD800 MSB:true.
+        self nextPutShort:lowBits+16rDC00 MSB:true.
+    ] ifFalse:[
+        EncodingError raiseWith:aCharacter errorString:'Character cannot be encoded as UTF-16'.
+    ]].
+
+    "
+        (FileStream newTemporary
+            nextPutUtf16:$B;
+            nextPutUtf16:$Ä; 
+            nextPutUtf16:(Character codePoint:16r10CCCC);
+            reset;
+            binary;
+            contents)
+    "
 ! !
 
 !ExternalStream class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/ExternalStream.st,v 1.372 2013-08-10 11:31:57 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/ExternalStream.st,v 1.373 2013-08-20 13:46:15 stefan Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/ExternalStream.st,v 1.372 2013-08-10 11:31:57 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/ExternalStream.st,v 1.373 2013-08-20 13:46:15 stefan Exp $'
 ! !