Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fgas / src / localization / fx_locale.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../fgas_base.h"\r
8 #include "fx_localeimp.h"\r
9 #define FX_LOCALECATEGORY_DateHash                      0xbde9abde\r
10 #define FX_LOCALECATEGORY_TimeHash                      0x2d71b00f\r
11 #define FX_LOCALECATEGORY_DateTimeHash          0x158c72ed\r
12 #define FX_LOCALECATEGORY_NumHash                       0x0b4ff870\r
13 #define FX_LOCALECATEGORY_TextHash                      0x2d08af85\r
14 #define FX_LOCALECATEGORY_ZeroHash                      0x568cb500\r
15 #define FX_LOCALECATEGORY_NullHash                      0x052931bb\r
16 typedef struct _FX_LOCALESUBCATEGORYINFO {\r
17     FX_UINT32                                   uHash;\r
18     FX_LPCWSTR                                  pName;\r
19     FX_INT32                                    eSubCategory;\r
20 } FX_LOCALESUBCATEGORYINFO, * FX_LPLOCALESUBCATEGORYINFO;\r
21 typedef FX_LOCALESUBCATEGORYINFO const * FX_LPCLOCALESUBCATEGORYINFO;\r
22 const static FX_LOCALESUBCATEGORYINFO g_FXLocaleDateTimeSubCatData[] = {\r
23     {0x14da2125, (FX_LPCWSTR)L"default", FX_LOCALEDATETIMESUBCATEGORY_Default},\r
24     {0x9041d4b0, (FX_LPCWSTR)L"short", FX_LOCALEDATETIMESUBCATEGORY_Short},\r
25     {0xa084a381, (FX_LPCWSTR)L"medium", FX_LOCALEDATETIMESUBCATEGORY_Medium},\r
26     {0xcdce56b3, (FX_LPCWSTR)L"full", FX_LOCALEDATETIMESUBCATEGORY_Full},\r
27     {0xf6b4afb0, (FX_LPCWSTR)L"long", FX_LOCALEDATETIMESUBCATEGORY_Long},\r
28 };\r
29 const static FX_INT32 g_iFXLocaleDateTimeSubCatCount = sizeof(g_FXLocaleDateTimeSubCatData) / sizeof(FX_LOCALESUBCATEGORYINFO);\r
30 const static FX_LOCALESUBCATEGORYINFO g_FXLocaleNumSubCatData[] = {\r
31     {0x46f95531, (FX_LPCWSTR)L"percent", FX_LOCALENUMPATTERN_Percent},\r
32     {0x4c4e8acb, (FX_LPCWSTR)L"currency", FX_LOCALENUMPATTERN_Currency},\r
33     {0x54034c2f, (FX_LPCWSTR)L"decimal", FX_LOCALENUMPATTERN_Decimal},\r
34     {0x7568e6ae, (FX_LPCWSTR)L"integer", FX_LOCALENUMPATTERN_Integer},\r
35 };\r
36 const static FX_INT32 g_iFXLocaleNumSubCatCount = sizeof(g_FXLocaleNumSubCatData) / sizeof(FX_LOCALESUBCATEGORYINFO);\r
37 typedef struct _FX_LOCALETIMEZONEINFO {\r
38     FX_DWORD                                    uHash;\r
39     FX_INT16                                    iHour;\r
40     FX_INT16                                    iMinute;\r
41 } FX_LOCALETIMEZONEINFO, * FX_LPLOCALETIMEZONEINFO;\r
42 typedef FX_LOCALETIMEZONEINFO const * FX_LPCLOCALETIMEZONEINFO;\r
43 const static FX_LOCALETIMEZONEINFO g_FXLocaleTimeZoneData[] = {\r
44     {FXBSTR_ID(0, 'C', 'D', 'T'), -5, 0}, {FXBSTR_ID(0, 'C', 'S', 'T'), -6, 0},\r
45     {FXBSTR_ID(0, 'E', 'D', 'T'), -4, 0}, {FXBSTR_ID(0, 'E', 'S', 'T'), -5, 0},\r
46     {FXBSTR_ID(0, 'M', 'D', 'T'), -6, 0}, {FXBSTR_ID(0, 'M', 'S', 'T'), -7, 0},\r
47     {FXBSTR_ID(0, 'P', 'D', 'T'), -7, 0}, {FXBSTR_ID(0, 'P', 'S', 'T'), -8, 0},\r
48 };\r
49 const static FX_INT32 g_iFXLocaleTimeZoneCount = sizeof(g_FXLocaleTimeZoneData) / sizeof(FX_LOCALETIMEZONEINFO);\r
50 const static CFX_WideStringC gs_wsTextSymbols = FX_WSTRC(L"AXO09");\r
51 const static CFX_WideStringC gs_wsTimeSymbols = FX_WSTRC(L"hHkKMSFAzZ");\r
52 const static CFX_WideStringC gs_wsDateSymbols = FX_WSTRC(L"DJMEeGgYwW");\r
53 const static CFX_WideStringC gs_wsConstChars = FX_WSTRC(L",-:/. ");\r
54 static FX_STRSIZE FX_Local_Find(FX_WSTR wsSymbols, FX_WCHAR ch, FX_STRSIZE nStart = 0)\r
55 {\r
56     FX_STRSIZE nLength = wsSymbols.GetLength();\r
57     if (nLength < 1 || nStart > nLength) {\r
58         return -1;\r
59     }\r
60     FX_LPCWSTR lpsz = (FX_LPCWSTR)FXSYS_wcschr(wsSymbols.GetPtr() + nStart, ch);\r
61     return (lpsz == NULL) ? -1 : (FX_STRSIZE)(lpsz - wsSymbols.GetPtr());\r
62 }\r
63 const static FX_LPCWSTR gs_LocalNumberSymbols[] = {\r
64     (FX_LPCWSTR)L"decimal", (FX_LPCWSTR)L"grouping", (FX_LPCWSTR)L"percent", (FX_LPCWSTR)L"minus", (FX_LPCWSTR)L"zero",\r
65     (FX_LPCWSTR)L"currencySymbol", (FX_LPCWSTR)L"currencyName",\r
66 };\r
67 IFX_Locale* IFX_Locale::Create(CXML_Element* pLocaleData)\r
68 {\r
69     return FX_NEW CFX_Locale(pLocaleData);\r
70 }\r
71 CFX_Locale::CFX_Locale(CXML_Element* pLocaleData)\r
72 {\r
73     m_pElement = pLocaleData;\r
74 }\r
75 CFX_Locale::~CFX_Locale()\r
76 {\r
77 }\r
78 CFX_WideString CFX_Locale::GetName()\r
79 {\r
80     return CFX_WideString();\r
81 }\r
82 static CFX_WideString FX_GetXMLContent(FX_BSTR bsSpace, CXML_Element* pxmlElement, FX_BSTR bsTag, FX_WSTR wsName)\r
83 {\r
84     CXML_Element* pDatePattern = NULL;\r
85     FX_INT32 nCount = pxmlElement->CountElements(bsSpace, bsTag);\r
86     FX_INT32 i = 0;\r
87     for (; i < nCount; i++) {\r
88         pDatePattern = pxmlElement->GetElement(bsSpace, bsTag, i);\r
89         if (pDatePattern->GetAttrValue(FX_BSTRC("name")) == wsName) {\r
90             break;\r
91         }\r
92     }\r
93     if (i < nCount && pDatePattern) {\r
94         return pDatePattern->GetContent(0);\r
95     }\r
96     return L"";\r
97 }\r
98 void CFX_Locale::GetNumbericSymbol(FX_LOCALENUMSYMBOL eType, CFX_WideString& wsNumSymbol) const\r
99 {\r
100     if (!m_pElement) {\r
101         return;\r
102     }\r
103     CFX_ByteString bsSpace;\r
104     CFX_WideString wsName = gs_LocalNumberSymbols[eType];\r
105     CXML_Element* pNumberSymbols = m_pElement->GetElement(bsSpace, FX_BSTRC("numberSymbols"));\r
106     if (!pNumberSymbols) {\r
107         return;\r
108     }\r
109     wsNumSymbol = FX_GetXMLContent(bsSpace, pNumberSymbols, FX_BSTRC("numberSymbol"), wsName);\r
110 }\r
111 void CFX_Locale::GetDateTimeSymbols(CFX_WideString& wsDtSymbol) const\r
112 {\r
113     if (!m_pElement) {\r
114         return;\r
115     }\r
116     CFX_ByteString bsSpace;\r
117     CXML_Element* pNumberSymbols = m_pElement->GetElement(bsSpace, FX_BSTRC("dateTimeSymbols"));\r
118     if (!pNumberSymbols) {\r
119         return;\r
120     }\r
121     wsDtSymbol = pNumberSymbols->GetContent(0);\r
122 }\r
123 static void FX_GetCalendarSymbol(CXML_Element* pXmlElement, const CFX_ByteString &symbol_type, FX_INT32 index, FX_BOOL bAbbr, CFX_WideString &wsName)\r
124 {\r
125     CFX_ByteString bsSpace;\r
126     CFX_ByteString pstrSymbolNames = symbol_type + FX_BSTRC("Names");\r
127     CXML_Element* pChild = pXmlElement->GetElement(bsSpace, FX_BSTRC("calendarSymbols"));\r
128     if (!pChild) {\r
129         return;\r
130     }\r
131     CXML_Element* pSymbolNames = pChild->GetElement(bsSpace, pstrSymbolNames);\r
132     if (!pSymbolNames) {\r
133         return;\r
134     }\r
135     if (pSymbolNames->GetAttrInteger(FX_BSTRC("abbr")) != bAbbr) {\r
136         pSymbolNames = pChild->GetElement(bsSpace, pstrSymbolNames, 1);\r
137     }\r
138     if (pSymbolNames && pSymbolNames->GetAttrInteger(FX_BSTRC("abbr")) == bAbbr) {\r
139         CXML_Element* pSymbolName = pSymbolNames->GetElement(bsSpace, symbol_type, index);\r
140         if (pSymbolName) {\r
141             wsName = pSymbolName->GetContent(0);\r
142         }\r
143     }\r
144 }\r
145 void CFX_Locale::GetMonthName(FX_INT32 nMonth, CFX_WideString& wsMonthName, FX_BOOL bAbbr ) const\r
146 {\r
147     if (!m_pElement) {\r
148         return;\r
149     }\r
150     FX_GetCalendarSymbol(m_pElement, "month", nMonth, bAbbr, wsMonthName);\r
151 }\r
152 void CFX_Locale::GetDayName(FX_INT32 nWeek, CFX_WideString& wsDayName, FX_BOOL bAbbr ) const\r
153 {\r
154     if (!m_pElement) {\r
155         return;\r
156     }\r
157     FX_GetCalendarSymbol(m_pElement, "day", nWeek, bAbbr, wsDayName);\r
158 }\r
159 void CFX_Locale::GetMeridiemName(CFX_WideString& wsMeridiemName, FX_BOOL bAM ) const\r
160 {\r
161     if (!m_pElement) {\r
162         return;\r
163     }\r
164     FX_GetCalendarSymbol(m_pElement, "meridiem", bAM ? 0 : 1, FALSE, wsMeridiemName);\r
165 }\r
166 static FX_INT32 FX_ParseTimeZone(FX_LPCWSTR pStr, FX_INT32 iLen, FX_TIMEZONE& tz)\r
167 {\r
168     tz.tzHour = 0;\r
169     tz.tzMinute = 0;\r
170     if (iLen < 0) {\r
171         return 0;\r
172     }\r
173     FX_INT32 iStart = 1;\r
174     FX_INT32 iEnd = iStart + 2;\r
175     while (iStart < iLen && iStart < iEnd) {\r
176         tz.tzHour = tz.tzHour * 10 + pStr[iStart++] - '0';\r
177     }\r
178     if (iStart < iLen && pStr[iStart] == ':') {\r
179         iStart++;\r
180     }\r
181     iEnd = iStart + 2;\r
182     while (iStart < iLen && iStart < iEnd) {\r
183         tz.tzMinute = tz.tzMinute * 10 + pStr[iStart++] - '0';\r
184     }\r
185     if (pStr[0] == '-') {\r
186         tz.tzHour = -tz.tzHour;\r
187     }\r
188     return iStart;\r
189 }\r
190 void CFX_Locale::GetTimeZone(FX_TIMEZONE& tz) const\r
191 {\r
192     tz.tzHour = 0;\r
193     tz.tzMinute = 0;\r
194     if (!m_pElement) {\r
195         return;\r
196     }\r
197     CXML_Element* pxmlTimeZone = m_pElement->GetElement("", FX_BSTRC("timeZone"));\r
198     if (pxmlTimeZone) {\r
199         CFX_WideString wsTimeZone = pxmlTimeZone->GetContent(0);\r
200         FX_ParseTimeZone(wsTimeZone, wsTimeZone.GetLength(), tz);\r
201     }\r
202 }\r
203 void CFX_Locale::GetEraName(CFX_WideString& wsEraName, FX_BOOL bAD ) const\r
204 {\r
205     if (!m_pElement) {\r
206         return;\r
207     }\r
208     FX_GetCalendarSymbol(m_pElement, "era", bAD ? 0 : 1, FALSE, wsEraName);\r
209 }\r
210 static void FX_GetPattern(CXML_Element* pXmlElement, const CFX_ByteString& bsCategory, const CFX_WideString& wsSubCategory, CFX_WideString& wsPattern)\r
211 {\r
212     CFX_ByteString bsSpace;\r
213     CXML_Element* pDatePatterns = pXmlElement->GetElement(bsSpace, bsCategory + "s");\r
214     if (!pDatePatterns) {\r
215         return;\r
216     }\r
217     wsPattern = FX_GetXMLContent(bsSpace, pDatePatterns, bsCategory, wsSubCategory);\r
218 }\r
219 static void FX_GetDateTimePattern(CXML_Element* pXmlElement, const CFX_ByteString& bsCategory, FX_LOCALEDATETIMESUBCATEGORY eType, CFX_WideString& wsPattern)\r
220 {\r
221     CFX_WideString wsType = g_FXLocaleDateTimeSubCatData[eType].pName;\r
222     FX_GetPattern(pXmlElement, bsCategory, wsType, wsPattern);\r
223 }\r
224 void CFX_Locale::GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY eType, CFX_WideString& wsPattern) const\r
225 {\r
226     if (!m_pElement) {\r
227         return;\r
228     }\r
229     FX_GetDateTimePattern(m_pElement, "datePattern", eType, wsPattern);\r
230 }\r
231 void CFX_Locale::GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY eType, CFX_WideString& wsPattern) const\r
232 {\r
233     if (!m_pElement) {\r
234         return;\r
235     }\r
236     FX_GetDateTimePattern(m_pElement, "timePattern", eType, wsPattern);\r
237 }\r
238 void CFX_Locale::GetNumPattern(FX_LOCALENUMSUBCATEGORY eType, CFX_WideString& wsPattern) const\r
239 {\r
240     CFX_WideString wsType = g_FXLocaleNumSubCatData[eType].pName;\r
241     FX_GetPattern(m_pElement, "numberPattern", wsType, wsPattern);\r
242 }\r
243 static FX_BOOL FX_IsDigit(FX_WCHAR c)\r
244 {\r
245     return c >= '0' && c <= '9';\r
246 }\r
247 static FX_BOOL FX_IsAlpha(FX_WCHAR c)\r
248 {\r
249     return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');\r
250 }\r
251 static FX_BOOL FX_IsSpace(FX_WCHAR c)\r
252 {\r
253     return (c == 0x20) || (c == 0x0d) || (c == 0x0a) || (c == 0x09);\r
254 }\r
255 static const FX_FLOAT gs_fraction_scales[] = {0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f,\r
256                                               0.0000001f, 0.00000001f, 0.000000001f, 0.0000000001f, 0.00000000001f\r
257                                              };\r
258 static const FX_INT32 gs_fraction_count = sizeof(gs_fraction_scales) / sizeof(FX_FLOAT);\r
259 class CFX_LCNumeric : public CFX_Object\r
260 {\r
261 public:\r
262     CFX_LCNumeric();\r
263     CFX_LCNumeric(FX_INT64 integral, FX_DWORD fractional = 0, FX_INT32 exponent = 0);\r
264     CFX_LCNumeric(FX_FLOAT dbRetValue);\r
265     CFX_LCNumeric(double dbvalue);\r
266     CFX_LCNumeric(CFX_WideString& wsNumeric);\r
267 \r
268     FX_FLOAT                            GetFloat() const;\r
269     double                                      GetDouble() const;\r
270     CFX_WideString                      ToString() const;\r
271     CFX_WideString                      ToString(FX_INT32 nTreading, FX_BOOL bTrimTailZeros) const;\r
272     FX_INT64                            m_Integral;\r
273     FX_DWORD                            m_Fractional;\r
274 #ifdef FX_NUM_DOUBLE\r
275     CFX_WideString                      m_wsValue;\r
276 #endif\r
277     FX_INT32                            m_Exponent;\r
278 };\r
279 static FX_BOOL FX_WStringToNumeric(const CFX_WideString& wsValue, CFX_LCNumeric& lcnum)\r
280 {\r
281     FX_INT64 *pIntegral = &lcnum.m_Integral;\r
282     FX_DWORD *pFractional = &lcnum.m_Fractional;\r
283     FX_INT32 *pExponent = &lcnum.m_Exponent;\r
284     *pIntegral = 0;\r
285     *pFractional = 0;\r
286     *pExponent = 0;\r
287 #ifdef FX_NUM_DOUBLE\r
288     lcnum.m_wsValue.Empty();\r
289 #endif\r
290     if (wsValue.IsEmpty()) {\r
291         return FALSE;\r
292     }\r
293     const FX_INT32 nIntegralMaxLen = 17;\r
294     FX_INT32 cc = 0;\r
295     FX_BOOL bNegative = FALSE, bExpSign = FALSE;\r
296     FX_LPCWSTR str = (FX_LPCWSTR)wsValue;\r
297     FX_INT32 len = wsValue.GetLength();\r
298     while (cc < len && FX_IsSpace(str[cc])) {\r
299         cc++;\r
300     }\r
301     if (cc >= len) {\r
302         return FALSE;\r
303     }\r
304     if (str[cc] == '+') {\r
305         cc++;\r
306     } else if (str[cc] == '-') {\r
307         bNegative = TRUE;\r
308         cc++;\r
309     }\r
310     FX_INT32 nIntegralLen = 0;\r
311     while (cc < len) {\r
312         if (str[cc] == '.') {\r
313             break;\r
314         }\r
315         if (!FX_IsDigit(str[cc])) {\r
316             if ((str[cc] == 'E' || str[cc] == 'e')) {\r
317                 break;\r
318             } else {\r
319                 return FALSE;\r
320             }\r
321         }\r
322         if (nIntegralLen < nIntegralMaxLen) {\r
323             *pIntegral = *pIntegral * 10 + str[cc] - '0';\r
324             nIntegralLen++;\r
325         }\r
326         cc ++;\r
327     }\r
328     *pIntegral = bNegative ? -*pIntegral : *pIntegral;\r
329     if (cc < len && str[cc] == '.') {\r
330         int scale = 0;\r
331         double fraction = 0.0;\r
332         cc ++;\r
333         while (cc < len) {\r
334             if (scale >= gs_fraction_count) {\r
335                 while (cc < len) {\r
336                     if (!FX_IsDigit(str[cc])) {\r
337                         break;\r
338                     }\r
339                     cc++;\r
340                 }\r
341             }\r
342             if (!FX_IsDigit(str[cc])) {\r
343                 if ((str[cc] == 'E' || str[cc] == 'e')) {\r
344                     break;\r
345                 } else {\r
346                     return FALSE;\r
347                 }\r
348             }\r
349             fraction += gs_fraction_scales[scale] * (str[cc] - '0');\r
350             scale ++;\r
351             cc ++;\r
352         }\r
353         *pFractional = (FX_DWORD)(fraction * 4294967296.0);\r
354     }\r
355     if (cc < len && (str[cc] == 'E' || str[cc] == 'e')) {\r
356         cc ++;\r
357         if (cc < len) {\r
358             if (str[cc] == '+') {\r
359                 cc++;\r
360             } else if (str[cc] == '-') {\r
361                 bExpSign = TRUE;\r
362                 cc++;\r
363             }\r
364         }\r
365         while (cc < len) {\r
366             if (FX_IsDigit(str[cc])) {\r
367                 return FALSE;\r
368             }\r
369             *pExponent = *pExponent * 10 + str[cc] - '0';\r
370             cc ++;\r
371         }\r
372         *pExponent = bExpSign ? -*pExponent : *pExponent;\r
373     }\r
374 #ifdef FX_NUM_DOUBLE\r
375     else {\r
376         lcnum.m_wsValue = wsValue;\r
377     }\r
378 #endif\r
379     return TRUE;\r
380 }\r
381 CFX_LCNumeric::CFX_LCNumeric()\r
382 {\r
383     m_Integral = 0;\r
384     m_Fractional = 0;\r
385     m_Exponent = 0;\r
386 }\r
387 CFX_LCNumeric::CFX_LCNumeric(FX_INT64 integral, FX_DWORD fractional , FX_INT32 exponent )\r
388 {\r
389     m_Integral = integral;\r
390     m_Fractional = fractional;\r
391     m_Exponent = exponent;\r
392 }\r
393 CFX_LCNumeric::CFX_LCNumeric(FX_FLOAT dbRetValue)\r
394 {\r
395     m_Integral = (FX_INT64)dbRetValue;\r
396     m_Fractional = (FX_DWORD)(((dbRetValue > 0) ? (dbRetValue - m_Integral) : (m_Integral - dbRetValue)) * 4294967296);\r
397     m_Exponent = 0;\r
398 }\r
399 CFX_LCNumeric::CFX_LCNumeric(double dbvalue)\r
400 {\r
401     m_Integral = (FX_INT64)dbvalue;\r
402     m_Fractional = (FX_DWORD)(((dbvalue > 0) ? (dbvalue - m_Integral) : (m_Integral - dbvalue)) * 4294967296);\r
403     m_Exponent = 0;\r
404 }\r
405 CFX_LCNumeric::CFX_LCNumeric(CFX_WideString& wsNumeric)\r
406 {\r
407     FX_WStringToNumeric(wsNumeric, *this);\r
408 }\r
409 FX_FLOAT CFX_LCNumeric::GetFloat() const\r
410 {\r
411     FX_FLOAT dbRetValue = m_Fractional / 4294967296.0f;\r
412     dbRetValue = m_Integral + (m_Integral >= 0 ? dbRetValue : -dbRetValue);\r
413     if (m_Exponent != 0) {\r
414         dbRetValue *= FXSYS_pow(10, (FX_FLOAT)m_Exponent);\r
415     }\r
416     return dbRetValue;\r
417 }\r
418 double CFX_LCNumeric::GetDouble() const\r
419 {\r
420     double value = m_Fractional / 4294967296.0;\r
421     value = m_Integral + (m_Integral >= 0 ? value : -value);\r
422     if (m_Exponent != 0) {\r
423         value *= FXSYS_pow(10, (FX_FLOAT)m_Exponent);\r
424     }\r
425     return value;\r
426 }\r
427 CFX_WideString CFX_LCNumeric::ToString() const\r
428 {\r
429     return ToString(8, TRUE);\r
430 }\r
431 CFX_WideString CFX_LCNumeric::ToString(FX_INT32 nTreading, FX_BOOL bTrimTailZeros) const\r
432 {\r
433 #ifdef FX_NUM_DOUBLE\r
434     CFX_WideString wsResult;\r
435     if (!m_wsValue.IsEmpty()) {\r
436         const FX_INT32 nIntegralMaxLen = 17;\r
437         FX_INT32 cc = 0;\r
438         FX_BOOL bNegative = FALSE, bExpSign = FALSE;\r
439         FX_LPCWSTR str = (FX_LPCWSTR)m_wsValue;\r
440         FX_INT32 len = m_wsValue.GetLength();\r
441         while (cc < len && FX_IsSpace(str[cc])) {\r
442             cc++;\r
443         }\r
444         if (cc >= len) {\r
445             return wsResult;\r
446         }\r
447         if (str[cc] == '+') {\r
448             cc++;\r
449         } else if (str[cc] == '-') {\r
450             bNegative = TRUE;\r
451             cc++;\r
452         }\r
453         FX_INT32 nIntegralLen = 0;\r
454         while (cc < len) {\r
455             if (str[cc] == '.') {\r
456                 break;\r
457             }\r
458             if (!FX_IsDigit(str[cc])) {\r
459                 if ((str[cc] == 'E' || str[cc] == 'e')) {\r
460                     break;\r
461                 } else {\r
462                     return wsResult;\r
463                 }\r
464             }\r
465             if (nIntegralLen < nIntegralMaxLen) {\r
466                 *pIntegral = *pIntegral * 10 + str[cc] - '0';\r
467                 nIntegralLen++;\r
468             }\r
469             cc ++;\r
470         }\r
471         *pIntegral = bNegative ? -*pIntegral : *pIntegral;\r
472         if (cc < len && str[cc] == '.') {\r
473             int scale = 0;\r
474             double fraction = 0.0;\r
475             cc ++;\r
476             while (cc < len) {\r
477                 if (scale >= gs_fraction_count) {\r
478                     while (cc < len) {\r
479                         if (!FX_IsDigit(str[cc])) {\r
480                             break;\r
481                         }\r
482                         cc++;\r
483                     }\r
484                 }\r
485                 if (!FX_IsDigit(str[cc])) {\r
486                     if ((str[cc] == 'E' || str[cc] == 'e')) {\r
487                         break;\r
488                     } else {\r
489                         return FALSE;\r
490                     }\r
491                 }\r
492                 fraction += gs_fraction_scales[scale] * (str[cc] - '0');\r
493                 scale ++;\r
494                 cc ++;\r
495             }\r
496             *pFractional = (FX_DWORD)(fraction * 4294967296.0);\r
497         }\r
498     }\r
499     double dbValeu = GetDouble();\r
500     FX_INT64 iInte = (FX_INT64)dbValeu;\r
501     wsResult.Format((FX_LPCWSTR)L"%l", (FX_INT64)iInte);\r
502     if (m_Fractional) {\r
503         CFX_WideString wsFormat;\r
504         wsFormat.Format((FX_LPCWSTR)L"%%.%dG", nTreading);\r
505         double dblMantissa = (dbValeu > 0) ? (dbValeu - iInte) : (iInte - dbValeu);\r
506         CFX_WideString wsFrac;\r
507         wsFrac.Format((FX_LPCWSTR)wsFormat, dblMantissa);\r
508         wsResult += CFX_WideStringC((FX_LPCWSTR)wsFrac + 1, wsFrac.GetLength() - 1);\r
509         if (bTrimTailZeros && nTreading > 0) {\r
510             wsResult.TrimRight(L"0");\r
511             wsResult.TrimRight(L".");\r
512         }\r
513     }\r
514 #endif\r
515     CFX_WideString wsFormat;\r
516     wsFormat.Format((FX_LPCWSTR)L"%%.%df", nTreading);\r
517     CFX_WideString wsResult;\r
518     wsResult.Format(FX_LPCWSTR(wsFormat), GetDouble());\r
519     if (bTrimTailZeros && nTreading > 0) {\r
520         wsResult.TrimRight(L"0");\r
521         wsResult.TrimRight(L".");\r
522     }\r
523     return wsResult;\r
524 }\r
525 IFX_FormatString* IFX_FormatString::Create(IFX_LocaleMgr* pLocaleMgr, FX_BOOL bUseLCID)\r
526 {\r
527     if (!pLocaleMgr) {\r
528         return NULL;\r
529     }\r
530     return FX_NEW CFX_FormatString(pLocaleMgr, bUseLCID);\r
531 }\r
532 CFX_FormatString::CFX_FormatString(IFX_LocaleMgr* pLocaleMgr, FX_BOOL bUseLCID)\r
533     : m_pLocaleMgr(pLocaleMgr)\r
534     , m_bUseLCID(bUseLCID)\r
535 {\r
536 }\r
537 CFX_FormatString::~CFX_FormatString()\r
538 {\r
539 }\r
540 void CFX_FormatString::SplitFormatString(const CFX_WideString& wsFormatString, CFX_WideStringArray& wsPatterns)\r
541 {\r
542     FX_INT32 iStrLen = wsFormatString.GetLength();\r
543     FX_LPCWSTR pStr = (FX_LPCWSTR)wsFormatString;\r
544     FX_LPCWSTR pToken = pStr;\r
545     FX_LPCWSTR pEnd = pStr + iStrLen;\r
546     FX_BOOL iQuote = FALSE;\r
547     while (TRUE) {\r
548         if (pStr >= pEnd) {\r
549             CFX_WideString sub(pToken, pStr - pToken);\r
550             wsPatterns.Add(sub);\r
551             return;\r
552         } else if (*pStr == '\'') {\r
553             iQuote = !iQuote;\r
554         } else if (*pStr == L'|' && !iQuote) {\r
555             CFX_WideString sub(pToken, pStr - pToken);\r
556             wsPatterns.Add(sub);\r
557             pToken = pStr + 1;\r
558         }\r
559         pStr ++;\r
560     }\r
561 }\r
562 static CFX_WideString FX_GetLiteralText(FX_LPCWSTR pStrPattern, FX_INT32 &iPattern, FX_INT32 iLenPattern)\r
563 {\r
564     CFX_WideString wsOutput;\r
565     if (pStrPattern[iPattern] != '\'') {\r
566         return wsOutput;\r
567     }\r
568     iPattern++;\r
569     FX_INT32 iQuote = 1;\r
570     while (iPattern < iLenPattern) {\r
571         if (pStrPattern[iPattern] == '\'') {\r
572             iQuote++;\r
573             if ((iPattern + 1 >= iLenPattern) || ((pStrPattern[iPattern + 1] != '\'') && (iQuote % 2 == 0))) {\r
574                 break;\r
575             } else {\r
576                 iQuote++;\r
577             }\r
578             iPattern++;\r
579         } else if (pStrPattern[iPattern] == '\\' && (iPattern + 1 < iLenPattern) && pStrPattern[iPattern + 1] == 'u') {\r
580             FX_INT32 iKeyValue = 0;\r
581             iPattern += 2;\r
582             FX_INT32 i = 0;\r
583             while (iPattern < iLenPattern && i++ < 4) {\r
584                 FX_WCHAR ch = pStrPattern[iPattern++];\r
585                 if ((ch >= '0' && ch <= '9')) {\r
586                     iKeyValue = iKeyValue * 16 + ch - '0';\r
587                 } else if ((ch >= 'a' && ch <= 'f')) {\r
588                     iKeyValue = iKeyValue * 16 + ch - 'a' + 10;\r
589                 } else if ((ch >= 'A' && ch <= 'F')) {\r
590                     iKeyValue = iKeyValue * 16 + ch - 'A' + 10;\r
591                 }\r
592             }\r
593             if (iKeyValue != 0) {\r
594                 wsOutput += (FX_WCHAR)(iKeyValue & 0x0000FFFF);\r
595             }\r
596             continue;\r
597         }\r
598         wsOutput += pStrPattern[iPattern++];\r
599     }\r
600     return wsOutput;\r
601 }\r
602 static CFX_WideString FX_GetLiteralTextReverse(FX_LPCWSTR pStrPattern, FX_INT32 &iPattern)\r
603 {\r
604     CFX_WideString wsOutput;\r
605     if (pStrPattern[iPattern] != '\'') {\r
606         return wsOutput;\r
607     }\r
608     iPattern--;\r
609     FX_INT32 iQuote = 1;\r
610     while (iPattern >= 0) {\r
611         if (pStrPattern[iPattern] == '\'') {\r
612             iQuote++;\r
613             if (iPattern - 1 >= 0 || ((pStrPattern[iPattern - 1] != '\'') && (iQuote % 2 == 0))) {\r
614                 break;\r
615             } else {\r
616                 iQuote++;\r
617             }\r
618             iPattern--;\r
619         } else if (pStrPattern[iPattern] == '\\' && pStrPattern[iPattern + 1] == 'u') {\r
620             iPattern--;\r
621             FX_INT32 iKeyValue = 0;\r
622             FX_INT32 iLen = wsOutput.GetLength();\r
623             FX_INT32 i = 1;\r
624             for (; i < iLen && i < 5; i++) {\r
625                 FX_WCHAR ch = wsOutput[i];\r
626                 if ((ch >= '0' && ch <= '9')) {\r
627                     iKeyValue = iKeyValue * 16 + ch - '0';\r
628                 } else if ((ch >= 'a' && ch <= 'f')) {\r
629                     iKeyValue = iKeyValue * 16 + ch - 'a' + 10;\r
630                 } else if ((ch >= 'A' && ch <= 'F')) {\r
631                     iKeyValue = iKeyValue * 16 + ch - 'A' + 10;\r
632                 }\r
633             }\r
634             if (iKeyValue != 0) {\r
635                 wsOutput.Delete(0, i);\r
636                 wsOutput = (FX_WCHAR)(iKeyValue & 0x0000FFFF) + wsOutput;\r
637             }\r
638             continue;\r
639         }\r
640         wsOutput = pStrPattern[iPattern--] + wsOutput;\r
641     }\r
642     return wsOutput;\r
643 }\r
644 FX_LOCALECATEGORY CFX_FormatString::GetCategory(const CFX_WideString& wsPattern)\r
645 {\r
646     FX_LOCALECATEGORY eCategory = FX_LOCALECATEGORY_Unknown;\r
647     FX_INT32 ccf = 0;\r
648     FX_INT32 iLenf = wsPattern.GetLength();\r
649     FX_LPCWSTR pStr = (FX_LPCWSTR)wsPattern;\r
650     FX_BOOL bBraceOpen = FALSE;\r
651     while (ccf < iLenf) {\r
652         if (pStr[ccf] == '\'') {\r
653             FX_GetLiteralText(pStr, ccf, iLenf);\r
654         } else if (!bBraceOpen && FX_Local_Find(gs_wsConstChars, pStr[ccf]) < 0) {\r
655             CFX_WideString wsCategory(pStr[ccf]);\r
656             ccf++;\r
657             while (TRUE) {\r
658                 if (ccf == iLenf) {\r
659                     return eCategory;\r
660                 }\r
661                 if ( pStr[ccf] == '.' || pStr[ccf] == '(') {\r
662                     break;\r
663                 }\r
664                 if (pStr[ccf] == '{') {\r
665                     bBraceOpen = TRUE;\r
666                     break;\r
667                 }\r
668                 wsCategory += pStr[ccf];\r
669                 ccf++;\r
670             }\r
671             FX_DWORD dwHash = FX_HashCode_String_GetW(wsCategory, wsCategory.GetLength());\r
672             if (dwHash == FX_LOCALECATEGORY_DateHash) {\r
673                 if (eCategory == FX_LOCALECATEGORY_Time) {\r
674                     return FX_LOCALECATEGORY_DateTime;\r
675                 }\r
676                 eCategory = FX_LOCALECATEGORY_Date;\r
677             } else if (dwHash == FX_LOCALECATEGORY_TimeHash) {\r
678                 if (eCategory == FX_LOCALECATEGORY_Date) {\r
679                     return FX_LOCALECATEGORY_DateTime;\r
680                 }\r
681                 eCategory = FX_LOCALECATEGORY_Time;\r
682             } else if (dwHash == FX_LOCALECATEGORY_DateTimeHash) {\r
683                 return FX_LOCALECATEGORY_DateTime;\r
684             } else if (dwHash == FX_LOCALECATEGORY_TextHash) {\r
685                 return FX_LOCALECATEGORY_Text;\r
686             } else if (dwHash == FX_LOCALECATEGORY_NumHash) {\r
687                 return FX_LOCALECATEGORY_Num;\r
688             } else if (dwHash == FX_LOCALECATEGORY_ZeroHash) {\r
689                 return FX_LOCALECATEGORY_Zero;\r
690             } else if (dwHash == FX_LOCALECATEGORY_NullHash) {\r
691                 return FX_LOCALECATEGORY_Null;\r
692             }\r
693         } else if (pStr[ccf] == '}') {\r
694             bBraceOpen = FALSE;\r
695         }\r
696         ccf++;\r
697     }\r
698     return eCategory;\r
699 }\r
700 static FX_WORD FX_WStringToLCID(FX_LPCWSTR pstrLCID)\r
701 {\r
702     if (!pstrLCID) {\r
703         return 0;\r
704     }\r
705     wchar_t* pEnd;\r
706     return (FX_WORD)wcstol((wchar_t*)pstrLCID, &pEnd, 16);\r
707 }\r
708 FX_WORD CFX_FormatString::GetLCID(const CFX_WideString& wsPattern)\r
709 {\r
710     return FX_WStringToLCID(GetLocaleName(wsPattern));\r
711 }\r
712 CFX_WideString CFX_FormatString::GetLocaleName(const CFX_WideString& wsPattern)\r
713 {\r
714     FX_INT32 ccf = 0;\r
715     FX_INT32 iLenf = wsPattern.GetLength();\r
716     FX_LPCWSTR pStr = (FX_LPCWSTR)wsPattern;\r
717     while (ccf < iLenf) {\r
718         if (pStr[ccf] == '\'') {\r
719             FX_GetLiteralText(pStr, ccf, iLenf);\r
720         } else if (pStr[ccf] == '(') {\r
721             ccf++;\r
722             CFX_WideString wsLCID;\r
723             while (ccf < iLenf && pStr[ccf] != ')') {\r
724                 wsLCID += pStr[ccf++];\r
725             }\r
726             return wsLCID;\r
727         }\r
728         ccf++;\r
729     }\r
730     return CFX_WideString();\r
731 }\r
732 IFX_Locale* CFX_FormatString::GetTextFormat(const CFX_WideString &wsPattern, FX_WSTR wsCategory, CFX_WideString& wsPurgePattern)\r
733 {\r
734     IFX_Locale* pLocale = NULL;\r
735     FX_INT32 ccf = 0;\r
736     FX_INT32 iLenf = wsPattern.GetLength();\r
737     FX_LPCWSTR pStr = (FX_LPCWSTR)wsPattern;\r
738     FX_BOOL bBrackOpen = FALSE;\r
739     while (ccf < iLenf) {\r
740         if (pStr[ccf] == '\'') {\r
741             FX_INT32 iCurChar = ccf;\r
742             FX_GetLiteralText(pStr, ccf, iLenf);\r
743             wsPurgePattern += CFX_WideStringC(pStr + iCurChar, ccf - iCurChar + 1);\r
744         } else if (!bBrackOpen && FX_Local_Find(gs_wsConstChars, pStr[ccf]) < 0) {\r
745             CFX_WideString wsSearchCategory(pStr[ccf]);\r
746             ccf++;\r
747             while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' && pStr[ccf] != '(') {\r
748                 wsSearchCategory += pStr[ccf];\r
749                 ccf++;\r
750             }\r
751             if (wsSearchCategory != wsCategory) {\r
752                 continue;\r
753             }\r
754             while (ccf < iLenf) {\r
755                 if (pStr[ccf] == '(') {\r
756                     ccf++;\r
757                     CFX_WideString wsLCID;\r
758                     while (ccf < iLenf && pStr[ccf] != ')')     {\r
759                         wsLCID += pStr[ccf++];\r
760                     }\r
761                     pLocale = GetPatternLocale(wsLCID);\r
762                 } else if (pStr[ccf] == '{') {\r
763                     bBrackOpen = TRUE;\r
764                     break;\r
765                 }\r
766                 ccf++;\r
767             }\r
768         } else if (pStr[ccf] != '}') {\r
769             wsPurgePattern += pStr[ccf];\r
770         }\r
771         ccf++;\r
772     }\r
773     if (!bBrackOpen) {\r
774         wsPurgePattern = wsPattern;\r
775     }\r
776     if (!pLocale) {\r
777         pLocale = m_pLocaleMgr->GetDefLocale();\r
778     }\r
779     return pLocale;\r
780 }\r
781 #define FX_NUMSTYLE_Percent             0x01\r
782 #define FX_NUMSTYLE_Exponent    0x02\r
783 #define FX_NUMSTYLE_DotVorv             0x04\r
784 IFX_Locale* CFX_FormatString::GetNumericFormat(const CFX_WideString& wsPattern, FX_INT32& iDotIndex, FX_DWORD& dwStyle, CFX_WideString& wsPurgePattern)\r
785 {\r
786     dwStyle = 0;\r
787     IFX_Locale* pLocale = NULL;\r
788     FX_INT32 ccf = 0;\r
789     FX_INT32 iLenf = wsPattern.GetLength();\r
790     FX_LPCWSTR pStr = (FX_LPCWSTR)wsPattern;\r
791     FX_BOOL bFindDot = FALSE;\r
792     FX_BOOL bBrackOpen = FALSE;\r
793     while (ccf < iLenf) {\r
794         if (pStr[ccf] == '\'') {\r
795             FX_INT32 iCurChar = ccf;\r
796             FX_GetLiteralText(pStr, ccf, iLenf);\r
797             wsPurgePattern += CFX_WideStringC(pStr + iCurChar, ccf - iCurChar + 1);\r
798         } else if (!bBrackOpen && FX_Local_Find(gs_wsConstChars, pStr[ccf]) < 0) {\r
799             CFX_WideString wsCategory(pStr[ccf]);\r
800             ccf++;\r
801             while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' && pStr[ccf] != '(') {\r
802                 wsCategory += pStr[ccf];\r
803                 ccf++;\r
804             }\r
805             if (wsCategory != FX_WSTRC(L"num")) {\r
806                 bBrackOpen = TRUE;\r
807                 ccf = 0;\r
808                 continue;\r
809             }\r
810             while (ccf < iLenf) {\r
811                 if (pStr[ccf] == '(') {\r
812                     ccf++;\r
813                     CFX_WideString wsLCID;\r
814                     while (ccf < iLenf && pStr[ccf] != ')')     {\r
815                         wsLCID += pStr[ccf++];\r
816                     }\r
817                     pLocale = GetPatternLocale(wsLCID);\r
818                 } else if (pStr[ccf] == '{') {\r
819                     bBrackOpen = TRUE;\r
820                     break;\r
821                 } else if (pStr[ccf] == '.') {\r
822                     CFX_WideString wsSubCategory;\r
823                     ccf++;\r
824                     while (ccf < iLenf && pStr[ccf] != '(' && pStr[ccf] != '{') {\r
825                         wsSubCategory += pStr[ccf++];\r
826                     }\r
827                     FX_DWORD dwSubHash = FX_HashCode_String_GetW(wsSubCategory, wsSubCategory.GetLength());\r
828                     FX_LOCALENUMSUBCATEGORY eSubCategory = FX_LOCALENUMPATTERN_Decimal;\r
829                     for (FX_INT32 i = 0; i < g_iFXLocaleNumSubCatCount; i++) {\r
830                         if (g_FXLocaleNumSubCatData[i].uHash == dwSubHash) {\r
831                             eSubCategory = (FX_LOCALENUMSUBCATEGORY)g_FXLocaleNumSubCatData[i].eSubCategory;\r
832                             break;\r
833                         }\r
834                     }\r
835                     wsSubCategory.Empty();\r
836                     if (!pLocale) {\r
837                         pLocale = m_pLocaleMgr->GetDefLocale();\r
838                     }\r
839                     FXSYS_assert(pLocale != NULL);\r
840                     pLocale->GetNumPattern(eSubCategory, wsSubCategory);\r
841                     iDotIndex = wsSubCategory.Find('.');\r
842                     if (iDotIndex > 0) {\r
843                         iDotIndex += wsPurgePattern.GetLength() ;\r
844                         bFindDot = TRUE;\r
845                         dwStyle |= FX_NUMSTYLE_DotVorv;\r
846                     }\r
847                     wsPurgePattern += wsSubCategory;\r
848                     if (eSubCategory == FX_LOCALENUMPATTERN_Percent) {\r
849                         dwStyle |= FX_NUMSTYLE_Percent;\r
850                     }\r
851                     continue;\r
852                 }\r
853                 ccf++;\r
854             }\r
855         } else if (pStr[ccf] == 'E') {\r
856             dwStyle |= FX_NUMSTYLE_Exponent;\r
857             wsPurgePattern += pStr[ccf];\r
858         } else if (pStr[ccf] == '%') {\r
859             dwStyle |= FX_NUMSTYLE_Percent;\r
860             wsPurgePattern += pStr[ccf];\r
861         } else if (pStr[ccf] != '}') {\r
862             wsPurgePattern += pStr[ccf];\r
863         }\r
864         if (!bFindDot) {\r
865             if (pStr[ccf] == '.' || pStr[ccf] == 'V' || pStr[ccf] == 'v') {\r
866                 bFindDot = TRUE;\r
867                 iDotIndex = wsPurgePattern.GetLength() - 1;\r
868                 dwStyle |= FX_NUMSTYLE_DotVorv;\r
869             }\r
870         }\r
871         ccf++;\r
872     }\r
873     if (!bFindDot) {\r
874         iDotIndex = wsPurgePattern.GetLength();\r
875     }\r
876     if (!pLocale) {\r
877         pLocale = m_pLocaleMgr->GetDefLocale();\r
878     }\r
879     return pLocale;\r
880 }\r
881 static FX_BOOL FX_GetNumericDotIndex(const CFX_WideString& wsNum, const CFX_WideString& wsDotSymbol, FX_INT32 &iDotIndex)\r
882 {\r
883     FX_INT32 ccf = 0;\r
884     FX_INT32 iLenf = wsNum.GetLength();\r
885     FX_LPCWSTR pStr = (FX_LPCWSTR)wsNum;\r
886     FX_INT32 iLenDot = wsDotSymbol.GetLength();\r
887     while (ccf < iLenf) {\r
888         if (pStr[ccf] == '\'') {\r
889             FX_GetLiteralText(pStr, ccf, iLenf);\r
890         } else if (ccf + iLenDot <= iLenf && !FXSYS_wcsncmp(pStr + ccf, (FX_LPCWSTR)wsDotSymbol, iLenDot)) {\r
891             iDotIndex = ccf;\r
892             return TRUE;\r
893         }\r
894         ccf++;\r
895     }\r
896     iDotIndex = wsNum.Find('.');\r
897     if (iDotIndex < 0) {\r
898         iDotIndex = iLenf;\r
899         return FALSE;\r
900     }\r
901     return TRUE;\r
902 }\r
903 FX_BOOL CFX_FormatString::ParseText(const CFX_WideString& wsSrcText, const CFX_WideString& wsPattern, CFX_WideString& wsValue)\r
904 {\r
905     wsValue.Empty();\r
906     if (wsSrcText.IsEmpty() || wsPattern.IsEmpty()) {\r
907         return FALSE;\r
908     }\r
909     CFX_WideString wsTextFormat;\r
910     IFX_Locale* pLocale = GetTextFormat(wsPattern, FX_WSTRC(L"text"), wsTextFormat);\r
911     if (wsTextFormat.IsEmpty()) {\r
912         return FALSE;\r
913     }\r
914     FX_INT32 iText = 0, iPattern = 0;\r
915     FX_LPCWSTR pStrText = (FX_LPCWSTR)wsSrcText;\r
916     FX_INT32 iLenText = wsSrcText.GetLength();\r
917     FX_LPCWSTR pStrPattern = (FX_LPCWSTR)wsTextFormat;\r
918     FX_INT32 iLenPattern = wsTextFormat.GetLength();\r
919     while (iPattern < iLenPattern && iText < iLenText) {\r
920         switch (pStrPattern[iPattern]) {\r
921             case '\'': {\r
922                     CFX_WideString wsLiteral = FX_GetLiteralText(pStrPattern, iPattern, iLenPattern);\r
923                     FX_INT32 iLiteralLen = wsLiteral.GetLength();\r
924                     if (iText + iLiteralLen > iLenText || FXSYS_wcsncmp(pStrText + iText, (FX_LPCWSTR)wsLiteral, iLiteralLen)) {\r
925                         wsValue = wsSrcText;\r
926                         return FALSE;\r
927                     }\r
928                     iText += iLiteralLen;\r
929                     iPattern++;\r
930                     break;\r
931                 }\r
932             case 'A':\r
933                 if (FX_IsAlpha(pStrText[iText])) {\r
934                     wsValue += pStrText[iText];\r
935                     iText++;\r
936                 }\r
937                 iPattern++;\r
938                 break;\r
939             case 'X':\r
940                 wsValue += pStrText[iText];\r
941                 iText++;\r
942                 iPattern++;\r
943                 break;\r
944             case 'O':\r
945             case '0':\r
946                 if (FX_IsDigit(pStrText[iText]) || FX_IsAlpha(pStrText[iText])) {\r
947                     wsValue += pStrText[iText];\r
948                     iText++;\r
949                 }\r
950                 iPattern++;\r
951                 break;\r
952             case '9':\r
953                 if (FX_IsDigit(pStrText[iText])) {\r
954                     wsValue += pStrText[iText];\r
955                     iText++;\r
956                 }\r
957                 iPattern++;\r
958                 break;\r
959             default:\r
960                 if (pStrPattern[iPattern] != pStrText[iText]) {\r
961                     wsValue = wsSrcText;\r
962                     return FALSE;\r
963                 }\r
964                 iPattern++;\r
965                 iText++;\r
966                 break;\r
967         }\r
968     }\r
969     return iPattern == iLenPattern && iText == iLenText;\r
970 }\r
971 FX_BOOL CFX_FormatString::ParseNum(const CFX_WideString& wsSrcNum, const CFX_WideString& wsPattern, FX_FLOAT &fValue)\r
972 {\r
973     fValue = 0.0f;\r
974     if (wsSrcNum.IsEmpty() || wsPattern.IsEmpty()) {\r
975         return FALSE;\r
976     }\r
977     FX_INT32 dot_index_f = -1;\r
978     FX_DWORD dwFormatStyle = 0;\r
979     CFX_WideString wsNumFormat;\r
980     IFX_Locale* pLocale = GetNumericFormat(wsPattern, dot_index_f, dwFormatStyle, wsNumFormat);\r
981     if (!pLocale || wsNumFormat.IsEmpty()) {\r
982         return FALSE;\r
983     }\r
984     FX_INT32 iExponent = 0;\r
985     CFX_WideString wsDotSymbol;\r
986     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal, wsDotSymbol);\r
987     FX_INT32 iDotLen = wsDotSymbol.GetLength();\r
988     CFX_WideString wsGroupSymbol;\r
989     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping, wsGroupSymbol);\r
990     FX_INT32 iGroupLen = wsGroupSymbol.GetLength();\r
991     CFX_WideString wsMinus;\r
992     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinus);\r
993     FX_INT32 iMinusLen = wsMinus.GetLength();\r
994     int cc = 0, ccf = 0;\r
995     FX_LPCWSTR str = (FX_LPCWSTR)wsSrcNum;\r
996     int len = wsSrcNum.GetLength();\r
997     FX_LPCWSTR strf = (FX_LPCWSTR)wsNumFormat;\r
998     int lenf = wsNumFormat.GetLength();\r
999     double dbRetValue = 0;\r
1000     double coeff = 1;\r
1001     FX_BOOL bHavePercentSymbol = FALSE;\r
1002     FX_BOOL bNeg = FALSE;\r
1003     FX_BOOL bReverseParse = FALSE;\r
1004     FX_INT32 dot_index = 0;\r
1005     if (!FX_GetNumericDotIndex(wsSrcNum, wsDotSymbol, dot_index) && (dwFormatStyle & FX_NUMSTYLE_DotVorv)) {\r
1006         bReverseParse = TRUE;\r
1007     }\r
1008     bReverseParse = FALSE;\r
1009     if (bReverseParse) {\r
1010         ccf = lenf - 1;\r
1011         cc = len - 1;\r
1012         while (ccf > dot_index_f && cc >= 0) {\r
1013             switch (strf[ccf]) {\r
1014                 case '\'': {\r
1015                         CFX_WideString wsLiteral = FX_GetLiteralTextReverse(strf, ccf);\r
1016                         FX_INT32 iLiteralLen = wsLiteral.GetLength();\r
1017                         cc -= iLiteralLen - 1;\r
1018                         if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsLiteral, iLiteralLen)) {\r
1019                             return FALSE;\r
1020                         }\r
1021                         cc--;\r
1022                         ccf--;\r
1023                         break;\r
1024                     }\r
1025                 case '9':\r
1026                     if (!FX_IsDigit(str[cc])) {\r
1027                         return FALSE;\r
1028                     }\r
1029                     dbRetValue = dbRetValue * coeff + (str[cc] - '0') * 0.1;\r
1030                     coeff *= 0.1;\r
1031                     cc--;\r
1032                     ccf--;\r
1033                     break;\r
1034                 case 'z':\r
1035                     if (cc >= 0) {\r
1036                         dbRetValue = dbRetValue * coeff + (str[cc] - '0') * 0.1;\r
1037                         coeff *= 0.1;\r
1038                         cc--;\r
1039                     }\r
1040                     ccf--;\r
1041                     break;\r
1042                 case 'Z':\r
1043                     if (str[cc] != ' ') {\r
1044                         dbRetValue = dbRetValue * coeff + (str[cc] - '0') * 0.1;\r
1045                         coeff *= 0.1;\r
1046                     }\r
1047                     cc--;\r
1048                     ccf--;\r
1049                     break;\r
1050                 case 'S':\r
1051                     if (str[cc] == '+' || str[cc] == ' ') {\r
1052                         cc--;\r
1053                     } else {\r
1054                         cc -= iMinusLen - 1;\r
1055                         if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1056                             return FALSE;\r
1057                         }\r
1058                         cc--;\r
1059                         bNeg = TRUE;\r
1060                     }\r
1061                     ccf--;\r
1062                     break;\r
1063                 case 's':\r
1064                     if (str[cc] == '+') {\r
1065                         cc--;\r
1066                     } else {\r
1067                         cc -= iMinusLen - 1;\r
1068                         if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1069                             return FALSE;\r
1070                         }\r
1071                         cc--;\r
1072                         bNeg = TRUE;\r
1073                     }\r
1074                     ccf--;\r
1075                     break;\r
1076                 case 'E': {\r
1077                         if (cc >= dot_index) {\r
1078                             return FALSE;\r
1079                         }\r
1080                         FX_BOOL bExpSign = FALSE;\r
1081                         while (cc >= 0) {\r
1082                             if (str[cc] == 'E' || str[cc] == 'e') {\r
1083                                 break;\r
1084                             }\r
1085                             if (FX_IsDigit(str[cc])) {\r
1086                                 iExponent = iExponent + (str[cc] - '0') * 10;\r
1087                                 cc--;\r
1088                                 continue;\r
1089                             } else if (str[cc] == '+') {\r
1090                                 cc--;\r
1091                                 continue;\r
1092                             } else if (cc - iMinusLen + 1 > 0 && !FXSYS_wcsncmp(str + (cc - iMinusLen + 1), (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1093                                 bExpSign = TRUE;\r
1094                                 cc -= iMinusLen;\r
1095                             } else {\r
1096                                 return FALSE;\r
1097                             }\r
1098                         }\r
1099                         cc --;\r
1100                         iExponent = bExpSign ? -iExponent : iExponent;\r
1101                         ccf--;\r
1102                     }\r
1103                     break;\r
1104                 case '$': {\r
1105                         CFX_WideString wsSymbol;\r
1106                         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);\r
1107                         FX_INT32 iSymbolLen = wsSymbol.GetLength();\r
1108                         cc -= iSymbolLen - 1;\r
1109                         if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsSymbol, iSymbolLen)) {\r
1110                             return FALSE;\r
1111                         }\r
1112                         cc--;\r
1113                         ccf--;\r
1114                     }\r
1115                     break;\r
1116                 case 'r':\r
1117                     if (ccf - 1 >= 0 && strf[ccf - 1] == 'c') {\r
1118                         if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {\r
1119                             bNeg = TRUE;\r
1120                             cc -= 2;\r
1121                         }\r
1122                         ccf -= 2;\r
1123                     } else {\r
1124                         ccf --;\r
1125                     }\r
1126                     break;\r
1127                 case 'R':\r
1128                     if (ccf - 1 >= 0 && strf[ccf - 1] == 'C') {\r
1129                         if (str[cc] == ' ') {\r
1130                             cc++;\r
1131                         } else if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {\r
1132                             bNeg = TRUE;\r
1133                             cc -= 2;\r
1134                         }\r
1135                         ccf -= 2;\r
1136                     } else {\r
1137                         ccf--;\r
1138                     }\r
1139                     break;\r
1140                 case 'b':\r
1141                     if (ccf - 1 >= 0 && strf[ccf - 1] == 'd') {\r
1142                         if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {\r
1143                             bNeg = TRUE;\r
1144                             cc -= 2;\r
1145                         }\r
1146                         ccf -= 2;\r
1147                     } else {\r
1148                         ccf --;\r
1149                     }\r
1150                     break;\r
1151                 case 'B':\r
1152                     if (ccf - 1 >= 0 && strf[ccf - 1] == 'D') {\r
1153                         if (str[cc] == ' ') {\r
1154                             cc++;\r
1155                         } else if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {\r
1156                             bNeg = TRUE;\r
1157                             cc -= 2;\r
1158                         }\r
1159                         ccf -= 2;\r
1160                     } else {\r
1161                         ccf--;\r
1162                     }\r
1163                     break;\r
1164                 case '.':\r
1165                 case 'V':\r
1166                 case 'v':\r
1167                     return FALSE;\r
1168                 case '%': {\r
1169                         CFX_WideString wsSymbol;\r
1170                         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);\r
1171                         FX_INT32 iSysmbolLen = wsSymbol.GetLength();\r
1172                         cc -= iSysmbolLen - 1;\r
1173                         if (cc < 0  || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsSymbol, iSysmbolLen)) {\r
1174                             return FALSE;\r
1175                         }\r
1176                         cc--;\r
1177                         ccf--;\r
1178                         bHavePercentSymbol = TRUE;\r
1179                     }\r
1180                     break;\r
1181                 case '8':\r
1182                     while (ccf < lenf && strf[ccf] == '8') {\r
1183                         ccf++;\r
1184                     }\r
1185                     while (cc < len && FX_IsDigit(str[cc])) {\r
1186                         dbRetValue = (str[cc] - '0') * coeff + dbRetValue;\r
1187                         coeff *= 0.1;\r
1188                         cc++;\r
1189                     }\r
1190                     break;\r
1191                 case ',': {\r
1192                         if (cc >= 0) {\r
1193                             cc -= iGroupLen - 1;\r
1194                             if (cc >= 0 && FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsGroupSymbol, iGroupLen) == 0) {\r
1195                                 cc--;\r
1196                             } else {\r
1197                                 cc += iGroupLen - 1;\r
1198                             }\r
1199                         }\r
1200                         ccf--;\r
1201                     }\r
1202                     break;\r
1203                 case '(':\r
1204                     if (str[cc] == L'(') {\r
1205                         bNeg = TRUE;\r
1206                     } else if (str[cc] != L' ') {\r
1207                         return FALSE;\r
1208                     }\r
1209                     cc--;\r
1210                     ccf--;\r
1211                     break;\r
1212                 case ')':\r
1213                     if (str[cc] == L')') {\r
1214                         bNeg = TRUE;\r
1215                     } else if (str[cc] != L' ') {\r
1216                         return FALSE;\r
1217                     }\r
1218                     cc--;\r
1219                     ccf--;\r
1220                     break;\r
1221                 default:\r
1222                     if (strf[ccf] != str[cc]) {\r
1223                         return FALSE;\r
1224                     }\r
1225                     cc--;\r
1226                     ccf--;\r
1227             }\r
1228         }\r
1229         dot_index = cc + 1;\r
1230     }\r
1231     ccf = dot_index_f - 1;\r
1232     cc = dot_index - 1;\r
1233     coeff = 1;\r
1234     while (ccf >= 0 && cc >= 0) {\r
1235         switch (strf[ccf]) {\r
1236             case '\'': {\r
1237                     CFX_WideString wsLiteral = FX_GetLiteralTextReverse(strf, ccf);\r
1238                     FX_INT32 iLiteralLen = wsLiteral.GetLength();\r
1239                     cc -= iLiteralLen - 1;\r
1240                     if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsLiteral, iLiteralLen)) {\r
1241                         return FALSE;\r
1242                     }\r
1243                     cc--;\r
1244                     ccf--;\r
1245                     break;\r
1246                 }\r
1247             case '9':\r
1248                 if (!FX_IsDigit(str[cc])) {\r
1249                     return FALSE;\r
1250                 }\r
1251                 dbRetValue = dbRetValue + (str[cc] - '0') * coeff;\r
1252                 coeff *= 10;\r
1253                 cc--;\r
1254                 ccf--;\r
1255                 break;\r
1256             case 'z':\r
1257                 if (FX_IsDigit(str[cc])) {\r
1258                     dbRetValue = dbRetValue + (str[cc] - '0') * coeff;\r
1259                     coeff *= 10;\r
1260                     cc--;\r
1261                 }\r
1262                 ccf--;\r
1263                 break;\r
1264             case 'Z':\r
1265                 if (str[cc] != ' ') {\r
1266                     if (FX_IsDigit(str[cc])) {\r
1267                         dbRetValue = dbRetValue + (str[cc] - '0') * coeff;\r
1268                         coeff *= 10;\r
1269                         cc--;\r
1270                     }\r
1271                 } else {\r
1272                     cc--;\r
1273                 }\r
1274                 ccf--;\r
1275                 break;\r
1276             case 'S':\r
1277                 if (str[cc] == '+' || str[cc] == ' ') {\r
1278                     cc--;\r
1279                 } else {\r
1280                     cc -= iMinusLen - 1;\r
1281                     if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1282                         return FALSE;\r
1283                     }\r
1284                     cc--;\r
1285                     bNeg = TRUE;\r
1286                 }\r
1287                 ccf--;\r
1288                 break;\r
1289             case 's':\r
1290                 if (str[cc] == '+') {\r
1291                     cc--;\r
1292                 } else {\r
1293                     cc -= iMinusLen - 1;\r
1294                     if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1295                         return FALSE;\r
1296                     }\r
1297                     cc--;\r
1298                     bNeg = TRUE;\r
1299                 }\r
1300                 ccf--;\r
1301                 break;\r
1302             case 'E': {\r
1303                     if (cc >= dot_index) {\r
1304                         return FALSE;\r
1305                     }\r
1306                     FX_BOOL bExpSign = FALSE;\r
1307                     while (cc >= 0) {\r
1308                         if (str[cc] == 'E' || str[cc] == 'e') {\r
1309                             break;\r
1310                         }\r
1311                         if (FX_IsDigit(str[cc])) {\r
1312                             iExponent = iExponent + (str[cc] - '0') * 10;\r
1313                             cc--;\r
1314                             continue;\r
1315                         } else if (str[cc] == '+') {\r
1316                             cc--;\r
1317                             continue;\r
1318                         } else if (cc - iMinusLen + 1 > 0 && !FXSYS_wcsncmp(str + (cc - iMinusLen + 1), (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1319                             bExpSign = TRUE;\r
1320                             cc -= iMinusLen;\r
1321                         } else {\r
1322                             return FALSE;\r
1323                         }\r
1324                     }\r
1325                     cc --;\r
1326                     iExponent = bExpSign ? -iExponent : iExponent;\r
1327                     ccf--;\r
1328                 }\r
1329                 break;\r
1330             case '$': {\r
1331                     CFX_WideString wsSymbol;\r
1332                     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);\r
1333                     FX_INT32 iSymbolLen = wsSymbol.GetLength();\r
1334                     cc -= iSymbolLen - 1;\r
1335                     if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsSymbol, iSymbolLen)) {\r
1336                         return FALSE;\r
1337                     }\r
1338                     cc--;\r
1339                     ccf--;\r
1340                 }\r
1341                 break;\r
1342             case 'r':\r
1343                 if (ccf - 1 >= 0 && strf[ccf - 1] == 'c') {\r
1344                     if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {\r
1345                         bNeg = TRUE;\r
1346                         cc -= 2;\r
1347                     }\r
1348                     ccf -= 2;\r
1349                 } else {\r
1350                     ccf --;\r
1351                 }\r
1352                 break;\r
1353             case 'R':\r
1354                 if (ccf - 1 >= 0 && strf[ccf - 1] == 'C') {\r
1355                     if (str[cc] == ' ') {\r
1356                         cc++;\r
1357                     } else if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {\r
1358                         bNeg = TRUE;\r
1359                         cc -= 2;\r
1360                     }\r
1361                     ccf -= 2;\r
1362                 } else {\r
1363                     ccf--;\r
1364                 }\r
1365                 break;\r
1366             case 'b':\r
1367                 if (ccf - 1 >= 0 && strf[ccf - 1] == 'd') {\r
1368                     if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {\r
1369                         bNeg = TRUE;\r
1370                         cc -= 2;\r
1371                     }\r
1372                     ccf -= 2;\r
1373                 } else {\r
1374                     ccf --;\r
1375                 }\r
1376                 break;\r
1377             case 'B':\r
1378                 if (ccf - 1 >= 0 && strf[ccf - 1] == 'D') {\r
1379                     if (str[cc] == ' ') {\r
1380                         cc++;\r
1381                     } else if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {\r
1382                         bNeg = TRUE;\r
1383                         cc -= 2;\r
1384                     }\r
1385                     ccf -= 2;\r
1386                 } else {\r
1387                     ccf--;\r
1388                 }\r
1389                 break;\r
1390             case '.':\r
1391             case 'V':\r
1392             case 'v':\r
1393                 return FALSE;\r
1394             case '%': {\r
1395                     CFX_WideString wsSymbol;\r
1396                     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);\r
1397                     FX_INT32 iSysmbolLen = wsSymbol.GetLength();\r
1398                     cc -= iSysmbolLen - 1;\r
1399                     if (cc < 0  || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsSymbol, iSysmbolLen)) {\r
1400                         return FALSE;\r
1401                     }\r
1402                     cc--;\r
1403                     ccf--;\r
1404                     bHavePercentSymbol = TRUE;\r
1405                 }\r
1406                 break;\r
1407             case '8':\r
1408                 return FALSE;\r
1409             case ',': {\r
1410                     if (cc >= 0) {\r
1411                         cc -= iGroupLen - 1;\r
1412                         if (cc >= 0 && FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsGroupSymbol, iGroupLen) == 0) {\r
1413                             cc--;\r
1414                         } else {\r
1415                             cc += iGroupLen - 1;\r
1416                         }\r
1417                     }\r
1418                     ccf--;\r
1419                 }\r
1420                 break;\r
1421             case '(':\r
1422                 if (str[cc] == L'(') {\r
1423                     bNeg = TRUE;\r
1424                 } else if (str[cc] != L' ') {\r
1425                     return FALSE;\r
1426                 }\r
1427                 cc--;\r
1428                 ccf--;\r
1429                 break;\r
1430             case ')':\r
1431                 if (str[cc] == L')') {\r
1432                     bNeg = TRUE;\r
1433                 } else if (str[cc] != L' ') {\r
1434                     return FALSE;\r
1435                 }\r
1436                 cc--;\r
1437                 ccf--;\r
1438                 break;\r
1439             default:\r
1440                 if (strf[ccf] != str[cc]) {\r
1441                     return FALSE;\r
1442                 }\r
1443                 cc--;\r
1444                 ccf--;\r
1445         }\r
1446     }\r
1447     if (cc >= 0) {\r
1448         return FALSE;\r
1449     }\r
1450     if (!bReverseParse) {\r
1451         ccf = dot_index_f + 1;\r
1452         cc = (dot_index == len) ? len : dot_index + 1;\r
1453         coeff = 0.1;\r
1454         while (cc < len && ccf < lenf) {\r
1455             switch (strf[ccf]) {\r
1456                 case '\'': {\r
1457                         CFX_WideString wsLiteral = FX_GetLiteralText(strf, ccf, lenf);\r
1458                         FX_INT32 iLiteralLen = wsLiteral.GetLength();\r
1459                         if (cc + iLiteralLen > len || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsLiteral, iLiteralLen)) {\r
1460                             return FALSE;\r
1461                         }\r
1462                         cc += iLiteralLen;\r
1463                         ccf++;\r
1464                         break;\r
1465                     }\r
1466                 case '9':\r
1467                     if (!FX_IsDigit(str[cc])) {\r
1468                         return FALSE;\r
1469                     }\r
1470                     {\r
1471                         dbRetValue = dbRetValue + (str[cc] - '0') * coeff;\r
1472                         coeff *= 0.1;\r
1473                     }\r
1474                     cc++;\r
1475                     ccf++;\r
1476                     break;\r
1477                 case 'z':\r
1478                     if (FX_IsDigit(str[cc])) {\r
1479                         dbRetValue = dbRetValue + (str[cc] - '0') * coeff;\r
1480                         coeff *= 0.1;\r
1481                         cc++;\r
1482                     }\r
1483                     ccf++;\r
1484                     break;\r
1485                 case 'Z':\r
1486                     if (str[cc] != ' ') {\r
1487                         if (FX_IsDigit(str[cc])) {\r
1488                             dbRetValue = dbRetValue + (str[cc] - '0') * coeff;\r
1489                             coeff *= 0.1;\r
1490                             cc++;\r
1491                         }\r
1492                     } else {\r
1493                         cc++;\r
1494                     }\r
1495                     ccf++;\r
1496                     break;\r
1497                 case 'S':\r
1498                     if (str[cc] == '+' || str[cc] == ' ') {\r
1499                         cc++;\r
1500                     } else {\r
1501                         if (cc + iMinusLen > len || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1502                             return FALSE;\r
1503                         }\r
1504                         bNeg = TRUE;\r
1505                         cc += iMinusLen;\r
1506                     }\r
1507                     ccf++;\r
1508                     break;\r
1509                 case 's':\r
1510                     if (str[cc] == '+') {\r
1511                         cc++;\r
1512                     } else {\r
1513                         if (cc + iMinusLen > len || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1514                             return FALSE;\r
1515                         }\r
1516                         bNeg = TRUE;\r
1517                         cc += iMinusLen;\r
1518                     }\r
1519                     ccf++;\r
1520                     break;\r
1521                 case 'E': {\r
1522                         if (cc >= len || (str[cc] != 'E' && str[cc] != 'e')) {\r
1523                             return FALSE;\r
1524                         }\r
1525                         FX_BOOL bExpSign = FALSE;\r
1526                         cc ++;\r
1527                         if (cc < len) {\r
1528                             if (str[cc] == '+') {\r
1529                                 cc++;\r
1530                             } else if (str[cc] == '-') {\r
1531                                 bExpSign = TRUE;\r
1532                                 cc++;\r
1533                             }\r
1534                         }\r
1535                         while (cc < len) {\r
1536                             if (!FX_IsDigit(str[cc])) {\r
1537                                 break;\r
1538                             }\r
1539                             iExponent = iExponent * 10 + str[cc] - '0';\r
1540                             cc ++;\r
1541                         }\r
1542                         iExponent = bExpSign ? -iExponent : iExponent;\r
1543                         ccf++;\r
1544                     }\r
1545                     break;\r
1546                 case '$': {\r
1547                         CFX_WideString wsSymbol;\r
1548                         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);\r
1549                         FX_INT32 iSymbolLen = wsSymbol.GetLength();\r
1550                         if (cc + iSymbolLen > len || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsSymbol, iSymbolLen)) {\r
1551                             return FALSE;\r
1552                         }\r
1553                         cc += iSymbolLen;\r
1554                         ccf++;\r
1555                     }\r
1556                     break;\r
1557                 case 'c':\r
1558                     if (ccf + 1 < lenf && strf[ccf + 1] == 'r') {\r
1559                         if (str[cc] == 'C' && cc + 1 < len && str[cc + 1] == 'R') {\r
1560                             bNeg = TRUE;\r
1561                             cc += 2;\r
1562                         }\r
1563                         ccf += 2;\r
1564                     }\r
1565                     break;\r
1566                 case 'C':\r
1567                     if (ccf + 1 < lenf && strf[ccf + 1] == 'R') {\r
1568                         if (str[cc] == ' ') {\r
1569                             cc++;\r
1570                         } else if (str[cc] == 'C' && cc + 1 < len && str[cc + 1] == 'R') {\r
1571                             bNeg = TRUE;\r
1572                             cc += 2;\r
1573                         }\r
1574                         ccf += 2;\r
1575                     }\r
1576                     break;\r
1577                 case 'd':\r
1578                     if (ccf + 1 < lenf && strf[ccf + 1] == 'b') {\r
1579                         if (str[cc] == 'D' && cc + 1 < len && str[cc + 1] == 'B') {\r
1580                             bNeg = TRUE;\r
1581                             cc += 2;\r
1582                         }\r
1583                         ccf += 2;\r
1584                     }\r
1585                     break;\r
1586                 case 'D':\r
1587                     if (ccf + 1 < lenf && strf[ccf + 1] == 'B') {\r
1588                         if (str[cc] == ' ') {\r
1589                             cc++;\r
1590                         } else if (str[cc] == 'D' && cc + 1 < len && str[cc + 1] == 'B') {\r
1591                             bNeg = TRUE;\r
1592                             cc += 2;\r
1593                         }\r
1594                         ccf += 2;\r
1595                     }\r
1596                     break;\r
1597                 case '.':\r
1598                 case 'V':\r
1599                 case 'v':\r
1600                     return FALSE;\r
1601                 case '%': {\r
1602                         CFX_WideString wsSymbol;\r
1603                         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);\r
1604                         FX_INT32 iSysmbolLen = wsSymbol.GetLength();\r
1605                         if (cc + iSysmbolLen <= len && !FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsSymbol, iSysmbolLen)) {\r
1606                             cc += iSysmbolLen;\r
1607                         }\r
1608                         ccf++;\r
1609                         bHavePercentSymbol = TRUE;\r
1610                     }\r
1611                     break;\r
1612                 case '8': {\r
1613                         while (ccf < lenf && strf[ccf] == '8') {\r
1614                             ccf++;\r
1615                         }\r
1616                         while (cc < len && FX_IsDigit(str[cc])) {\r
1617                             dbRetValue = (str[cc] - '0') * coeff + dbRetValue;\r
1618                             coeff *= 0.1;\r
1619                             cc++;\r
1620                         }\r
1621                     }\r
1622                     break;\r
1623                 case ',': {\r
1624                         if (cc + iGroupLen <= len && FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsGroupSymbol, iGroupLen) == 0) {\r
1625                             cc += iGroupLen;\r
1626                         }\r
1627                         ccf++;\r
1628                     }\r
1629                     break;\r
1630                 case '(':\r
1631                     if (str[cc] == L'(') {\r
1632                         bNeg = TRUE;\r
1633                     } else if (str[cc] != L' ') {\r
1634                         return FALSE;\r
1635                     }\r
1636                     cc++;\r
1637                     ccf++;\r
1638                     break;\r
1639                 case ')':\r
1640                     if (str[cc] == L')') {\r
1641                         bNeg = TRUE;\r
1642                     } else if (str[cc] != L' ') {\r
1643                         return FALSE;\r
1644                     }\r
1645                     cc++;\r
1646                     ccf++;\r
1647                     break;\r
1648                 default:\r
1649                     if (strf[ccf] != str[cc]) {\r
1650                         return FALSE;\r
1651                     }\r
1652                     cc++;\r
1653                     ccf++;\r
1654             }\r
1655         }\r
1656         if (cc != len) {\r
1657             return FALSE;\r
1658         }\r
1659     }\r
1660     if (iExponent) {\r
1661         dbRetValue *= FXSYS_pow(10, (FX_FLOAT)iExponent);\r
1662     }\r
1663     if (bHavePercentSymbol) {\r
1664         dbRetValue /= 100.0;\r
1665     }\r
1666     if (bNeg) {\r
1667         dbRetValue = -dbRetValue;\r
1668     }\r
1669     fValue = (FX_FLOAT)dbRetValue;\r
1670     return TRUE;\r
1671 }\r
1672 void  FX_ParseNumString(const CFX_WideString& wsNum, CFX_WideString& wsResult)\r
1673 {\r
1674     FX_INT32 iCount = wsNum.GetLength();\r
1675     FX_LPCWSTR pStr = (FX_LPCWSTR)wsNum;\r
1676     FX_LPWSTR pDst = wsResult.GetBuffer(iCount);\r
1677     FX_INT32 nIndex = 0;\r
1678     FX_BOOL bMinus = FALSE;\r
1679     FX_INT32 i = 0;\r
1680     for (i = 0; i < iCount; i++) {\r
1681         FX_WCHAR wc = pStr[i];\r
1682         if (wc == '.') {\r
1683             break;\r
1684         }\r
1685         if ((wc == L'0' || wc == L' ' || wc == '+') && nIndex == 0) {\r
1686             continue;\r
1687         }\r
1688         if (wc == '-') {\r
1689             pDst[nIndex++] = wc;\r
1690             bMinus = TRUE;\r
1691             continue;\r
1692         }\r
1693         if (wc == L'0' && nIndex == 1 && bMinus) {\r
1694             continue;\r
1695         }\r
1696         pDst[nIndex++] = wc;\r
1697     }\r
1698     if (bMinus && nIndex == 1) {\r
1699         pDst[nIndex++] = '0';\r
1700     }\r
1701     if (nIndex == 0) {\r
1702         wsResult.ReleaseBuffer(0);\r
1703         pDst = wsResult.GetBuffer(iCount + 1);\r
1704         pDst[nIndex++] = '0';\r
1705     }\r
1706     FX_INT32 j = 0;\r
1707     for (j = iCount - 1; j > i; j--) {\r
1708         FX_WCHAR wc = pStr[j];\r
1709         if (wc != L'0' && wc != L' ') {\r
1710             break;\r
1711         }\r
1712     }\r
1713     if (j > i) {\r
1714         pDst[nIndex++] = '.';\r
1715         FXSYS_wcsncpy(pDst + nIndex, pStr + i + 1, j - i);\r
1716         nIndex += j - i;\r
1717     }\r
1718     wsResult.ReleaseBuffer(nIndex);\r
1719 }\r
1720 FX_BOOL CFX_FormatString::ParseNum(const CFX_WideString& wsSrcNum, const CFX_WideString& wsPattern, CFX_WideString &wsValue)\r
1721 {\r
1722     wsValue.Empty();\r
1723     if (wsSrcNum.IsEmpty() || wsPattern.IsEmpty()) {\r
1724         return FALSE;\r
1725     }\r
1726     FX_INT32 dot_index_f = -1;\r
1727     FX_DWORD dwFormatStyle = 0;\r
1728     CFX_WideString wsNumFormat;\r
1729     IFX_Locale* pLocale = GetNumericFormat(wsPattern, dot_index_f, dwFormatStyle, wsNumFormat);\r
1730     if (!pLocale || wsNumFormat.IsEmpty()) {\r
1731         return FALSE;\r
1732     }\r
1733     FX_INT32 iExponent = 0;\r
1734     CFX_WideString wsDotSymbol;\r
1735     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal, wsDotSymbol);\r
1736     FX_INT32 iDotLen = wsDotSymbol.GetLength();\r
1737     CFX_WideString wsGroupSymbol;\r
1738     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping, wsGroupSymbol);\r
1739     FX_INT32 iGroupLen = wsGroupSymbol.GetLength();\r
1740     CFX_WideString wsMinus;\r
1741     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinus);\r
1742     FX_INT32 iMinusLen = wsMinus.GetLength();\r
1743     int cc = 0, ccf = 0;\r
1744     FX_LPCWSTR str = (FX_LPCWSTR)wsSrcNum;\r
1745     int len = wsSrcNum.GetLength();\r
1746     FX_LPCWSTR strf = (FX_LPCWSTR)wsNumFormat;\r
1747     int lenf = wsNumFormat.GetLength();\r
1748     FX_BOOL bHavePercentSymbol = FALSE;\r
1749     FX_BOOL bNeg = FALSE;\r
1750     FX_BOOL bReverseParse = FALSE;\r
1751     FX_INT32 dot_index = 0;\r
1752     if (!FX_GetNumericDotIndex(wsSrcNum, wsDotSymbol, dot_index) && (dwFormatStyle & FX_NUMSTYLE_DotVorv)) {\r
1753         bReverseParse = TRUE;\r
1754     }\r
1755     bReverseParse = FALSE;\r
1756     ccf = dot_index_f - 1;\r
1757     cc = dot_index - 1;\r
1758     while (ccf >= 0 && cc >= 0) {\r
1759         switch (strf[ccf]) {\r
1760             case '\'': {\r
1761                     CFX_WideString wsLiteral = FX_GetLiteralTextReverse(strf, ccf);\r
1762                     FX_INT32 iLiteralLen = wsLiteral.GetLength();\r
1763                     cc -= iLiteralLen - 1;\r
1764                     if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsLiteral, iLiteralLen)) {\r
1765                         return FALSE;\r
1766                     }\r
1767                     cc--;\r
1768                     ccf--;\r
1769                     break;\r
1770                 }\r
1771             case '9':\r
1772                 if (!FX_IsDigit(str[cc])) {\r
1773                     return FALSE;\r
1774                 }\r
1775                 wsValue = CFX_WideStringC(str[cc]) + wsValue;\r
1776                 cc--;\r
1777                 ccf--;\r
1778                 break;\r
1779             case 'z':\r
1780                 if (FX_IsDigit(str[cc])) {\r
1781                     wsValue = CFX_WideStringC(str[cc]) + wsValue;\r
1782                     cc--;\r
1783                 }\r
1784                 ccf--;\r
1785                 break;\r
1786             case 'Z':\r
1787                 if (str[cc] != ' ') {\r
1788                     if (FX_IsDigit(str[cc])) {\r
1789                         wsValue = CFX_WideStringC(str[cc]) + wsValue;\r
1790                         cc--;\r
1791                     }\r
1792                 } else {\r
1793                     cc--;\r
1794                 }\r
1795                 ccf--;\r
1796                 break;\r
1797             case 'S':\r
1798                 if (str[cc] == '+' || str[cc] == ' ') {\r
1799                     cc--;\r
1800                 } else {\r
1801                     cc -= iMinusLen - 1;\r
1802                     if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1803                         return FALSE;\r
1804                     }\r
1805                     cc--;\r
1806                     bNeg = TRUE;\r
1807                 }\r
1808                 ccf--;\r
1809                 break;\r
1810             case 's':\r
1811                 if (str[cc] == '+') {\r
1812                     cc--;\r
1813                 } else {\r
1814                     cc -= iMinusLen - 1;\r
1815                     if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1816                         return FALSE;\r
1817                     }\r
1818                     cc--;\r
1819                     bNeg = TRUE;\r
1820                 }\r
1821                 ccf--;\r
1822                 break;\r
1823             case 'E': {\r
1824                     if (cc >= dot_index) {\r
1825                         return FALSE;\r
1826                     }\r
1827                     FX_BOOL bExpSign = FALSE;\r
1828                     while (cc >= 0) {\r
1829                         if (str[cc] == 'E' || str[cc] == 'e') {\r
1830                             break;\r
1831                         }\r
1832                         if (FX_IsDigit(str[cc])) {\r
1833                             iExponent = iExponent + (str[cc] - '0') * 10;\r
1834                             cc--;\r
1835                             continue;\r
1836                         } else if (str[cc] == '+') {\r
1837                             cc--;\r
1838                             continue;\r
1839                         } else if (cc - iMinusLen + 1 > 0 && !FXSYS_wcsncmp(str + (cc - iMinusLen + 1), (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
1840                             bExpSign = TRUE;\r
1841                             cc -= iMinusLen;\r
1842                         } else {\r
1843                             return FALSE;\r
1844                         }\r
1845                     }\r
1846                     cc --;\r
1847                     iExponent = bExpSign ? -iExponent : iExponent;\r
1848                     ccf--;\r
1849                 }\r
1850                 break;\r
1851             case '$': {\r
1852                     CFX_WideString wsSymbol;\r
1853                     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);\r
1854                     FX_INT32 iSymbolLen = wsSymbol.GetLength();\r
1855                     cc -= iSymbolLen - 1;\r
1856                     if (cc < 0 || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsSymbol, iSymbolLen)) {\r
1857                         return FALSE;\r
1858                     }\r
1859                     cc--;\r
1860                     ccf--;\r
1861                 }\r
1862                 break;\r
1863             case 'r':\r
1864                 if (ccf - 1 >= 0 && strf[ccf - 1] == 'c') {\r
1865                     if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {\r
1866                         bNeg = TRUE;\r
1867                         cc -= 2;\r
1868                     }\r
1869                     ccf -= 2;\r
1870                 } else {\r
1871                     ccf --;\r
1872                 }\r
1873                 break;\r
1874             case 'R':\r
1875                 if (ccf - 1 >= 0 && strf[ccf - 1] == 'C') {\r
1876                     if (str[cc] == ' ') {\r
1877                         cc++;\r
1878                     } else if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {\r
1879                         bNeg = TRUE;\r
1880                         cc -= 2;\r
1881                     }\r
1882                     ccf -= 2;\r
1883                 } else {\r
1884                     ccf--;\r
1885                 }\r
1886                 break;\r
1887             case 'b':\r
1888                 if (ccf - 1 >= 0 && strf[ccf - 1] == 'd') {\r
1889                     if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {\r
1890                         bNeg = TRUE;\r
1891                         cc -= 2;\r
1892                     }\r
1893                     ccf -= 2;\r
1894                 } else {\r
1895                     ccf --;\r
1896                 }\r
1897                 break;\r
1898             case 'B':\r
1899                 if (ccf - 1 >= 0 && strf[ccf - 1] == 'D') {\r
1900                     if (str[cc] == ' ') {\r
1901                         cc++;\r
1902                     } else if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {\r
1903                         bNeg = TRUE;\r
1904                         cc -= 2;\r
1905                     }\r
1906                     ccf -= 2;\r
1907                 } else {\r
1908                     ccf--;\r
1909                 }\r
1910                 break;\r
1911             case '.':\r
1912             case 'V':\r
1913             case 'v':\r
1914                 return FALSE;\r
1915             case '%': {\r
1916                     CFX_WideString wsSymbol;\r
1917                     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);\r
1918                     FX_INT32 iSysmbolLen = wsSymbol.GetLength();\r
1919                     cc -= iSysmbolLen - 1;\r
1920                     if (cc < 0  || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsSymbol, iSysmbolLen)) {\r
1921                         return FALSE;\r
1922                     }\r
1923                     cc--;\r
1924                     ccf--;\r
1925                     bHavePercentSymbol = TRUE;\r
1926                 }\r
1927                 break;\r
1928             case '8':\r
1929                 return FALSE;\r
1930             case ',': {\r
1931                     if (cc >= 0) {\r
1932                         cc -= iGroupLen - 1;\r
1933                         if (cc >= 0 && FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsGroupSymbol, iGroupLen) == 0) {\r
1934                             cc--;\r
1935                         } else {\r
1936                             cc += iGroupLen - 1;\r
1937                         }\r
1938                     }\r
1939                     ccf--;\r
1940                 }\r
1941                 break;\r
1942             case '(':\r
1943                 if (str[cc] == L'(') {\r
1944                     bNeg = TRUE;\r
1945                 } else if (str[cc] != L' ') {\r
1946                     return FALSE;\r
1947                 }\r
1948                 cc--;\r
1949                 ccf--;\r
1950                 break;\r
1951             case ')':\r
1952                 if (str[cc] == L')') {\r
1953                     bNeg = TRUE;\r
1954                 } else if (str[cc] != L' ') {\r
1955                     return FALSE;\r
1956                 }\r
1957                 cc--;\r
1958                 ccf--;\r
1959                 break;\r
1960             default:\r
1961                 if (strf[ccf] != str[cc]) {\r
1962                     return FALSE;\r
1963                 }\r
1964                 cc--;\r
1965                 ccf--;\r
1966         }\r
1967     }\r
1968     if (cc >= 0) {\r
1969         if (str[cc] == '-') {\r
1970             bNeg = TRUE;\r
1971             cc --;\r
1972         }\r
1973         if (cc >= 0) {\r
1974             return FALSE;\r
1975         }\r
1976     }\r
1977     if (dot_index < len && (dwFormatStyle & FX_NUMSTYLE_DotVorv)) {\r
1978         wsValue += '.';\r
1979     }\r
1980     if (!bReverseParse) {\r
1981         ccf = dot_index_f + 1;\r
1982         cc = (dot_index == len) ? len : dot_index + 1;\r
1983         while (cc < len && ccf < lenf) {\r
1984             switch (strf[ccf]) {\r
1985                 case '\'': {\r
1986                         CFX_WideString wsLiteral = FX_GetLiteralText(strf, ccf, lenf);\r
1987                         FX_INT32 iLiteralLen = wsLiteral.GetLength();\r
1988                         if (cc + iLiteralLen > len || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsLiteral, iLiteralLen)) {\r
1989                             return FALSE;\r
1990                         }\r
1991                         cc += iLiteralLen;\r
1992                         ccf++;\r
1993                         break;\r
1994                     }\r
1995                 case '9':\r
1996                     if (!FX_IsDigit(str[cc])) {\r
1997                         return FALSE;\r
1998                     }\r
1999                     {\r
2000                         wsValue += str[cc];\r
2001                     }\r
2002                     cc++;\r
2003                     ccf++;\r
2004                     break;\r
2005                 case 'z':\r
2006                     if (FX_IsDigit(str[cc])) {\r
2007                         wsValue += str[cc];\r
2008                         cc++;\r
2009                     }\r
2010                     ccf++;\r
2011                     break;\r
2012                 case 'Z':\r
2013                     if (str[cc] != ' ') {\r
2014                         if (FX_IsDigit(str[cc])) {\r
2015                             wsValue += str[cc];\r
2016                             cc++;\r
2017                         }\r
2018                     } else {\r
2019                         cc++;\r
2020                     }\r
2021                     ccf++;\r
2022                     break;\r
2023                 case 'S':\r
2024                     if (str[cc] == '+' || str[cc] == ' ') {\r
2025                         cc++;\r
2026                     } else {\r
2027                         if (cc + iMinusLen > len || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
2028                             return FALSE;\r
2029                         }\r
2030                         bNeg = TRUE;\r
2031                         cc += iMinusLen;\r
2032                     }\r
2033                     ccf++;\r
2034                     break;\r
2035                 case 's':\r
2036                     if (str[cc] == '+') {\r
2037                         cc++;\r
2038                     } else {\r
2039                         if (cc + iMinusLen > len || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsMinus, iMinusLen)) {\r
2040                             return FALSE;\r
2041                         }\r
2042                         bNeg = TRUE;\r
2043                         cc += iMinusLen;\r
2044                     }\r
2045                     ccf++;\r
2046                     break;\r
2047                 case 'E': {\r
2048                         if (cc >= len || (str[cc] != 'E' && str[cc] != 'e')) {\r
2049                             return FALSE;\r
2050                         }\r
2051                         FX_BOOL bExpSign = FALSE;\r
2052                         cc ++;\r
2053                         if (cc < len) {\r
2054                             if (str[cc] == '+') {\r
2055                                 cc++;\r
2056                             } else if (str[cc] == '-') {\r
2057                                 bExpSign = TRUE;\r
2058                                 cc++;\r
2059                             }\r
2060                         }\r
2061                         while (cc < len) {\r
2062                             if (!FX_IsDigit(str[cc])) {\r
2063                                 break;\r
2064                             }\r
2065                             iExponent = iExponent * 10 + str[cc] - '0';\r
2066                             cc ++;\r
2067                         }\r
2068                         iExponent = bExpSign ? -iExponent : iExponent;\r
2069                         ccf++;\r
2070                     }\r
2071                     break;\r
2072                 case '$': {\r
2073                         CFX_WideString wsSymbol;\r
2074                         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);\r
2075                         FX_INT32 iSymbolLen = wsSymbol.GetLength();\r
2076                         if (cc + iSymbolLen > len || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsSymbol, iSymbolLen)) {\r
2077                             return FALSE;\r
2078                         }\r
2079                         cc += iSymbolLen;\r
2080                         ccf++;\r
2081                     }\r
2082                     break;\r
2083                 case 'c':\r
2084                     if (ccf + 1 < lenf && strf[ccf + 1] == 'r') {\r
2085                         if (str[cc] == 'C' && cc + 1 < len && str[cc + 1] == 'R') {\r
2086                             bNeg = TRUE;\r
2087                             cc += 2;\r
2088                         }\r
2089                         ccf += 2;\r
2090                     }\r
2091                     break;\r
2092                 case 'C':\r
2093                     if (ccf + 1 < lenf && strf[ccf + 1] == 'R') {\r
2094                         if (str[cc] == ' ') {\r
2095                             cc++;\r
2096                         } else if (str[cc] == 'C' && cc + 1 < len && str[cc + 1] == 'R') {\r
2097                             bNeg = TRUE;\r
2098                             cc += 2;\r
2099                         }\r
2100                         ccf += 2;\r
2101                     }\r
2102                     break;\r
2103                 case 'd':\r
2104                     if (ccf + 1 < lenf && strf[ccf + 1] == 'b') {\r
2105                         if (str[cc] == 'D' && cc + 1 < len && str[cc + 1] == 'B') {\r
2106                             bNeg = TRUE;\r
2107                             cc += 2;\r
2108                         }\r
2109                         ccf += 2;\r
2110                     }\r
2111                     break;\r
2112                 case 'D':\r
2113                     if (ccf + 1 < lenf && strf[ccf + 1] == 'B') {\r
2114                         if (str[cc] == ' ') {\r
2115                             cc++;\r
2116                         } else if (str[cc] == 'D' && cc + 1 < len && str[cc + 1] == 'B') {\r
2117                             bNeg = TRUE;\r
2118                             cc += 2;\r
2119                         }\r
2120                         ccf += 2;\r
2121                     }\r
2122                     break;\r
2123                 case '.':\r
2124                 case 'V':\r
2125                 case 'v':\r
2126                     return FALSE;\r
2127                 case '%': {\r
2128                         CFX_WideString wsSymbol;\r
2129                         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);\r
2130                         FX_INT32 iSysmbolLen = wsSymbol.GetLength();\r
2131                         if (cc + iSysmbolLen <= len && !FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsSymbol, iSysmbolLen)) {\r
2132                             cc += iSysmbolLen;\r
2133                         }\r
2134                         ccf++;\r
2135                         bHavePercentSymbol = TRUE;\r
2136                     }\r
2137                     break;\r
2138                 case '8': {\r
2139                         while (ccf < lenf && strf[ccf] == '8') {\r
2140                             ccf++;\r
2141                         }\r
2142                         while (cc < len && FX_IsDigit(str[cc])) {\r
2143                             wsValue += str[cc];\r
2144                             cc++;\r
2145                         }\r
2146                     }\r
2147                     break;\r
2148                 case ',': {\r
2149                         if (cc + iGroupLen <= len && FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsGroupSymbol, iGroupLen) == 0) {\r
2150                             cc += iGroupLen;\r
2151                         }\r
2152                         ccf++;\r
2153                     }\r
2154                     break;\r
2155                 case '(':\r
2156                     if (str[cc] == L'(') {\r
2157                         bNeg = TRUE;\r
2158                     } else if (str[cc] != L' ') {\r
2159                         return FALSE;\r
2160                     }\r
2161                     cc++;\r
2162                     ccf++;\r
2163                     break;\r
2164                 case ')':\r
2165                     if (str[cc] == L')') {\r
2166                         bNeg = TRUE;\r
2167                     } else if (str[cc] != L' ') {\r
2168                         return FALSE;\r
2169                     }\r
2170                     cc++;\r
2171                     ccf++;\r
2172                     break;\r
2173                 default:\r
2174                     if (strf[ccf] != str[cc]) {\r
2175                         return FALSE;\r
2176                     }\r
2177                     cc++;\r
2178                     ccf++;\r
2179             }\r
2180         }\r
2181         if (cc != len) {\r
2182             return FALSE;\r
2183         }\r
2184     }\r
2185     if (iExponent || bHavePercentSymbol) {\r
2186         CFX_Decimal decimal = CFX_Decimal(wsValue);\r
2187         if (iExponent) {\r
2188             decimal = decimal * CFX_Decimal(FXSYS_pow(10, (FX_FLOAT)iExponent));\r
2189         }\r
2190         if (bHavePercentSymbol) {\r
2191             decimal = decimal / CFX_Decimal(100);\r
2192         }\r
2193         wsValue = decimal;\r
2194     }\r
2195     if (bNeg) {\r
2196         wsValue = CFX_WideStringC('-') + wsValue;\r
2197     }\r
2198     return TRUE;\r
2199 }\r
2200 FX_DATETIMETYPE CFX_FormatString::GetDateTimeFormat(const CFX_WideString& wsPattern, IFX_Locale*& pLocale, CFX_WideString &wsDatePattern, CFX_WideString &wsTimePattern)\r
2201 {\r
2202     pLocale = NULL;\r
2203     CFX_WideString wsTempPattern;\r
2204     FX_LOCALECATEGORY eCategory = FX_LOCALECATEGORY_Unknown;\r
2205     FX_INT32 ccf = 0;\r
2206     FX_INT32 iLenf = wsPattern.GetLength();\r
2207     FX_LPCWSTR pStr = (FX_LPCWSTR)wsPattern;\r
2208     FX_INT32 iFindCategory = 0;\r
2209     FX_BOOL bBraceOpen = FALSE;\r
2210     while (ccf < iLenf) {\r
2211         if (pStr[ccf] == '\'') {\r
2212             FX_INT32 iCurChar = ccf;\r
2213             FX_GetLiteralText(pStr, ccf, iLenf);\r
2214             wsTempPattern += CFX_WideStringC(pStr + iCurChar, ccf - iCurChar + 1);\r
2215         } else if (!bBraceOpen && iFindCategory != 3 && FX_Local_Find(gs_wsConstChars, pStr[ccf]) < 0) {\r
2216             CFX_WideString wsCategory(pStr[ccf]);\r
2217             ccf++;\r
2218             while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' && pStr[ccf] != '(') {\r
2219                 if (pStr[ccf] == 'T') {\r
2220                     wsDatePattern = wsPattern.Left(ccf);\r
2221                     wsTimePattern = wsPattern.Right(wsPattern.GetLength() - ccf);\r
2222                     wsTimePattern.SetAt(0, ' ');\r
2223                     if (!pLocale) {\r
2224                         pLocale = m_pLocaleMgr->GetDefLocale();\r
2225                     }\r
2226                     return FX_DATETIMETYPE_DateTime;\r
2227                 }\r
2228                 wsCategory += pStr[ccf];\r
2229                 ccf++;\r
2230             }\r
2231             if (!(iFindCategory & 1) && wsCategory == FX_WSTRC(L"date")) {\r
2232                 iFindCategory |= 1;\r
2233                 eCategory = FX_LOCALECATEGORY_Date;\r
2234                 if (iFindCategory & 2) {\r
2235                     iFindCategory = 4;\r
2236                 }\r
2237             } else if (!(iFindCategory & 2) && wsCategory == FX_WSTRC(L"time")) {\r
2238                 iFindCategory |= 2;\r
2239                 eCategory = FX_LOCALECATEGORY_Time;\r
2240             } else if (wsCategory == FX_WSTRC(L"datetime")) {\r
2241                 iFindCategory = 3;\r
2242                 eCategory = FX_LOCALECATEGORY_DateTime;\r
2243             } else {\r
2244                 continue;\r
2245             }\r
2246             while (ccf < iLenf) {\r
2247                 if (pStr[ccf] == '(') {\r
2248                     ccf++;\r
2249                     CFX_WideString wsLCID;\r
2250                     while (ccf < iLenf && pStr[ccf] != ')')     {\r
2251                         wsLCID += pStr[ccf++];\r
2252                     }\r
2253                     pLocale = GetPatternLocale(wsLCID);\r
2254                 } else if (pStr[ccf] == '{') {\r
2255                     bBraceOpen = TRUE;\r
2256                     break;\r
2257                 } else if (pStr[ccf] == '.') {\r
2258                     CFX_WideString wsSubCategory;\r
2259                     ccf++;\r
2260                     while (ccf < iLenf && pStr[ccf] != '(' && pStr[ccf] != '{') {\r
2261                         wsSubCategory += pStr[ccf++];\r
2262                     }\r
2263                     FX_DWORD dwSubHash = FX_HashCode_String_GetW(wsSubCategory, wsSubCategory.GetLength());\r
2264                     FX_LOCALEDATETIMESUBCATEGORY eSubCategory = FX_LOCALEDATETIMESUBCATEGORY_Medium;\r
2265                     for (FX_INT32 i = 0; i < g_iFXLocaleDateTimeSubCatCount; i++) {\r
2266                         if (g_FXLocaleDateTimeSubCatData[i].uHash == dwSubHash) {\r
2267                             eSubCategory = (FX_LOCALEDATETIMESUBCATEGORY)g_FXLocaleDateTimeSubCatData[i].eSubCategory;\r
2268                             break;\r
2269                         }\r
2270                     }\r
2271                     if (!pLocale) {\r
2272                         pLocale = m_pLocaleMgr->GetDefLocale();\r
2273                     }\r
2274                     FXSYS_assert(pLocale != NULL);\r
2275                     switch (eCategory) {\r
2276                         case FX_LOCALECATEGORY_Date:\r
2277                             pLocale->GetDatePattern(eSubCategory, wsDatePattern);\r
2278                             wsDatePattern = wsTempPattern + wsDatePattern;\r
2279                             break;\r
2280                         case FX_LOCALECATEGORY_Time:\r
2281                             pLocale->GetTimePattern(eSubCategory, wsTimePattern);\r
2282                             wsTimePattern = wsTempPattern + wsTimePattern;\r
2283                             break;\r
2284                         case FX_LOCALECATEGORY_DateTime:\r
2285                             pLocale->GetDatePattern(eSubCategory, wsDatePattern);\r
2286                             wsDatePattern = wsTempPattern + wsDatePattern;\r
2287                             pLocale->GetTimePattern(eSubCategory, wsTimePattern);\r
2288                             break;\r
2289                         default:\r
2290                             break;\r
2291                     }\r
2292                     wsTempPattern.Empty();\r
2293                     continue;\r
2294                 }\r
2295                 ccf++;\r
2296             }\r
2297         } else if (pStr[ccf] == '}') {\r
2298             bBraceOpen = FALSE;\r
2299             if (!wsTempPattern.IsEmpty()) {\r
2300                 if (eCategory == FX_LOCALECATEGORY_Time) {\r
2301                     wsTimePattern = wsTempPattern;\r
2302                 } else if (eCategory == FX_LOCALECATEGORY_Date) {\r
2303                     wsDatePattern = wsTempPattern;\r
2304                 }\r
2305                 wsTempPattern.Empty();\r
2306             }\r
2307         } else {\r
2308             wsTempPattern += pStr[ccf];\r
2309         }\r
2310         ccf++;\r
2311     }\r
2312     if (!wsTempPattern.IsEmpty()) {\r
2313         if (eCategory == FX_LOCALECATEGORY_Date) {\r
2314             wsDatePattern += wsTempPattern;\r
2315         } else {\r
2316             wsTimePattern += wsTempPattern;\r
2317         }\r
2318     }\r
2319     if (!pLocale) {\r
2320         pLocale = m_pLocaleMgr->GetDefLocale();\r
2321     }\r
2322     if (!iFindCategory) {\r
2323         wsTimePattern.Empty();\r
2324         wsDatePattern = wsPattern;\r
2325     }\r
2326     return (FX_DATETIMETYPE)iFindCategory;\r
2327 }\r
2328 static FX_BOOL FX_ParseLocaleDate(const CFX_WideString& wsDate, const CFX_WideString& wsDatePattern, IFX_Locale* pLocale, CFX_Unitime &datetime, FX_INT32 &cc)\r
2329 {\r
2330     FX_INT32 year = 1900;\r
2331     FX_INT32 month = 1;\r
2332     FX_INT32 day = 1;\r
2333     FX_INT32 ccf = 0;\r
2334     FX_LPCWSTR str = (FX_LPCWSTR)wsDate;\r
2335     FX_INT32 len = wsDate.GetLength();\r
2336     FX_LPCWSTR strf = (FX_LPCWSTR)wsDatePattern;\r
2337     FX_INT32 lenf = wsDatePattern.GetLength();\r
2338     while (cc < len && ccf < lenf) {\r
2339         if (strf[ccf] == '\'') {\r
2340             CFX_WideString wsLiteral = FX_GetLiteralText(strf, ccf, lenf);\r
2341             FX_INT32 iLiteralLen = wsLiteral.GetLength();\r
2342             if (cc + iLiteralLen > len || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsLiteral, iLiteralLen)) {\r
2343                 return FALSE;\r
2344             }\r
2345             cc += iLiteralLen;\r
2346             ccf++;\r
2347             continue;\r
2348         } else if (FX_Local_Find(gs_wsDateSymbols, strf[ccf]) < 0) {\r
2349             if (strf[ccf] != str[cc]) {\r
2350                 return FALSE;\r
2351             }\r
2352             cc++;\r
2353             ccf++;\r
2354             continue;\r
2355         }\r
2356         FX_DWORD dwSymbolNum = 1;\r
2357         FX_DWORD dwSymbol = strf[ccf++];\r
2358         while (ccf < lenf && strf[ccf] == dwSymbol) {\r
2359             ccf++;\r
2360             dwSymbolNum++;\r
2361         }\r
2362         dwSymbol = (dwSymbol << 8) | (dwSymbolNum + '0');\r
2363         if (dwSymbol == FXBSTR_ID(0, 0, 'D', '1')) {\r
2364             if (!FX_IsDigit(str[cc])) {\r
2365                 return FALSE;\r
2366             }\r
2367             day = str[cc++] - '0';\r
2368             if (cc < len && FX_IsDigit(str[cc])) {\r
2369                 day = day * 10 + str[cc++] - '0';\r
2370             }\r
2371         } else if (dwSymbol == FXBSTR_ID(0, 0, 'D', '2')) {\r
2372             if (!FX_IsDigit(str[cc])) {\r
2373                 return FALSE;\r
2374             }\r
2375             day = str[cc++] - '0';\r
2376             if (cc < len) {\r
2377                 day = day * 10 + str[cc++] - '0';\r
2378             }\r
2379         } else if (dwSymbol == FXBSTR_ID(0, 0, 'J', '1')) {\r
2380             int i = 0;\r
2381             while (cc < len && i < 3 && FX_IsDigit(str[cc])) {\r
2382                 cc++;\r
2383                 i++;\r
2384             }\r
2385         } else if (dwSymbol == FXBSTR_ID(0, 0, 'J', '3')) {\r
2386             cc += 3;\r
2387         } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '1')) {\r
2388             if (!FX_IsDigit(str[cc])) {\r
2389                 return FALSE;\r
2390             }\r
2391             month = str[cc++] - '0';\r
2392             if (cc < len && FX_IsDigit(str[cc])) {\r
2393                 month = month * 10 + str[cc++] - '0';\r
2394             }\r
2395         } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '2')) {\r
2396             if (!FX_IsDigit(str[cc])) {\r
2397                 return FALSE;\r
2398             }\r
2399             month = str[cc++] - '0';\r
2400             if (cc < len) {\r
2401                 month = month * 10 + str[cc++] - '0';\r
2402             }\r
2403         } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '3')) {\r
2404             CFX_WideString wsMonthNameAbbr;\r
2405             FX_WORD i = 0;\r
2406             for (; i < 12; i++) {\r
2407                 pLocale->GetMonthName(i, wsMonthNameAbbr, TRUE);\r
2408                 if (wsMonthNameAbbr.IsEmpty()) {\r
2409                     continue;\r
2410                 }\r
2411                 if (!FXSYS_wcsncmp((FX_LPCWSTR)wsMonthNameAbbr, str + cc, wsMonthNameAbbr.GetLength())) {\r
2412                     break;\r
2413                 }\r
2414             }\r
2415             if (i < 12) {\r
2416                 cc += wsMonthNameAbbr.GetLength();\r
2417                 month = i + 1;\r
2418             }\r
2419         } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '4')) {\r
2420             CFX_WideString wsMonthName;\r
2421             FX_WORD i = 0;\r
2422             for (; i < 12; i++) {\r
2423                 pLocale->GetMonthName(i, wsMonthName, FALSE);\r
2424                 if (wsMonthName.IsEmpty()) {\r
2425                     continue;\r
2426                 }\r
2427                 if (!FXSYS_wcsncmp((FX_LPCWSTR)wsMonthName, str + cc, wsMonthName.GetLength())) {\r
2428                     break;\r
2429                 }\r
2430             }\r
2431             if (i < 12) {\r
2432                 cc += wsMonthName.GetLength();\r
2433                 month = i + 1;\r
2434             }\r
2435         } else if (dwSymbol == FXBSTR_ID(0, 0, 'E', '1')) {\r
2436             cc += 1;\r
2437         } else if (dwSymbol == FXBSTR_ID(0, 0, 'E', '3')) {\r
2438             CFX_WideString wsDayNameAbbr;\r
2439             FX_WORD i = 0;\r
2440             for (; i < 7; i++) {\r
2441                 pLocale->GetDayName(i, wsDayNameAbbr, TRUE);\r
2442                 if (wsDayNameAbbr.IsEmpty()) {\r
2443                     continue;\r
2444                 }\r
2445                 if (!FXSYS_wcsncmp((FX_LPCWSTR)wsDayNameAbbr, str + cc, wsDayNameAbbr.GetLength())) {\r
2446                     break;\r
2447                 }\r
2448             }\r
2449             if (i < 12) {\r
2450                 cc += wsDayNameAbbr.GetLength();\r
2451             }\r
2452         } else if (dwSymbol == FXBSTR_ID(0, 0, 'E', '4')) {\r
2453             CFX_WideString wsDayName;\r
2454             FX_INT32 i = 0;\r
2455             for (; i < 7; i++) {\r
2456                 pLocale->GetDayName(i, wsDayName, FALSE);\r
2457                 if (wsDayName == L"") {\r
2458                     continue;\r
2459                 }\r
2460                 if (!FXSYS_wcsncmp((FX_LPCWSTR)wsDayName, str + cc, wsDayName.GetLength())) {\r
2461                     break;\r
2462                 }\r
2463             }\r
2464             if (i < 12) {\r
2465                 cc += wsDayName.GetLength();\r
2466             }\r
2467         } else if (dwSymbol == FXBSTR_ID(0, 0, 'e', '1')) {\r
2468             cc += 1;\r
2469         } else if (dwSymbol == FXBSTR_ID(0, 0, 'G', '1')) {\r
2470             cc += 2;\r
2471         } else if (dwSymbol == FXBSTR_ID(0, 0, 'Y', '2')) {\r
2472             if (cc + 2 > len) {\r
2473                 return FALSE;\r
2474             }\r
2475             if (!FX_IsDigit(str[cc])) {\r
2476                 return FALSE;\r
2477             }\r
2478             year = str[cc++] - '0';\r
2479             if (cc >= len || !FX_IsDigit(str[cc])) {\r
2480                 return FALSE;\r
2481             }\r
2482             year = year * 10 + str[cc++] - '0';\r
2483             if (year <= 29) {\r
2484                 year += 2000;\r
2485             } else {\r
2486                 year += 1900;\r
2487             }\r
2488         } else if (dwSymbol == FXBSTR_ID(0, 0, 'Y', '4')) {\r
2489             int i = 0;\r
2490             year = 0;\r
2491             if (cc + 4 > len) {\r
2492                 return FALSE;\r
2493             }\r
2494             while (i < 4) {\r
2495                 if (!FX_IsDigit(str[cc])) {\r
2496                     return FALSE;\r
2497                 }\r
2498                 year = year * 10 + str[cc] - '0';\r
2499                 cc++;\r
2500                 i++;\r
2501             }\r
2502         } else if (dwSymbol == FXBSTR_ID(0, 0, 'w', '1')) {\r
2503             cc += 1;\r
2504         } else if (dwSymbol == FXBSTR_ID(0, 0, 'W', '2')) {\r
2505             cc += 2;\r
2506         }\r
2507     }\r
2508     CFX_Unitime ut;\r
2509     ut.Set(year, month, day);\r
2510     datetime = datetime + ut;\r
2511     return cc;\r
2512 }\r
2513 static void FX_ResolveZone(FX_BYTE& wHour, FX_BYTE& wMinute, FX_TIMEZONE tzDiff, IFX_Locale* pLocale)\r
2514 {\r
2515     FX_INT32 iMinuteDiff = wHour * 60 + wMinute;\r
2516     FX_TIMEZONE tzLocale;\r
2517     pLocale->GetTimeZone(tzLocale);\r
2518     iMinuteDiff += tzLocale.tzHour * 60 + (tzLocale.tzHour < 0 ? -tzLocale.tzMinute : tzLocale.tzMinute);\r
2519     iMinuteDiff -= tzDiff.tzHour * 60 + (tzDiff.tzHour < 0 ? -tzDiff.tzMinute : tzDiff.tzMinute);\r
2520     while (iMinuteDiff > 1440) {\r
2521         iMinuteDiff -= 1440;\r
2522     }\r
2523     while (iMinuteDiff < 0) {\r
2524         iMinuteDiff += 1440;\r
2525     }\r
2526     wHour = iMinuteDiff / 60;\r
2527     wMinute = iMinuteDiff % 60;\r
2528 }\r
2529 static FX_BOOL FX_ParseLocaleTime(const CFX_WideString& wsTime, const CFX_WideString& wsTimePattern, IFX_Locale* pLocale, CFX_Unitime &datetime, FX_INT32 &cc)\r
2530 {\r
2531     FX_BYTE hour = 0;\r
2532     FX_BYTE minute = 0;\r
2533     FX_BYTE second = 0;\r
2534     FX_WORD millisecond = 0;\r
2535     FX_INT32 ccf = 0;\r
2536     FX_LPCWSTR str = (FX_LPCWSTR)wsTime;\r
2537     int len = wsTime.GetLength();\r
2538     FX_LPCWSTR strf = (FX_LPCWSTR)wsTimePattern;\r
2539     int lenf = wsTimePattern.GetLength();\r
2540     FX_BOOL bHasA = FALSE;\r
2541     FX_BOOL bPM = FALSE;\r
2542     while (cc < len && ccf < lenf) {\r
2543         if (strf[ccf] == '\'') {\r
2544             CFX_WideString wsLiteral = FX_GetLiteralText(strf, ccf, lenf);\r
2545             FX_INT32 iLiteralLen = wsLiteral.GetLength();\r
2546             if (cc + iLiteralLen > len || FXSYS_wcsncmp(str + cc, (FX_LPCWSTR)wsLiteral, iLiteralLen)) {\r
2547                 return FALSE;\r
2548             }\r
2549             cc += iLiteralLen;\r
2550             ccf++;\r
2551             continue;\r
2552         } else if (FX_Local_Find(gs_wsTimeSymbols, strf[ccf]) == -1) {\r
2553             if (strf[ccf] != str[cc]) {\r
2554                 return FALSE;\r
2555             }\r
2556             cc++;\r
2557             ccf++;\r
2558             continue;\r
2559         }\r
2560         FX_DWORD dwSymbolNum = 1;\r
2561         FX_DWORD dwSymbol = strf[ccf++];\r
2562         while (ccf < lenf && strf[ccf] == dwSymbol) {\r
2563             ccf++;\r
2564             dwSymbolNum++;\r
2565         }\r
2566         dwSymbol = (dwSymbol << 8) | (dwSymbolNum + '0');\r
2567         if (dwSymbol == FXBSTR_ID(0, 0, 'k', '1') || dwSymbol == FXBSTR_ID(0, 0, 'H', '1') || dwSymbol == FXBSTR_ID(0, 0, 'h', '1') || dwSymbol == FXBSTR_ID(0, 0, 'K', '1')) {\r
2568             if (!FX_IsDigit(str[cc])) {\r
2569                 return FALSE;\r
2570             }\r
2571             hour = str[cc++] - '0';\r
2572             if (cc < len && FX_IsDigit(str[cc])) {\r
2573                 hour = hour * 10 + str[cc++] - '0';\r
2574             }\r
2575             if (dwSymbol == FXBSTR_ID(0, 0, 'K', '1') && hour == 24) {\r
2576                 hour = 0;\r
2577             }\r
2578         } else if (dwSymbol == FXBSTR_ID(0, 0, 'k', '2') || dwSymbol == FXBSTR_ID(0, 0, 'H', '2') || dwSymbol == FXBSTR_ID(0, 0, 'h', '2') || dwSymbol == FXBSTR_ID(0, 0, 'K', '2')) {\r
2579             if (!FX_IsDigit(str[cc])) {\r
2580                 return FALSE;\r
2581             }\r
2582             hour = str[cc++] - '0';\r
2583             if (cc >= len) {\r
2584                 return FALSE;\r
2585             }\r
2586             if (!FX_IsDigit(str[cc])) {\r
2587                 return FALSE;\r
2588             }\r
2589             hour = hour * 10 + str[cc++] - '0';\r
2590             if (dwSymbol == FXBSTR_ID(0, 0, 'K', '2') && hour == 24) {\r
2591                 hour = 0;\r
2592             }\r
2593         } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '1')) {\r
2594             if (!FX_IsDigit(str[cc])) {\r
2595                 return FALSE;\r
2596             }\r
2597             minute = str[cc++] - '0';\r
2598             if (cc < len && FX_IsDigit(str[cc])) {\r
2599                 minute = minute * 10 + str[cc++] - '0';\r
2600             }\r
2601         } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '2')) {\r
2602             if (!FX_IsDigit(str[cc])) {\r
2603                 return FALSE;\r
2604             }\r
2605             minute = str[cc++] - '0';\r
2606             if (cc >= len) {\r
2607                 return FALSE;\r
2608             }\r
2609             if (!FX_IsDigit(str[cc])) {\r
2610                 return FALSE;\r
2611             }\r
2612             minute = minute * 10 + str[cc++] - '0';\r
2613         } else if (dwSymbol == FXBSTR_ID(0, 0, 'S', '1')) {\r
2614             if (!FX_IsDigit(str[cc])) {\r
2615                 return FALSE;\r
2616             }\r
2617             second = str[cc++] - '0';\r
2618             if (cc < len && FX_IsDigit(str[cc])) {\r
2619                 second = second * 10 + str[cc++] - '0';\r
2620             }\r
2621         } else if (dwSymbol == FXBSTR_ID(0, 0, 'S', '2')) {\r
2622             if (!FX_IsDigit(str[cc])) {\r
2623                 return FALSE;\r
2624             }\r
2625             second = str[cc++] - '0';\r
2626             if (cc >= len) {\r
2627                 return FALSE;\r
2628             }\r
2629             if (!FX_IsDigit(str[cc])) {\r
2630                 return FALSE;\r
2631             }\r
2632             second = second * 10 + str[cc++] - '0';\r
2633         } else if (dwSymbol == FXBSTR_ID(0, 0, 'F', '3')) {\r
2634             if (cc + 3 >= len) {\r
2635                 return FALSE;\r
2636             }\r
2637             int i = 0;\r
2638             while (i < 3) {\r
2639                 if (!FX_IsDigit(str[cc])) {\r
2640                     return FALSE;\r
2641                 }\r
2642                 millisecond = millisecond * 10 + str[cc++] - '0';\r
2643                 i++;\r
2644             }\r
2645         } else if (dwSymbol == FXBSTR_ID(0, 0, 'A', '1')) {\r
2646             CFX_WideString wsAM;\r
2647             pLocale->GetMeridiemName(wsAM, TRUE);\r
2648             CFX_WideString wsPM;\r
2649             pLocale->GetMeridiemName(wsPM, FALSE);\r
2650             if ((cc + wsAM.GetLength() <= len) && (CFX_WideStringC(str + cc, wsAM.GetLength()) == wsAM)) {\r
2651                 cc += wsAM.GetLength();\r
2652                 bHasA = TRUE;\r
2653             } else if ((cc + wsPM.GetLength() <= len) && (CFX_WideStringC(str + cc, wsPM.GetLength()) == wsPM)) {\r
2654                 cc += wsPM.GetLength();\r
2655                 bHasA = TRUE;\r
2656                 bPM = TRUE;\r
2657             }\r
2658         } else if (dwSymbol == FXBSTR_ID(0, 0, 'Z', '1')) {\r
2659             if (cc + 3 > len) {\r
2660                 continue;\r
2661             }\r
2662             FX_DWORD dwHash = str[cc++];\r
2663             dwHash = (dwHash << 8) | str[cc++];\r
2664             dwHash = (dwHash << 8) | str[cc++];\r
2665             if (dwHash == FXBSTR_ID(0, 'G', 'M', 'T')) {\r
2666                 FX_TIMEZONE tzDiff;\r
2667                 tzDiff.tzHour = 0;\r
2668                 tzDiff.tzMinute = 0;\r
2669                 if (cc < len && (str[cc] == '-' || str[cc] == '+')) {\r
2670                     cc += FX_ParseTimeZone(str + cc, len - cc, tzDiff);\r
2671                 }\r
2672                 FX_ResolveZone(hour, minute, tzDiff, pLocale);\r
2673             } else {\r
2674                 FX_LPCLOCALETIMEZONEINFO pTimeZoneInfo = NULL;\r
2675                 FX_INT32 iStart = 0, iEnd = g_iFXLocaleTimeZoneCount - 1;\r
2676                 do {\r
2677                     FX_INT32 iMid = (iStart + iEnd) / 2;\r
2678                     FX_LPCLOCALETIMEZONEINFO pInfo = g_FXLocaleTimeZoneData + iMid;\r
2679                     if (dwHash == pInfo->uHash) {\r
2680                         pTimeZoneInfo = pInfo;\r
2681                         break;\r
2682                     } else if (dwHash < pInfo->uHash) {\r
2683                         iEnd = iMid - 1;\r
2684                     } else {\r
2685                         iStart = iMid + 1;\r
2686                     }\r
2687                 } while (iStart <= iEnd);\r
2688                 if (pTimeZoneInfo) {\r
2689                     hour += pTimeZoneInfo->iHour;\r
2690                     minute += pTimeZoneInfo->iHour > 0 ? pTimeZoneInfo->iMinute : -pTimeZoneInfo->iMinute;\r
2691                 }\r
2692             }\r
2693         } else if (dwSymbol == FXBSTR_ID(0, 0, 'z', '1')) {\r
2694             if (str[cc] != 'Z') {\r
2695                 FX_TIMEZONE tzDiff;\r
2696                 cc += FX_ParseTimeZone(str + cc, len - cc, tzDiff);\r
2697                 FX_ResolveZone(hour, minute, tzDiff, pLocale);\r
2698             } else {\r
2699                 cc++;\r
2700             }\r
2701         }\r
2702     }\r
2703     if (bHasA) {\r
2704         if (bPM) {\r
2705             hour += 12;\r
2706             if (hour == 24) {\r
2707                 hour = 12;\r
2708             }\r
2709         } else {\r
2710             if (hour == 12) {\r
2711                 hour = 0;\r
2712             }\r
2713         }\r
2714     }\r
2715     CFX_Unitime ut;\r
2716     ut.Set(0, 0, 0, hour, minute, second, millisecond);\r
2717     datetime = datetime + ut;\r
2718     return cc;\r
2719 }\r
2720 FX_BOOL CFX_FormatString::ParseDateTime(const CFX_WideString& wsSrcDateTime, const CFX_WideString& wsPattern, FX_DATETIMETYPE eDateTimeType, CFX_Unitime& dtValue)\r
2721 {\r
2722     dtValue.Set(0);\r
2723     if (wsSrcDateTime.IsEmpty() || wsPattern.IsEmpty()) {\r
2724         return FALSE;\r
2725     }\r
2726     CFX_WideString wsDatePattern, wsTimePattern;\r
2727     IFX_Locale* pLocale = NULL;\r
2728     FX_DATETIMETYPE eCategory = GetDateTimeFormat(wsPattern, pLocale, wsDatePattern, wsTimePattern);\r
2729     if (!pLocale) {\r
2730         return FALSE;\r
2731     }\r
2732     if (eCategory == FX_DATETIMETYPE_Unknown) {\r
2733         eCategory = eDateTimeType;\r
2734     }\r
2735     if (eCategory == FX_DATETIMETYPE_Unknown) {\r
2736         return FALSE;\r
2737     }\r
2738     if (eCategory == FX_DATETIMETYPE_TimeDate) {\r
2739         FX_INT32 iStart = 0;\r
2740         if (!FX_ParseLocaleTime(wsSrcDateTime, wsTimePattern, pLocale, dtValue, iStart)) {\r
2741             return FALSE;\r
2742         }\r
2743         if (!FX_ParseLocaleDate(wsSrcDateTime, wsDatePattern, pLocale, dtValue, iStart)) {\r
2744             return FALSE;\r