1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "xfa/fxfa/parser/cxfa_xmllocale.h"
8 
9 #include <utility>
10 
11 #include "core/fxcrt/cfx_readonlymemorystream.h"
12 #include "core/fxcrt/fx_codepage.h"
13 #include "core/fxcrt/xml/cfx_xmldocument.h"
14 #include "core/fxcrt/xml/cfx_xmlelement.h"
15 #include "core/fxcrt/xml/cfx_xmlparser.h"
16 #include "third_party/base/ptr_util.h"
17 #include "xfa/fxfa/parser/cxfa_document.h"
18 #include "xfa/fxfa/parser/cxfa_localemgr.h"
19 #include "xfa/fxfa/parser/cxfa_nodelocale.h"
20 #include "xfa/fxfa/parser/cxfa_timezoneprovider.h"
21 #include "xfa/fxfa/parser/xfa_utils.h"
22 
23 namespace {
24 
25 constexpr wchar_t kNumberSymbols[] = L"numberSymbols";
26 constexpr wchar_t kNumberSymbol[] = L"numberSymbol";
27 constexpr wchar_t kCurrencySymbols[] = L"currencySymbols";
28 constexpr wchar_t kCurrencySymbol[] = L"currencySymbol";
29 
30 }  // namespace
31 
32 // static
Create(pdfium::span<uint8_t> data)33 std::unique_ptr<CXFA_XMLLocale> CXFA_XMLLocale::Create(
34     pdfium::span<uint8_t> data) {
35   auto stream = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(data);
36   CFX_XMLParser parser(stream);
37   auto doc = parser.Parse();
38   if (!doc)
39     return nullptr;
40 
41   CFX_XMLElement* locale = nullptr;
42   for (auto* child = doc->GetRoot()->GetFirstChild(); child;
43        child = child->GetNextSibling()) {
44     CFX_XMLElement* elem = ToXMLElement(child);
45     if (elem && elem->GetName().EqualsASCII("locale")) {
46       locale = elem;
47       break;
48     }
49   }
50   if (!locale)
51     return nullptr;
52 
53   return pdfium::MakeUnique<CXFA_XMLLocale>(std::move(doc), locale);
54 }
55 
CXFA_XMLLocale(std::unique_ptr<CFX_XMLDocument> doc,CFX_XMLElement * locale)56 CXFA_XMLLocale::CXFA_XMLLocale(std::unique_ptr<CFX_XMLDocument> doc,
57                                CFX_XMLElement* locale)
58     : xml_doc_(std::move(doc)), locale_(locale) {
59   ASSERT(xml_doc_);
60   ASSERT(locale_);
61 }
62 
~CXFA_XMLLocale()63 CXFA_XMLLocale::~CXFA_XMLLocale() {}
64 
GetName() const65 WideString CXFA_XMLLocale::GetName() const {
66   return locale_->GetAttribute(L"name");
67 }
68 
GetDecimalSymbol() const69 WideString CXFA_XMLLocale::GetDecimalSymbol() const {
70   CFX_XMLElement* patterns = locale_->GetFirstChildNamed(kNumberSymbols);
71   return patterns ? GetPattern(patterns, kNumberSymbol, L"decimal")
72                   : WideString();
73 }
74 
GetGroupingSymbol() const75 WideString CXFA_XMLLocale::GetGroupingSymbol() const {
76   CFX_XMLElement* patterns = locale_->GetFirstChildNamed(kNumberSymbols);
77   return patterns ? GetPattern(patterns, kNumberSymbol, L"grouping")
78                   : WideString();
79 }
80 
GetPercentSymbol() const81 WideString CXFA_XMLLocale::GetPercentSymbol() const {
82   CFX_XMLElement* patterns = locale_->GetFirstChildNamed(kNumberSymbols);
83   return patterns ? GetPattern(patterns, kNumberSymbol, L"percent")
84                   : WideString();
85 }
86 
GetMinusSymbol() const87 WideString CXFA_XMLLocale::GetMinusSymbol() const {
88   CFX_XMLElement* patterns = locale_->GetFirstChildNamed(kNumberSymbols);
89   return patterns ? GetPattern(patterns, kNumberSymbol, L"minus")
90                   : WideString();
91 }
92 
GetCurrencySymbol() const93 WideString CXFA_XMLLocale::GetCurrencySymbol() const {
94   CFX_XMLElement* patterns = locale_->GetFirstChildNamed(kCurrencySymbols);
95   return patterns ? GetPattern(patterns, kCurrencySymbol, L"symbol")
96                   : WideString();
97 }
98 
GetDateTimeSymbols() const99 WideString CXFA_XMLLocale::GetDateTimeSymbols() const {
100   CFX_XMLElement* symbols = locale_->GetFirstChildNamed(L"dateTimeSymbols");
101   return symbols ? symbols->GetTextData() : WideString();
102 }
103 
GetMonthName(int32_t nMonth,bool bAbbr) const104 WideString CXFA_XMLLocale::GetMonthName(int32_t nMonth, bool bAbbr) const {
105   return GetCalendarSymbol(L"month", nMonth, bAbbr);
106 }
107 
GetDayName(int32_t nWeek,bool bAbbr) const108 WideString CXFA_XMLLocale::GetDayName(int32_t nWeek, bool bAbbr) const {
109   return GetCalendarSymbol(L"day", nWeek, bAbbr);
110 }
111 
GetMeridiemName(bool bAM) const112 WideString CXFA_XMLLocale::GetMeridiemName(bool bAM) const {
113   return GetCalendarSymbol(L"meridiem", bAM ? 0 : 1, false);
114 }
115 
GetTimeZone() const116 FX_TIMEZONE CXFA_XMLLocale::GetTimeZone() const {
117   return CXFA_TimeZoneProvider().GetTimeZone();
118 }
119 
GetEraName(bool bAD) const120 WideString CXFA_XMLLocale::GetEraName(bool bAD) const {
121   return GetCalendarSymbol(L"era", bAD ? 1 : 0, false);
122 }
123 
GetCalendarSymbol(WideStringView symbol,size_t index,bool bAbbr) const124 WideString CXFA_XMLLocale::GetCalendarSymbol(WideStringView symbol,
125                                              size_t index,
126                                              bool bAbbr) const {
127   CFX_XMLElement* child = locale_->GetFirstChildNamed(L"calendarSymbols");
128   if (!child)
129     return WideString();
130 
131   WideString pstrSymbolNames = symbol + L"Names";
132   CFX_XMLElement* name_child = nullptr;
133   for (auto* name = child->GetFirstChild(); name;
134        name = name->GetNextSibling()) {
135     CFX_XMLElement* elem = ToXMLElement(name);
136     if (!elem || elem->GetName() != pstrSymbolNames)
137       continue;
138 
139     WideString abbr = elem->GetAttribute(L"abbr");
140     bool abbr_value = false;
141     if (!abbr.IsEmpty())
142       abbr_value = abbr.EqualsASCII("1");
143     if (abbr_value != bAbbr)
144       continue;
145 
146     name_child = elem;
147     break;
148   }
149   if (!name_child)
150     return WideString();
151 
152   CFX_XMLElement* sym_element = name_child->GetNthChildNamed(symbol, index);
153   return sym_element ? sym_element->GetTextData() : WideString();
154 }
155 
GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY eType) const156 WideString CXFA_XMLLocale::GetDatePattern(
157     FX_LOCALEDATETIMESUBCATEGORY eType) const {
158   CFX_XMLElement* patterns = locale_->GetFirstChildNamed(L"datePatterns");
159   if (!patterns)
160     return WideString();
161 
162   WideString wsName;
163   switch (eType) {
164     case FX_LOCALEDATETIMESUBCATEGORY_Short:
165       wsName = L"short";
166       break;
167     case FX_LOCALEDATETIMESUBCATEGORY_Default:
168     case FX_LOCALEDATETIMESUBCATEGORY_Medium:
169       wsName = L"med";
170       break;
171     case FX_LOCALEDATETIMESUBCATEGORY_Full:
172       wsName = L"full";
173       break;
174     case FX_LOCALEDATETIMESUBCATEGORY_Long:
175       wsName = L"long";
176       break;
177   }
178   return GetPattern(patterns, L"datePattern", wsName.AsStringView());
179 }
180 
GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY eType) const181 WideString CXFA_XMLLocale::GetTimePattern(
182     FX_LOCALEDATETIMESUBCATEGORY eType) const {
183   CFX_XMLElement* patterns = locale_->GetFirstChildNamed(L"timePatterns");
184   if (!patterns)
185     return WideString();
186 
187   WideString wsName;
188   switch (eType) {
189     case FX_LOCALEDATETIMESUBCATEGORY_Short:
190       wsName = L"short";
191       break;
192     case FX_LOCALEDATETIMESUBCATEGORY_Default:
193     case FX_LOCALEDATETIMESUBCATEGORY_Medium:
194       wsName = L"med";
195       break;
196     case FX_LOCALEDATETIMESUBCATEGORY_Full:
197       wsName = L"full";
198       break;
199     case FX_LOCALEDATETIMESUBCATEGORY_Long:
200       wsName = L"long";
201       break;
202   }
203   return GetPattern(patterns, L"timePattern", wsName.AsStringView());
204 }
205 
GetNumPattern(FX_LOCALENUMSUBCATEGORY eType) const206 WideString CXFA_XMLLocale::GetNumPattern(FX_LOCALENUMSUBCATEGORY eType) const {
207   CFX_XMLElement* patterns = locale_->GetFirstChildNamed(L"numberPatterns");
208   return patterns ? XFA_PatternToString(eType) : WideString();
209 }
210 
GetPattern(CFX_XMLElement * patterns,WideStringView bsTag,WideStringView wsName) const211 WideString CXFA_XMLLocale::GetPattern(CFX_XMLElement* patterns,
212                                       WideStringView bsTag,
213                                       WideStringView wsName) const {
214   for (auto* child = patterns->GetFirstChild(); child;
215        child = child->GetNextSibling()) {
216     CFX_XMLElement* pattern = ToXMLElement(child);
217     if (pattern && pattern->GetName() == bsTag &&
218         pattern->GetAttribute(L"name") == wsName) {
219       return pattern->GetTextData();
220     }
221   }
222   return WideString();
223 }
224