Additional Include: stddef.h
[platform/framework/web/wrt-commons.git] / modules / core / src / string.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file        string.cpp
18  * @author      Piotr Marcinkiewicz (p.marcinkiew@samsung.com)
19  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20  * @version     1.0
21  */
22 #include <stddef.h>
23 #include <dpl/string.h>
24 #include <dpl/char_traits.h>
25 #include <dpl/errno_string.h>
26 #include <dpl/exception.h>
27 #include <dpl/scoped_array.h>
28 #include <dpl/log/log.h>
29 #include <string>
30 #include <vector>
31 #include <algorithm>
32 #include <cstring>
33 #include <errno.h>
34 #include <iconv.h>
35 #include <unicode/ustring.h>
36
37 // TODO: Completely move to ICU
38 namespace DPL
39 {
40 namespace //anonymous
41 {
42 class ASCIIValidator
43 {
44     const std::string& m_TestedString;
45
46 public:
47     ASCIIValidator(const std::string& aTestedString);
48
49     void operator()(char aCharacter) const;
50 };
51
52 ASCIIValidator::ASCIIValidator(const std::string& aTestedString)
53     : m_TestedString(aTestedString)
54 {
55 }
56
57 void ASCIIValidator::operator()(char aCharacter) const
58 {
59     // Check for ASCII data range
60     if (aCharacter <= 0)
61     {
62         ThrowMsg(StringException::InvalidASCIICharacter,
63                  "invalid character code " << static_cast<int>(aCharacter)
64                  << " from string [" << m_TestedString
65                  << "] passed as ASCII");
66     }
67 }
68
69 const iconv_t gc_IconvOperError = reinterpret_cast<iconv_t>(-1);
70 const size_t gc_IconvConvertError = static_cast<size_t>(-1);
71 } // namespace anonymous
72
73 String FromUTF8String(const std::string& aIn)
74 {
75     if (aIn.empty())
76
77         return String();
78
79     size_t inbytes = aIn.size();
80
81     // Default iconv UTF-32 module adds BOM (4 bytes) in from of string
82     // The worst case is when 8bit UTF-8 char converts to 32bit UTF-32
83     // newsize = oldsize * 4 + end + bom
84     // newsize - bytes for UTF-32 string
85     // oldsize - letters in UTF-8 string
86     // end - end character for UTF-32 (\0)
87     // bom - Unicode header in front of string (0xfeff)
88     size_t outbytes = sizeof(wchar_t)*(inbytes + 2);
89     std::vector<wchar_t> output(inbytes + 2, 0);
90
91     size_t outbytesleft = outbytes;
92     char* inbuf = const_cast<char*>(aIn.c_str());
93
94     // vector is used to provide buffer for iconv which expects char* buffer
95     // but during conversion from UTF32 uses internaly wchar_t
96     char* outbuf = reinterpret_cast<char*>(&output[0]);
97
98     iconv_t iconvHandle = iconv_open("UTF-32","UTF-8");
99
100     if (gc_IconvOperError == iconvHandle)
101     {
102         int error = errno;
103
104         ThrowMsg(StringException::IconvInitErrorUTF8ToUTF32,
105                  "iconv_open failed for " << "UTF-32 <- UTF-8" <<
106                  "error: " << GetErrnoString(error));
107     }
108
109     size_t iconvRet = iconv(iconvHandle, &inbuf, &inbytes, &outbuf, &outbytesleft);
110
111     iconv_close(iconvHandle);
112
113     if (gc_IconvConvertError == iconvRet)
114     {
115         ThrowMsg(StringException::IconvConvertErrorUTF8ToUTF32,
116                  "iconv failed for " << "UTF-32 <- UTF-8" << "error: "
117                             << GetErrnoString());
118         return String();
119     }
120
121     // Ignore BOM in front of UTF-32
122     return &output[1];
123 }
124
125 std::string ToUTF8String(const DPL::String& aIn)
126 {
127     if (aIn.empty())
128
129         return std::string();
130
131     size_t inbytes = aIn.size() * sizeof(wchar_t);
132     size_t outbytes = inbytes + sizeof(char);
133
134     // wstring returns wchar_t but iconv expects char*
135     // iconv internally is processing input as wchar_t
136     char* inbuf =  reinterpret_cast<char*>(const_cast<wchar_t*>(aIn.c_str()));
137     std::vector<char> output(inbytes, 0);
138     char* outbuf = &output[0];
139
140     size_t outbytesleft = outbytes;
141
142     iconv_t iconvHandle = iconv_open("UTF-8","UTF-32");
143
144     if (gc_IconvOperError == iconvHandle)
145     {
146         ThrowMsg(StringException::IconvInitErrorUTF32ToUTF8,
147                  "iconv_open failed for " << "UTF-8 <- UTF-32"
148                             << "error: " << GetErrnoString());
149         return std::string();
150     }
151
152     size_t iconvRet = iconv(iconvHandle, &inbuf, &inbytes, &outbuf, &outbytesleft);
153
154     iconv_close(iconvHandle);
155
156     if (gc_IconvConvertError == iconvRet)
157     {
158         ThrowMsg(StringException::IconvConvertErrorUTF32ToUTF8,
159                  "iconv failed for " << "UTF-8 <- UTF-32"
160                             << "error: " << GetErrnoString());
161         return std::string();
162     }
163
164     return &output[0];
165 }
166
167 String FromASCIIString(const std::string& aString)
168 {
169     String output;
170
171     std::for_each(aString.begin(), aString.end(), ASCIIValidator(aString));
172     std::copy(aString.begin(), aString.end(), std::back_inserter<String>(output));
173
174     return output;
175 }
176
177 String FromUTF32String(const std::wstring& aString)
178 {
179     return String(&aString[0]);
180 }
181
182 static UChar *ConvertToICU(const String &inputString)
183 {
184     ScopedArray<UChar> outputString;
185     int32_t size = 0;
186     int32_t convertedSize = 0;
187     UErrorCode error = U_ZERO_ERROR;
188
189     // Calculate size of output string
190     ::u_strFromWCS(NULL,
191                    0,
192                    &size,
193                    inputString.c_str(),
194                    -1,
195                    &error);
196
197     if (error == U_ZERO_ERROR ||
198         error == U_BUFFER_OVERFLOW_ERROR)
199     {
200         // What buffer size is ok ?
201         LogPedantic("ICU: Output buffer size: " << size);
202     }
203     else
204     {
205         ThrowMsg(StringException::ICUInvalidCharacterFound,
206                  "ICU: Failed to retrieve output string size. Error: "
207                  << error);
208     }
209
210     // Allocate proper buffer
211     outputString.Reset(new UChar[size + 1]);
212     ::memset(outputString.Get(), 0, sizeof(UChar) * (size + 1));
213
214     error = U_ZERO_ERROR;
215
216     // Do conversion
217     ::u_strFromWCS(outputString.Get(),
218                    size + 1,
219                    &convertedSize,
220                    inputString.c_str(),
221                    -1,
222                    &error);
223
224     if (!U_SUCCESS(error))
225     {
226         ThrowMsg(StringException::ICUInvalidCharacterFound,
227                  "ICU: Failed to convert string. Error: " << error);
228     }
229
230     // Done
231     return outputString.Release();
232 }
233
234 int StringCompare(const String &left,
235                   const String &right,
236                   bool caseInsensitive)
237 {
238     // Convert input strings
239     ScopedArray<UChar> leftICU(ConvertToICU(left));
240     ScopedArray<UChar> rightICU(ConvertToICU(right));
241
242     if (caseInsensitive)
243     {
244         return static_cast<int>(u_strcasecmp(leftICU.Get(), rightICU.Get(), 0));
245     }
246     else
247     {
248         return static_cast<int>(u_strcmp(leftICU.Get(), rightICU.Get()));
249     }
250 }
251 } //namespace DPL
252
253 std::ostream& operator<<(std::ostream& aStream, const DPL::String& aString)
254 {
255     return aStream << DPL::ToUTF8String(aString);
256 }