Update User Agent String
[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 <dpl/string.h>
23 #include <dpl/char_traits.h>
24 #include <dpl/errno_string.h>
25 #include <dpl/exception.h>
26 #include <dpl/scoped_array.h>
27 #include <dpl/log/log.h>
28 #include <string>
29 #include <vector>
30 #include <algorithm>
31 #include <cstring>
32 #include <errno.h>
33 #include <iconv.h>
34 #include <unicode/ustring.h>
35
36 // TODO: Completely move to ICU
37 namespace DPL
38 {
39 namespace //anonymous
40 {
41 class ASCIIValidator
42 {
43     const std::string& m_TestedString;
44
45 public:
46     ASCIIValidator(const std::string& aTestedString);
47
48     void operator()(char aCharacter) const;
49 };
50
51 ASCIIValidator::ASCIIValidator(const std::string& aTestedString)
52     : m_TestedString(aTestedString)
53 {
54 }
55
56 void ASCIIValidator::operator()(char aCharacter) const
57 {
58     // Check for ASCII data range
59     if (aCharacter <= 0)
60     {
61         ThrowMsg(StringException::InvalidASCIICharacter,
62                  "invalid character code " << static_cast<int>(aCharacter)
63                  << " from string [" << m_TestedString
64                  << "] passed as ASCII");
65     }
66 }
67
68 const iconv_t gc_IconvOperError = reinterpret_cast<iconv_t>(-1);
69 const size_t gc_IconvConvertError = static_cast<size_t>(-1);
70 } // namespace anonymous
71
72 String FromUTF8String(const std::string& aIn)
73 {
74     if (aIn.empty())
75
76         return String();
77
78     size_t inbytes = aIn.size();
79
80     // Default iconv UTF-32 module adds BOM (4 bytes) in from of string
81     // The worst case is when 8bit UTF-8 char converts to 32bit UTF-32
82     // newsize = oldsize * 4 + end + bom
83     // newsize - bytes for UTF-32 string
84     // oldsize - letters in UTF-8 string
85     // end - end character for UTF-32 (\0)
86     // bom - Unicode header in front of string (0xfeff)
87     size_t outbytes = sizeof(wchar_t)*(inbytes + 2);
88     std::vector<wchar_t> output(inbytes + 2, 0);
89
90     size_t outbytesleft = outbytes;
91     char* inbuf = const_cast<char*>(aIn.c_str());
92
93     // vector is used to provide buffer for iconv which expects char* buffer
94     // but during conversion from UTF32 uses internaly wchar_t
95     char* outbuf = reinterpret_cast<char*>(&output[0]);
96
97     iconv_t iconvHandle = iconv_open("UTF-32","UTF-8");
98
99     if (gc_IconvOperError == iconvHandle)
100     {
101         int error = errno;
102
103         ThrowMsg(StringException::IconvInitErrorUTF8ToUTF32,
104                  "iconv_open failed for " << "UTF-32 <- UTF-8" <<
105                  "error: " << GetErrnoString(error));
106     }
107
108     size_t iconvRet = iconv(iconvHandle, &inbuf, &inbytes, &outbuf, &outbytesleft);
109
110     iconv_close(iconvHandle);
111
112     if (gc_IconvConvertError == iconvRet)
113     {
114         ThrowMsg(StringException::IconvConvertErrorUTF8ToUTF32,
115                  "iconv failed for " << "UTF-32 <- UTF-8" << "error: "
116                             << GetErrnoString());
117         return String();
118     }
119
120     // Ignore BOM in front of UTF-32
121     return &output[1];
122 }
123
124 std::string ToUTF8String(const DPL::String& aIn)
125 {
126     if (aIn.empty())
127
128         return std::string();
129
130     size_t inbytes = aIn.size() * sizeof(wchar_t);
131     size_t outbytes = inbytes + sizeof(char);
132
133     // wstring returns wchar_t but iconv expects char*
134     // iconv internally is processing input as wchar_t
135     char* inbuf =  reinterpret_cast<char*>(const_cast<wchar_t*>(aIn.c_str()));
136     std::vector<char> output(inbytes, 0);
137     char* outbuf = &output[0];
138
139     size_t outbytesleft = outbytes;
140
141     iconv_t iconvHandle = iconv_open("UTF-8","UTF-32");
142
143     if (gc_IconvOperError == iconvHandle)
144     {
145         ThrowMsg(StringException::IconvInitErrorUTF32ToUTF8,
146                  "iconv_open failed for " << "UTF-8 <- UTF-32"
147                             << "error: " << GetErrnoString());
148         return std::string();
149     }
150
151     size_t iconvRet = iconv(iconvHandle, &inbuf, &inbytes, &outbuf, &outbytesleft);
152
153     iconv_close(iconvHandle);
154
155     if (gc_IconvConvertError == iconvRet)
156     {
157         ThrowMsg(StringException::IconvConvertErrorUTF32ToUTF8,
158                  "iconv failed for " << "UTF-8 <- UTF-32"
159                             << "error: " << GetErrnoString());
160         return std::string();
161     }
162
163     return &output[0];
164 }
165
166 String FromASCIIString(const std::string& aString)
167 {
168     String output;
169
170     std::for_each(aString.begin(), aString.end(), ASCIIValidator(aString));
171     std::copy(aString.begin(), aString.end(), std::back_inserter<String>(output));
172
173     return output;
174 }
175
176 String FromUTF32String(const std::wstring& aString)
177 {
178     return String(&aString[0]);
179 }
180
181 static UChar *ConvertToICU(const String &inputString)
182 {
183     ScopedArray<UChar> outputString;
184     int32_t size = 0;
185     int32_t convertedSize = 0;
186     UErrorCode error = U_ZERO_ERROR;
187
188     // Calculate size of output string
189     ::u_strFromWCS(NULL,
190                    0,
191                    &size,
192                    inputString.c_str(),
193                    -1,
194                    &error);
195
196     if (error == U_ZERO_ERROR ||
197         error == U_BUFFER_OVERFLOW_ERROR)
198     {
199         // What buffer size is ok ?
200         LogPedantic("ICU: Output buffer size: " << size);
201     }
202     else
203     {
204         ThrowMsg(StringException::ICUInvalidCharacterFound,
205                  "ICU: Failed to retrieve output string size. Error: "
206                  << error);
207     }
208
209     // Allocate proper buffer
210     outputString.Reset(new UChar[size + 1]);
211     ::memset(outputString.Get(), 0, sizeof(UChar) * (size + 1));
212
213     error = U_ZERO_ERROR;
214
215     // Do conversion
216     ::u_strFromWCS(outputString.Get(),
217                    size + 1,
218                    &convertedSize,
219                    inputString.c_str(),
220                    -1,
221                    &error);
222
223     if (!U_SUCCESS(error))
224     {
225         ThrowMsg(StringException::ICUInvalidCharacterFound,
226                  "ICU: Failed to convert string. Error: " << error);
227     }
228
229     // Done
230     return outputString.Release();
231 }
232
233 int StringCompare(const String &left,
234                   const String &right,
235                   bool caseInsensitive)
236 {
237     // Convert input strings
238     ScopedArray<UChar> leftICU(ConvertToICU(left));
239     ScopedArray<UChar> rightICU(ConvertToICU(right));
240
241     if (caseInsensitive)
242     {
243         return static_cast<int>(u_strcasecmp(leftICU.Get(), rightICU.Get(), 0));
244     }
245     else
246     {
247         return static_cast<int>(u_strcmp(leftICU.Get(), rightICU.Get()));
248     }
249 }
250 } //namespace DPL
251
252 std::ostream& operator<<(std::ostream& aStream, const DPL::String& aString)
253 {
254     return aStream << DPL::ToUTF8String(aString);
255 }