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