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