1 /* 2 ********************************************************************** 3 * Copyright (C) 2001-2011, International Business Machines 4 * Corporation and others. All Rights Reserved. 5 ********************************************************************** 6 * FILE NAME : ustream.cpp 7 * 8 * Modification History: 9 * 10 * Date Name Description 11 * 06/25/2001 grhoten Move iostream from unistr.h to here 12 ****************************************************************************** 13 */ 14 15 #include "unicode/utypes.h" 16 #include "unicode/uobject.h" 17 #include "unicode/ustream.h" 18 #include "unicode/ucnv.h" 19 #include "unicode/uchar.h" 20 #include "unicode/utf16.h" 21 #include "ustr_cnv.h" 22 #include "cmemory.h" 23 #include <string.h> 24 25 // console IO 26 27 #if U_IOSTREAM_SOURCE >= 199711 28 29 #define STD_NAMESPACE std:: 30 31 #define STD_OSTREAM STD_NAMESPACE ostream 32 #define STD_ISTREAM STD_NAMESPACE istream 33 34 U_NAMESPACE_BEGIN 35 36 U_IO_API STD_OSTREAM & U_EXPORT2 37 operator<<(STD_OSTREAM& stream, const UnicodeString& str) 38 { 39 if(str.length() > 0) { 40 char buffer[200]; 41 UConverter *converter; 42 UErrorCode errorCode = U_ZERO_ERROR; 43 44 // use the default converter to convert chunks of text 45 converter = u_getDefaultConverter(&errorCode); 46 if(U_SUCCESS(errorCode)) { 47 const UChar *us = str.getBuffer(); 48 const UChar *uLimit = us + str.length(); 49 char *s, *sLimit = buffer + (sizeof(buffer) - 1); 50 do { 51 errorCode = U_ZERO_ERROR; 52 s = buffer; 53 ucnv_fromUnicode(converter, &s, sLimit, &us, uLimit, 0, FALSE, &errorCode); 54 *s = 0; 55 56 // write this chunk 57 if(s > buffer) { 58 stream << buffer; 59 } 60 } while(errorCode == U_BUFFER_OVERFLOW_ERROR); 61 u_releaseDefaultConverter(converter); 62 } 63 } 64 65 /* stream.flush();*/ 66 return stream; 67 } 68 69 U_IO_API STD_ISTREAM & U_EXPORT2 70 operator>>(STD_ISTREAM& stream, UnicodeString& str) 71 { 72 // This is like ICU status checking. 73 if (stream.fail()) { 74 return stream; 75 } 76 77 /* ipfx should eat whitespace when ios::skipws is set */ 78 UChar uBuffer[16]; 79 char buffer[16]; 80 int32_t idx = 0; 81 UConverter *converter; 82 UErrorCode errorCode = U_ZERO_ERROR; 83 84 // use the default converter to convert chunks of text 85 converter = u_getDefaultConverter(&errorCode); 86 if(U_SUCCESS(errorCode)) { 87 UChar *us = uBuffer; 88 const UChar *uLimit = uBuffer + sizeof(uBuffer)/sizeof(*uBuffer); 89 const char *s, *sLimit; 90 char ch; 91 UChar ch32; 92 UBool initialWhitespace = TRUE; 93 UBool continueReading = TRUE; 94 95 /* We need to consume one byte at a time to see what is considered whitespace. */ 96 while (continueReading) { 97 ch = stream.get(); 98 if (stream.eof()) { 99 // The EOF is only set after the get() of an unavailable byte. 100 if (!initialWhitespace) { 101 stream.clear(stream.eofbit); 102 } 103 continueReading = FALSE; 104 } 105 sLimit = &ch + (int)continueReading; 106 us = uBuffer; 107 s = &ch; 108 errorCode = U_ZERO_ERROR; 109 /* 110 Since we aren't guaranteed to see the state before this call, 111 this code won't work on stateful encodings like ISO-2022 or an EBCDIC stateful encoding. 112 We flush on the last byte to ensure that we output truncated multibyte characters. 113 */ 114 ucnv_toUnicode(converter, &us, uLimit, &s, sLimit, 0, !continueReading, &errorCode); 115 if(U_FAILURE(errorCode)) { 116 /* Something really bad happened. setstate() isn't always an available API */ 117 stream.clear(stream.failbit); 118 goto STOP_READING; 119 } 120 /* Was the character consumed? */ 121 if (us != uBuffer) { 122 /* Reminder: ibm-1390 & JISX0213 can output 2 Unicode code points */ 123 int32_t uBuffSize = us-uBuffer; 124 int32_t uBuffIdx = 0; 125 while (uBuffIdx < uBuffSize) { 126 U16_NEXT(uBuffer, uBuffIdx, uBuffSize, ch32); 127 if (u_isWhitespace(ch32)) { 128 if (!initialWhitespace) { 129 buffer[idx++] = ch; 130 while (idx > 0) { 131 stream.putback(buffer[--idx]); 132 } 133 goto STOP_READING; 134 } 135 /* else skip intialWhitespace */ 136 } 137 else { 138 if (initialWhitespace) { 139 /* 140 When initialWhitespace is TRUE, we haven't appended any 141 character yet. This is where we truncate the string, 142 to avoid modifying the string before we know if we can 143 actually read from the stream. 144 */ 145 str.truncate(0); 146 initialWhitespace = FALSE; 147 } 148 str.append(ch32); 149 } 150 } 151 idx = 0; 152 } 153 else { 154 buffer[idx++] = ch; 155 } 156 } 157 STOP_READING: 158 u_releaseDefaultConverter(converter); 159 } 160 161 /* stream.flush();*/ 162 return stream; 163 } 164 165 U_NAMESPACE_END 166 167 #endif 168