michael@0: /* michael@0: ********************************************************************** michael@0: * Copyright (C) 2001-2011, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: ********************************************************************** michael@0: * FILE NAME : ustream.cpp michael@0: * michael@0: * Modification History: michael@0: * michael@0: * Date Name Description michael@0: * 06/25/2001 grhoten Move iostream from unistr.h to here michael@0: ****************************************************************************** michael@0: */ michael@0: michael@0: #include "unicode/utypes.h" michael@0: #include "unicode/uobject.h" michael@0: #include "unicode/ustream.h" michael@0: #include "unicode/ucnv.h" michael@0: #include "unicode/uchar.h" michael@0: #include "unicode/utf16.h" michael@0: #include "ustr_cnv.h" michael@0: #include "cmemory.h" michael@0: #include michael@0: michael@0: // console IO michael@0: michael@0: #if U_IOSTREAM_SOURCE >= 199711 michael@0: michael@0: #define STD_NAMESPACE std:: michael@0: michael@0: #define STD_OSTREAM STD_NAMESPACE ostream michael@0: #define STD_ISTREAM STD_NAMESPACE istream michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: U_IO_API STD_OSTREAM & U_EXPORT2 michael@0: operator<<(STD_OSTREAM& stream, const UnicodeString& str) michael@0: { michael@0: if(str.length() > 0) { michael@0: char buffer[200]; michael@0: UConverter *converter; michael@0: UErrorCode errorCode = U_ZERO_ERROR; michael@0: michael@0: // use the default converter to convert chunks of text michael@0: converter = u_getDefaultConverter(&errorCode); michael@0: if(U_SUCCESS(errorCode)) { michael@0: const UChar *us = str.getBuffer(); michael@0: const UChar *uLimit = us + str.length(); michael@0: char *s, *sLimit = buffer + (sizeof(buffer) - 1); michael@0: do { michael@0: errorCode = U_ZERO_ERROR; michael@0: s = buffer; michael@0: ucnv_fromUnicode(converter, &s, sLimit, &us, uLimit, 0, FALSE, &errorCode); michael@0: *s = 0; michael@0: michael@0: // write this chunk michael@0: if(s > buffer) { michael@0: stream << buffer; michael@0: } michael@0: } while(errorCode == U_BUFFER_OVERFLOW_ERROR); michael@0: u_releaseDefaultConverter(converter); michael@0: } michael@0: } michael@0: michael@0: /* stream.flush();*/ michael@0: return stream; michael@0: } michael@0: michael@0: U_IO_API STD_ISTREAM & U_EXPORT2 michael@0: operator>>(STD_ISTREAM& stream, UnicodeString& str) michael@0: { michael@0: // This is like ICU status checking. michael@0: if (stream.fail()) { michael@0: return stream; michael@0: } michael@0: michael@0: /* ipfx should eat whitespace when ios::skipws is set */ michael@0: UChar uBuffer[16]; michael@0: char buffer[16]; michael@0: int32_t idx = 0; michael@0: UConverter *converter; michael@0: UErrorCode errorCode = U_ZERO_ERROR; michael@0: michael@0: // use the default converter to convert chunks of text michael@0: converter = u_getDefaultConverter(&errorCode); michael@0: if(U_SUCCESS(errorCode)) { michael@0: UChar *us = uBuffer; michael@0: const UChar *uLimit = uBuffer + sizeof(uBuffer)/sizeof(*uBuffer); michael@0: const char *s, *sLimit; michael@0: char ch; michael@0: UChar ch32; michael@0: UBool initialWhitespace = TRUE; michael@0: UBool continueReading = TRUE; michael@0: michael@0: /* We need to consume one byte at a time to see what is considered whitespace. */ michael@0: while (continueReading) { michael@0: ch = stream.get(); michael@0: if (stream.eof()) { michael@0: // The EOF is only set after the get() of an unavailable byte. michael@0: if (!initialWhitespace) { michael@0: stream.clear(stream.eofbit); michael@0: } michael@0: continueReading = FALSE; michael@0: } michael@0: sLimit = &ch + (int)continueReading; michael@0: us = uBuffer; michael@0: s = &ch; michael@0: errorCode = U_ZERO_ERROR; michael@0: /* michael@0: Since we aren't guaranteed to see the state before this call, michael@0: this code won't work on stateful encodings like ISO-2022 or an EBCDIC stateful encoding. michael@0: We flush on the last byte to ensure that we output truncated multibyte characters. michael@0: */ michael@0: ucnv_toUnicode(converter, &us, uLimit, &s, sLimit, 0, !continueReading, &errorCode); michael@0: if(U_FAILURE(errorCode)) { michael@0: /* Something really bad happened. setstate() isn't always an available API */ michael@0: stream.clear(stream.failbit); michael@0: goto STOP_READING; michael@0: } michael@0: /* Was the character consumed? */ michael@0: if (us != uBuffer) { michael@0: /* Reminder: ibm-1390 & JISX0213 can output 2 Unicode code points */ michael@0: int32_t uBuffSize = us-uBuffer; michael@0: int32_t uBuffIdx = 0; michael@0: while (uBuffIdx < uBuffSize) { michael@0: U16_NEXT(uBuffer, uBuffIdx, uBuffSize, ch32); michael@0: if (u_isWhitespace(ch32)) { michael@0: if (!initialWhitespace) { michael@0: buffer[idx++] = ch; michael@0: while (idx > 0) { michael@0: stream.putback(buffer[--idx]); michael@0: } michael@0: goto STOP_READING; michael@0: } michael@0: /* else skip intialWhitespace */ michael@0: } michael@0: else { michael@0: if (initialWhitespace) { michael@0: /* michael@0: When initialWhitespace is TRUE, we haven't appended any michael@0: character yet. This is where we truncate the string, michael@0: to avoid modifying the string before we know if we can michael@0: actually read from the stream. michael@0: */ michael@0: str.truncate(0); michael@0: initialWhitespace = FALSE; michael@0: } michael@0: str.append(ch32); michael@0: } michael@0: } michael@0: idx = 0; michael@0: } michael@0: else { michael@0: buffer[idx++] = ch; michael@0: } michael@0: } michael@0: STOP_READING: michael@0: u_releaseDefaultConverter(converter); michael@0: } michael@0: michael@0: /* stream.flush();*/ michael@0: return stream; michael@0: } michael@0: michael@0: U_NAMESPACE_END michael@0: michael@0: #endif