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