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
14CFX_PrivateData::~CFX_PrivateData()
15{
16    ClearAll();
17}
18void 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}
29void 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}
47void CFX_PrivateData::SetPrivateData(FX_LPVOID pModuleId, FX_LPVOID pData, PD_CALLBACK_FREEDATA callback)
48{
49    AddData(pModuleId, pData, callback, FALSE);
50}
51void CFX_PrivateData::SetPrivateObj(FX_LPVOID pModuleId, CFX_DestructObject* pObj)
52{
53    AddData(pModuleId, pObj, NULL, TRUE);
54}
55FX_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}
70FX_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}
84void 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}
93void 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}
126FX_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
173#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ && _MSC_VER < 1900
174void FXSYS_snprintf(char *str, size_t size, _Printf_format_string_ const char* fmt, ...)
175{
176    va_list ap;
177    va_start(ap, fmt);
178    FXSYS_vsnprintf(str, size, fmt, ap);
179    va_end(ap);
180}
181void FXSYS_vsnprintf(char *str, size_t size, const char* fmt, va_list ap)
182{
183    (void) _vsnprintf(str, size, fmt, ap);
184    if (size) {
185        str[size - 1] = 0;
186    }
187}
188#endif  // _FXM_PLATFORM_WINDOWS_ && _MSC_VER < 1900
189
190static FX_BOOL FX_IsDigit(FX_BYTE ch)
191{
192    return (ch >= '0' && ch <= '9') ? TRUE : FALSE;
193}
194static FX_BOOL FX_IsXDigit(FX_BYTE ch)
195{
196    return (FX_IsDigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) ? TRUE : FALSE;
197}
198static FX_BYTE FX_MakeUpper(FX_BYTE ch)
199{
200    if (ch < 'a' || ch > 'z') {
201        return ch;
202    }
203    return ch - 32;
204}
205static int FX_HexToI(FX_BYTE ch)
206{
207    ch = FX_MakeUpper(ch);
208    return FX_IsDigit(ch) ? (ch - '0') : (ch - 55);
209}
210static const unsigned char url_encodeTable[128] = {
211    1,  1,  1,  1,		1,  1,  1,  1,
212    1,  1,  1,  1,		1,  1,  1,  1,
213    1,  1,  1,  1,		1,  1,  1,  1,
214    1,  1,  1,  1,		1,  1,  1,  1,
215    1,  0,  1,  1,		0,  1,  0,  0,
216    0,  0,  0,  0,		0,  0,  0,  0,
217    0,  0,  0,  0,		0,  0,  0,  0,
218    0,  0,  0,  0,		1,  0,  1,  0,
219    0,  0,  0,  0,		0,  0,  0,  0,
220    0,  0,  0,  0,		0,  0,  0,  0,
221    0,  0,  0,  0,		0,  0,  0,  0,
222    0,  0,  0,  1,		1,  1,  1,  0,
223    1,  0,  0,  0,		0,  0,  0,  0,
224    0,  0,  0,  0,		0,  0,  0,  0,
225    0,  0,  0,  0,		0,  0,  0,  0,
226    0,  0,  0,  1,		1,  1,  1,  1,
227};
228CFX_ByteString FX_UrlEncode(const CFX_WideString& wsUrl)
229{
230    const char arDigits[] = "0123456789ABCDEF";
231    CFX_ByteString rUrl;
232    int nLength = wsUrl.GetLength();
233    for (int i = 0; i < nLength; i++) {
234        FX_DWORD word = wsUrl.GetAt(i);
235        if (word > 0x7F || url_encodeTable[word] == 1) {
236            CFX_ByteString bsUri = CFX_ByteString::FromUnicode((FX_WORD)word);
237            int nByte = bsUri.GetLength();
238            for (int j = 0; j < nByte; j++) {
239                rUrl += '%';
240                FX_BYTE code = bsUri.GetAt(j);
241                rUrl += arDigits[code >> 4];
242                rUrl += arDigits[code & 0x0F];
243            }
244        } else {
245            rUrl += CFX_ByteString::FromUnicode((FX_WORD)word);
246        }
247    }
248    return rUrl;
249}
250CFX_WideString FX_UrlDecode(const CFX_ByteString& bsUrl)
251{
252    CFX_ByteString rUrl;
253    int nLength = bsUrl.GetLength();
254    for (int i = 0; i < nLength; i++) {
255        if (i < nLength - 2 && bsUrl[i] == '%' && FX_IsXDigit(bsUrl[i + 1]) && FX_IsXDigit(bsUrl[i + 2])) {
256            rUrl += (FX_HexToI(bsUrl[i + 1]) << 4 | FX_HexToI(bsUrl[i + 2]));
257            i += 2;
258        } else {
259            rUrl += bsUrl[i];
260        }
261    }
262    return CFX_WideString::FromLocal(rUrl);
263}
264CFX_ByteString FX_EncodeURI(const CFX_WideString& wsURI)
265{
266    const char arDigits[] = "0123456789ABCDEF";
267    CFX_ByteString rURI;
268    CFX_ByteString bsUri = wsURI.UTF8Encode();
269    int nLength = bsUri.GetLength();
270    for (int i = 0; i < nLength; i++) {
271        FX_BYTE code = bsUri.GetAt(i);
272        if (code > 0x7F || url_encodeTable[code] == 1) {
273            rURI += '%';
274            rURI += arDigits[code >> 4];
275            rURI += arDigits[code & 0x0F];
276        } else {
277            rURI += code;
278        }
279    }
280    return rURI;
281}
282CFX_WideString FX_DecodeURI(const CFX_ByteString& bsURI)
283{
284    CFX_ByteString rURI;
285    int nLength = bsURI.GetLength();
286    for (int i = 0; i < nLength; i++) {
287        if (i < nLength - 2 && bsURI[i] == '%' && FX_IsXDigit(bsURI[i + 1]) && FX_IsXDigit(bsURI[i + 2])) {
288            rURI += (FX_HexToI(bsURI[i + 1]) << 4 | FX_HexToI(bsURI[i + 2]));
289            i += 2;
290        } else {
291            rURI += bsURI[i];
292        }
293    }
294    return CFX_WideString::FromUTF8(rURI, rURI.GetLength());
295}
296#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
297class CFindFileData
298{
299public:
300    virtual ~CFindFileData() {}
301    HANDLE				m_Handle;
302    FX_BOOL				m_bEnd;
303};
304class CFindFileDataA : public CFindFileData
305{
306public:
307    virtual ~CFindFileDataA() {}
308    WIN32_FIND_DATAA	m_FindData;
309};
310class CFindFileDataW : public CFindFileData
311{
312public:
313    virtual ~CFindFileDataW() {}
314    WIN32_FIND_DATAW	m_FindData;
315};
316#endif
317void* FX_OpenFolder(FX_LPCSTR path)
318{
319#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
320#ifndef _WIN32_WCE
321    CFindFileDataA* pData = new CFindFileDataA;
322#ifdef _FX_WINAPI_PARTITION_DESKTOP_
323    pData->m_Handle = FindFirstFileA(CFX_ByteString(path) + "/*.*", &pData->m_FindData);
324#else
325    pData->m_Handle = FindFirstFileExA(CFX_ByteString(path) + "/*.*", FindExInfoStandard, &pData->m_FindData, FindExSearchNameMatch, NULL, 0);
326#endif
327#else
328    CFindFileDataW* pData = new CFindFileDataW;
329    pData->m_Handle = FindFirstFileW(CFX_WideString::FromLocal(path) + L"/*.*", &pData->m_FindData);
330#endif
331    if (pData->m_Handle == INVALID_HANDLE_VALUE) {
332        delete pData;
333        return NULL;
334    }
335    pData->m_bEnd = FALSE;
336    return pData;
337#else
338    DIR* dir = opendir(path);
339    return dir;
340#endif
341}
342void* FX_OpenFolder(FX_LPCWSTR path)
343{
344#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
345    CFindFileDataW* pData = new CFindFileDataW;
346#ifdef _FX_WINAPI_PARTITION_DESKTOP_
347    pData->m_Handle = FindFirstFileW((CFX_WideString(path) + L"/*.*").c_str(), &pData->m_FindData);
348#else
349    pData->m_Handle = FindFirstFileExW((CFX_WideString(path) + L"/*.*").c_str(), FindExInfoStandard, &pData->m_FindData, FindExSearchNameMatch, NULL, 0);
350#endif
351    if (pData->m_Handle == INVALID_HANDLE_VALUE) {
352        delete pData;
353        return NULL;
354    }
355    pData->m_bEnd = FALSE;
356    return pData;
357#else
358    DIR* dir = opendir(CFX_ByteString::FromUnicode(path));
359    return dir;
360#endif
361}
362FX_BOOL FX_GetNextFile(void* handle, CFX_ByteString& filename, FX_BOOL& bFolder)
363{
364    if (handle == NULL) {
365        return FALSE;
366    }
367#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
368#ifndef _WIN32_WCE
369    CFindFileDataA* pData = (CFindFileDataA*)handle;
370    if (pData->m_bEnd) {
371        return FALSE;
372    }
373    filename = pData->m_FindData.cFileName;
374    bFolder = pData->m_FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
375    if (!FindNextFileA(pData->m_Handle, &pData->m_FindData)) {
376        pData->m_bEnd = TRUE;
377    }
378    return TRUE;
379#else
380    CFindFileDataW* pData = (CFindFileDataW*)handle;
381    if (pData->m_bEnd) {
382        return FALSE;
383    }
384    filename = CFX_ByteString::FromUnicode(pData->m_FindData.cFileName);
385    bFolder = pData->m_FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
386    if (!FindNextFileW(pData->m_Handle, &pData->m_FindData)) {
387        pData->m_bEnd = TRUE;
388    }
389    return TRUE;
390#endif
391#elif defined(__native_client__)
392    abort();
393    return FALSE;
394#else
395    struct dirent *de = readdir((DIR*)handle);
396    if (de == NULL) {
397        return FALSE;
398    }
399    filename = de->d_name;
400    bFolder = de->d_type == DT_DIR;
401    return TRUE;
402#endif
403}
404FX_BOOL FX_GetNextFile(void* handle, CFX_WideString& filename, FX_BOOL& bFolder)
405{
406    if (handle == NULL) {
407        return FALSE;
408    }
409#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
410    CFindFileDataW* pData = (CFindFileDataW*)handle;
411    if (pData->m_bEnd) {
412        return FALSE;
413    }
414    filename = pData->m_FindData.cFileName;
415    bFolder = pData->m_FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
416    if (!FindNextFileW(pData->m_Handle, &pData->m_FindData)) {
417        pData->m_bEnd = TRUE;
418    }
419    return TRUE;
420#elif defined(__native_client__)
421    abort();
422    return FALSE;
423#else
424    struct dirent *de = readdir((DIR*)handle);
425    if (de == NULL) {
426        return FALSE;
427    }
428    filename = CFX_WideString::FromLocal(de->d_name);
429    bFolder = de->d_type == DT_DIR;
430    return TRUE;
431#endif
432}
433void FX_CloseFolder(void* handle)
434{
435    if (handle == NULL) {
436        return;
437    }
438#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
439    CFindFileData* pData = (CFindFileData*)handle;
440    FindClose(pData->m_Handle);
441    delete pData;
442#else
443    closedir((DIR*)handle);
444#endif
445}
446FX_WCHAR FX_GetFolderSeparator()
447{
448#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
449    return '\\';
450#else
451    return '/';
452#endif
453}
454
455CFX_Matrix_3by3 CFX_Matrix_3by3::Inverse()
456{
457    FX_FLOAT det = a*(e*i - f*h) - b*(i*d - f*g) + c*(d*h - e*g);
458    if (FXSYS_fabs(det) < 0.0000001)
459        return CFX_Matrix_3by3();
460    else
461        return CFX_Matrix_3by3(
462            (e*i - f*h) / det,
463            -(b*i - c*h) / det,
464            (b*f - c*e) / det,
465            -(d*i - f*g) / det,
466            (a*i - c*g) / det,
467            -(a*f - c*d) / det,
468            (d*h - e*g) / det,
469            -(a*h - b*g) / det,
470            (a*e - b*d) / det
471        );
472}
473
474CFX_Matrix_3by3 CFX_Matrix_3by3::Multiply(const CFX_Matrix_3by3 &m)
475{
476    return CFX_Matrix_3by3(
477        a*m.a + b*m.d + c*m.g,
478        a*m.b + b*m.e + c*m.h,
479        a*m.c + b*m.f + c*m.i,
480        d*m.a + e*m.d + f*m.g,
481        d*m.b + e*m.e + f*m.h,
482        d*m.c + e*m.f + f*m.i,
483        g*m.a + h*m.d + i*m.g,
484        g*m.b + h*m.e + i*m.h,
485        g*m.c + h*m.f + i*m.i
486      );
487}
488
489CFX_Vector_3by1 CFX_Matrix_3by3::TransformVector(const CFX_Vector_3by1 &v)
490{
491    return CFX_Vector_3by1(
492        a * v.a + b * v.b + c * v.c,
493        d * v.a + e * v.b + f * v.c,
494        g * v.a + h * v.b + i * v.c
495    );
496}
497