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