Add ostream helpers for FX String classes.
[pdfium.git] / core / src / fxcrt / fx_basic_util.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4  
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../include/fxcrt/fx_basic.h"
8 #if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
9 #include <sys/types.h>
10 #include <dirent.h>
11 #else
12 #include <direct.h>
13 #endif
14 CFX_PrivateData::~CFX_PrivateData()
15 {
16     ClearAll();
17 }
18 void FX_PRIVATEDATA::FreeData()
19 {
20     if (m_pData == NULL) {
21         return;
22     }
23     if (m_bSelfDestruct) {
24         delete (CFX_DestructObject*)m_pData;
25     } else if (m_pCallback) {
26         m_pCallback(m_pData);
27     }
28 }
29 void CFX_PrivateData::AddData(FX_LPVOID pModuleId, FX_LPVOID pData, PD_CALLBACK_FREEDATA callback, FX_BOOL bSelfDestruct)
30 {
31     if (pModuleId == NULL) {
32         return;
33     }
34     FX_PRIVATEDATA* pList = m_DataList.GetData();
35     int count = m_DataList.GetSize();
36     for (int i = 0; i < count; i ++) {
37         if (pList[i].m_pModuleId == pModuleId) {
38             pList[i].FreeData();
39             pList[i].m_pData = pData;
40             pList[i].m_pCallback = callback;
41             return;
42         }
43     }
44     FX_PRIVATEDATA data = {pModuleId, pData, callback, bSelfDestruct};
45     m_DataList.Add(data);
46 }
47 void CFX_PrivateData::SetPrivateData(FX_LPVOID pModuleId, FX_LPVOID pData, PD_CALLBACK_FREEDATA callback)
48 {
49     AddData(pModuleId, pData, callback, FALSE);
50 }
51 void CFX_PrivateData::SetPrivateObj(FX_LPVOID pModuleId, CFX_DestructObject* pObj)
52 {
53     AddData(pModuleId, pObj, NULL, TRUE);
54 }
55 FX_BOOL CFX_PrivateData::RemovePrivateData(FX_LPVOID pModuleId)
56 {
57     if (pModuleId == NULL) {
58         return FALSE;
59     }
60     FX_PRIVATEDATA* pList = m_DataList.GetData();
61     int count = m_DataList.GetSize();
62     for (int i = 0; i < count; i ++) {
63         if (pList[i].m_pModuleId == pModuleId) {
64             m_DataList.RemoveAt(i);
65             return TRUE;
66         }
67     }
68     return FALSE;
69 }
70 FX_LPVOID CFX_PrivateData::GetPrivateData(FX_LPVOID pModuleId)
71 {
72     if (pModuleId == NULL) {
73         return NULL;
74     }
75     FX_PRIVATEDATA* pList = m_DataList.GetData();
76     int count = m_DataList.GetSize();
77     for (int i = 0; i < count; i ++) {
78         if (pList[i].m_pModuleId == pModuleId) {
79             return pList[i].m_pData;
80         }
81     }
82     return NULL;
83 }
84 void CFX_PrivateData::ClearAll()
85 {
86     FX_PRIVATEDATA* pList = m_DataList.GetData();
87     int count = m_DataList.GetSize();
88     for (int i = 0; i < count; i ++) {
89         pList[i].FreeData();
90     }
91     m_DataList.RemoveAll();
92 }
93 void FX_atonum(FX_BSTR strc, FX_BOOL& bInteger, void* pData)
94 {
95     if (FXSYS_memchr(strc.GetPtr(), '.', strc.GetLength()) == NULL) {
96         bInteger = TRUE;
97         int cc = 0, integer = 0;
98         FX_LPCSTR str = strc.GetCStr();
99         int len = strc.GetLength();
100         FX_BOOL bNegative = FALSE;
101         if (str[0] == '+') {
102             cc++;
103         } else if (str[0] == '-') {
104             bNegative = TRUE;
105             cc++;
106         }
107         while (cc < len) {
108             if (str[cc] < '0' || str[cc] > '9') {
109                 break;
110             }
111             integer = integer * 10 + str[cc] - '0';
112             if (integer < 0) {
113                 break;
114             }
115             cc ++;
116         }
117         if (bNegative) {
118             integer = -integer;
119         }
120         *(int*)pData = integer;
121     } else {
122         bInteger = FALSE;
123         *(FX_FLOAT*)pData = FX_atof(strc);
124     }
125 }
126 FX_FLOAT FX_atof(FX_BSTR strc)
127 {
128     if (strc.GetLength() == 0) {
129         return 0.0;
130     }
131     int cc = 0;
132     FX_BOOL bNegative = FALSE;
133     FX_LPCSTR str = strc.GetCStr();
134     int len = strc.GetLength();
135     if (str[0] == '+') {
136         cc++;
137     } else if (str[0] == '-') {
138         bNegative = TRUE;
139         cc++;
140     }
141     while (cc < len) {
142         if (str[cc] != '+' && str[cc] != '-') {
143             break;
144         }
145         cc ++;
146     }
147     FX_FLOAT value = 0;
148     while (cc < len) {
149         if (str[cc] == '.') {
150             break;
151         }
152         value = value * 10 + str[cc] - '0';
153         cc ++;
154     }
155     static const FX_FLOAT fraction_scales[] = {0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f,
156                                                0.0000001f, 0.00000001f, 0.000000001f, 0.0000000001f, 0.00000000001f
157                                               };
158     int scale = 0;
159     if (cc < len && str[cc] == '.') {
160         cc ++;
161         while (cc < len) {
162             value += fraction_scales[scale] * (str[cc] - '0');
163             scale ++;
164             if (scale == sizeof fraction_scales / sizeof(FX_FLOAT)) {
165                 break;
166             }
167             cc ++;
168         }
169     }
170     return bNegative ? -value : value;
171 }
172 static FX_BOOL FX_IsDigit(FX_BYTE ch)
173 {
174     return (ch >= '0' && ch <= '9') ? TRUE : FALSE;
175 }
176 static FX_BOOL FX_IsXDigit(FX_BYTE ch)
177 {
178     return (FX_IsDigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) ? TRUE : FALSE;
179 }
180 static FX_BYTE FX_MakeUpper(FX_BYTE ch)
181 {
182     if (ch < 'a' || ch > 'z') {
183         return ch;
184     }
185     return ch - 32;
186 }
187 static int FX_HexToI(FX_BYTE ch)
188 {
189     ch = FX_MakeUpper(ch);
190     return FX_IsDigit(ch) ? (ch - '0') : (ch - 55);
191 }
192 static const unsigned char url_encodeTable[128] = {
193     1,  1,  1,  1,              1,  1,  1,  1,
194     1,  1,  1,  1,              1,  1,  1,  1,
195     1,  1,  1,  1,              1,  1,  1,  1,
196     1,  1,  1,  1,              1,  1,  1,  1,
197     1,  0,  1,  1,              0,  1,  0,  0,
198     0,  0,  0,  0,              0,  0,  0,  0,
199     0,  0,  0,  0,              0,  0,  0,  0,
200     0,  0,  0,  0,              1,  0,  1,  0,
201     0,  0,  0,  0,              0,  0,  0,  0,
202     0,  0,  0,  0,              0,  0,  0,  0,
203     0,  0,  0,  0,              0,  0,  0,  0,
204     0,  0,  0,  1,              1,  1,  1,  0,
205     1,  0,  0,  0,              0,  0,  0,  0,
206     0,  0,  0,  0,              0,  0,  0,  0,
207     0,  0,  0,  0,              0,  0,  0,  0,
208     0,  0,  0,  1,              1,  1,  1,  1,
209 };
210 CFX_ByteString FX_UrlEncode(const CFX_WideString& wsUrl)
211 {
212     const char arDigits[] = "0123456789ABCDEF";
213     CFX_ByteString rUrl;
214     int nLength = wsUrl.GetLength();
215     for (int i = 0; i < nLength; i++) {
216         FX_DWORD word = wsUrl.GetAt(i);
217         if (word > 0x7F || url_encodeTable[word] == 1) {
218             CFX_ByteString bsUri = CFX_ByteString::FromUnicode((FX_WORD)word);
219             int nByte = bsUri.GetLength();
220             for (int j = 0; j < nByte; j++) {
221                 rUrl += '%';
222                 FX_BYTE code = bsUri.GetAt(j);
223                 rUrl += arDigits[code >> 4];
224                 rUrl += arDigits[code & 0x0F];
225             }
226         } else {
227             rUrl += CFX_ByteString::FromUnicode((FX_WORD)word);
228         }
229     }
230     return rUrl;
231 }
232 CFX_WideString FX_UrlDecode(const CFX_ByteString& bsUrl)
233 {
234     CFX_ByteString rUrl;
235     int nLength = bsUrl.GetLength();
236     for (int i = 0; i < nLength; i++) {
237         if (i < nLength - 2 && bsUrl[i] == '%' && FX_IsXDigit(bsUrl[i + 1]) && FX_IsXDigit(bsUrl[i + 2])) {
238             rUrl += (FX_HexToI(bsUrl[i + 1]) << 4 | FX_HexToI(bsUrl[i + 2]));
239             i += 2;
240         } else {
241             rUrl += bsUrl[i];
242         }
243     }
244     return CFX_WideString::FromLocal(rUrl);
245 }
246 CFX_ByteString FX_EncodeURI(const CFX_WideString& wsURI)
247 {
248     const char arDigits[] = "0123456789ABCDEF";
249     CFX_ByteString rURI;
250     CFX_ByteString bsUri = wsURI.UTF8Encode();
251     int nLength = bsUri.GetLength();
252     for (int i = 0; i < nLength; i++) {
253         FX_BYTE code = bsUri.GetAt(i);
254         if (code > 0x7F || url_encodeTable[code] == 1) {
255             rURI += '%';
256             rURI += arDigits[code >> 4];
257             rURI += arDigits[code & 0x0F];
258         } else {
259             rURI += code;
260         }
261     }
262     return rURI;
263 }
264 CFX_WideString FX_DecodeURI(const CFX_ByteString& bsURI)
265 {
266     CFX_ByteString rURI;
267     int nLength = bsURI.GetLength();
268     for (int i = 0; i < nLength; i++) {
269         if (i < nLength - 2 && bsURI[i] == '%' && FX_IsXDigit(bsURI[i + 1]) && FX_IsXDigit(bsURI[i + 2])) {
270             rURI += (FX_HexToI(bsURI[i + 1]) << 4 | FX_HexToI(bsURI[i + 2]));
271             i += 2;
272         } else {
273             rURI += bsURI[i];
274         }
275     }
276     return CFX_WideString::FromUTF8(rURI, rURI.GetLength());
277 }
278 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
279 class CFindFileData : public CFX_Object
280 {
281 public:
282     virtual ~CFindFileData() {}
283     HANDLE                              m_Handle;
284     FX_BOOL                             m_bEnd;
285 };
286 class CFindFileDataA : public CFindFileData
287 {
288 public:
289     virtual ~CFindFileDataA() {}
290     WIN32_FIND_DATAA    m_FindData;
291 };
292 class CFindFileDataW : public CFindFileData
293 {
294 public:
295     virtual ~CFindFileDataW() {}
296     WIN32_FIND_DATAW    m_FindData;
297 };
298 #endif
299 void* FX_OpenFolder(FX_LPCSTR path)
300 {
301 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
302 #ifndef _WIN32_WCE
303     CFindFileDataA* pData = FX_NEW CFindFileDataA;
304     if (!pData) {
305         return NULL;
306     }
307 #ifdef _FX_WINAPI_PARTITION_DESKTOP_
308     pData->m_Handle = FindFirstFileA(CFX_ByteString(path) + "/*.*", &pData->m_FindData);
309 #else
310     pData->m_Handle = FindFirstFileExA(CFX_ByteString(path) + "/*.*", FindExInfoStandard, &pData->m_FindData, FindExSearchNameMatch, NULL, 0);
311 #endif
312 #else
313     CFindFileDataW* pData = FX_NEW CFindFileDataW;
314     if (!pData) {
315         return NULL;
316     }
317     pData->m_Handle = FindFirstFileW(CFX_WideString::FromLocal(path) + L"/*.*", &pData->m_FindData);
318 #endif
319     if (pData->m_Handle == INVALID_HANDLE_VALUE) {
320         delete pData;
321         return NULL;
322     }
323     pData->m_bEnd = FALSE;
324     return pData;
325 #else
326     DIR* dir = opendir(path);
327     return dir;
328 #endif
329 }
330 void* FX_OpenFolder(FX_LPCWSTR path)
331 {
332 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
333     CFindFileDataW* pData = FX_NEW CFindFileDataW;
334     if (!pData) {
335         return NULL;
336     }
337 #ifdef _FX_WINAPI_PARTITION_DESKTOP_
338     pData->m_Handle = FindFirstFileW(CFX_WideString(path) + L"/*.*", &pData->m_FindData);
339 #else
340     pData->m_Handle = FindFirstFileExW(CFX_WideString(path) + L"/*.*", FindExInfoStandard, &pData->m_FindData, FindExSearchNameMatch, NULL, 0);
341 #endif
342     if (pData->m_Handle == INVALID_HANDLE_VALUE) {
343         delete pData;
344         return NULL;
345     }
346     pData->m_bEnd = FALSE;
347     return pData;
348 #else
349     DIR* dir = opendir(CFX_ByteString::FromUnicode(path));
350     return dir;
351 #endif
352 }
353 FX_BOOL FX_GetNextFile(void* handle, CFX_ByteString& filename, FX_BOOL& bFolder)
354 {
355     if (handle == NULL) {
356         return FALSE;
357     }
358 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
359 #ifndef _WIN32_WCE
360     CFindFileDataA* pData = (CFindFileDataA*)handle;
361     if (pData->m_bEnd) {
362         return FALSE;
363     }
364     filename = pData->m_FindData.cFileName;
365     bFolder = pData->m_FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
366     if (!FindNextFileA(pData->m_Handle, &pData->m_FindData)) {
367         pData->m_bEnd = TRUE;
368     }
369     return TRUE;
370 #else
371     CFindFileDataW* pData = (CFindFileDataW*)handle;
372     if (pData->m_bEnd) {
373         return FALSE;
374     }
375     filename = CFX_ByteString::FromUnicode(pData->m_FindData.cFileName);
376     bFolder = pData->m_FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
377     if (!FindNextFileW(pData->m_Handle, &pData->m_FindData)) {
378         pData->m_bEnd = TRUE;
379     }
380     return TRUE;
381 #endif
382 #elif defined(__native_client__)
383     abort();
384     return FALSE;
385 #else
386     struct dirent *de = readdir((DIR*)handle);
387     if (de == NULL) {
388         return FALSE;
389     }
390     filename = de->d_name;
391     bFolder = de->d_type == DT_DIR;
392     return TRUE;
393 #endif
394 }
395 FX_BOOL FX_GetNextFile(void* handle, CFX_WideString& filename, FX_BOOL& bFolder)
396 {
397     if (handle == NULL) {
398         return FALSE;
399     }
400 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
401     CFindFileDataW* pData = (CFindFileDataW*)handle;
402     if (pData->m_bEnd) {
403         return FALSE;
404     }
405     filename = pData->m_FindData.cFileName;
406     bFolder = pData->m_FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
407     if (!FindNextFileW(pData->m_Handle, &pData->m_FindData)) {
408         pData->m_bEnd = TRUE;
409     }
410     return TRUE;
411 #elif defined(__native_client__)
412     abort();
413     return FALSE;
414 #else
415     struct dirent *de = readdir((DIR*)handle);
416     if (de == NULL) {
417         return FALSE;
418     }
419     filename = CFX_WideString::FromLocal(de->d_name);
420     bFolder = de->d_type == DT_DIR;
421     return TRUE;
422 #endif
423 }
424 void FX_CloseFolder(void* handle)
425 {
426     if (handle == NULL) {
427         return;
428     }
429 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
430     CFindFileData* pData = (CFindFileData*)handle;
431     FindClose(pData->m_Handle);
432     delete pData;
433 #else
434     closedir((DIR*)handle);
435 #endif
436 }
437 FX_WCHAR FX_GetFolderSeparator()
438 {
439 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
440     return '\\';
441 #else
442     return '/';
443 #endif
444 }
445
446 CFX_Matrix_3by3 CFX_Matrix_3by3::Inverse()
447 {
448     FX_FLOAT det = a*(e*i - f*h) - b*(i*d - f*g) + c*(d*h - e*g);
449     if (FXSYS_fabs(det) < 0.0000001)
450         return CFX_Matrix_3by3();
451     else
452         return CFX_Matrix_3by3(
453             (e*i - f*h) / det,
454             -(b*i - c*h) / det,
455             (b*f - c*e) / det,
456             -(d*i - f*g) / det,
457             (a*i - c*g) / det,
458             -(a*f - c*d) / det,
459             (d*h - e*g) / det,
460             -(a*h - b*g) / det,
461             (a*e - b*d) / det
462         );
463 }
464
465 CFX_Matrix_3by3 CFX_Matrix_3by3::Multiply(const CFX_Matrix_3by3 &m)
466 {
467     return CFX_Matrix_3by3(
468         a*m.a + b*m.d + c*m.g,
469         a*m.b + b*m.e + c*m.h,
470         a*m.c + b*m.f + c*m.i,
471         d*m.a + e*m.d + f*m.g,
472         d*m.b + e*m.e + f*m.h,
473         d*m.c + e*m.f + f*m.i,
474         g*m.a + h*m.d + i*m.g,
475         g*m.b + h*m.e + i*m.h,
476         g*m.c + h*m.f + i*m.i
477       );
478 }
479
480 CFX_Vector_3by1 CFX_Matrix_3by3::TransformVector(const CFX_Vector_3by1 &v)
481 {
482     return CFX_Vector_3by1(
483         a * v.a + b * v.b + c * v.c,
484         d * v.a + e * v.b + f * v.c,
485         g * v.a + h * v.b + i * v.c
486     );
487 }