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}
172static FX_BOOL FX_IsDigit(FX_BYTE ch)
173{
174    return (ch >= '0' && ch <= '9') ? TRUE : FALSE;
175}
176static FX_BOOL FX_IsXDigit(FX_BYTE ch)
177{
178    return (FX_IsDigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) ? TRUE : FALSE;
179}
180static FX_BYTE FX_MakeUpper(FX_BYTE ch)
181{
182    if (ch < 'a' || ch > 'z') {
183        return ch;
184    }
185    return ch - 32;
186}
187static int FX_HexToI(FX_BYTE ch)
188{
189    ch = FX_MakeUpper(ch);
190    return FX_IsDigit(ch) ? (ch - '0') : (ch - 55);
191}
192static 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};
210CFX_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}
232CFX_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}
246CFX_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}
264CFX_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);
277}
278#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
279class CFindFileData : public CFX_Object
280{
281public:
282    virtual ~CFindFileData() {}
283    HANDLE				m_Handle;
284    FX_BOOL				m_bEnd;
285};
286class CFindFileDataA : public CFindFileData
287{
288public:
289    virtual ~CFindFileDataA() {}
290    WIN32_FIND_DATAA	m_FindData;
291};
292class CFindFileDataW : public CFindFileData
293{
294public:
295    virtual ~CFindFileDataW() {}
296    WIN32_FIND_DATAW	m_FindData;
297};
298#endif
299void* 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}
330void* 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}
353FX_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}
395FX_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}
424void 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}
437FX_WCHAR FX_GetFolderSeparator()
438{
439#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
440    return '\\';
441#else
442    return '/';
443#endif
444}
445