1 // Copyright 2017 The PDFium Authors
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_read_only_span_stream.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/check.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(cppgc::Heap * heap,pdfium::span<uint8_t> data)33 CXFA_XMLLocale* CXFA_XMLLocale::Create(cppgc::Heap* heap,
34 pdfium::span<uint8_t> data) {
35 auto stream = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(data);
36 CFX_XMLParser parser(stream);
37 auto doc = parser.Parse();
38 if (!doc)
39 return nullptr;
40
41 for (auto* child = doc->GetRoot()->GetFirstChild(); child;
42 child = child->GetNextSibling()) {
43 CFX_XMLElement* elem = ToXMLElement(child);
44 if (elem && elem->GetName().EqualsASCII("locale")) {
45 return cppgc::MakeGarbageCollected<CXFA_XMLLocale>(
46 heap->GetAllocationHandle(), std::move(doc), elem);
47 }
48 }
49 return nullptr;
50 }
51
CXFA_XMLLocale(std::unique_ptr<CFX_XMLDocument> doc,const CFX_XMLElement * locale)52 CXFA_XMLLocale::CXFA_XMLLocale(std::unique_ptr<CFX_XMLDocument> doc,
53 const CFX_XMLElement* locale)
54 : xml_doc_(std::move(doc)), locale_(locale) {
55 DCHECK(xml_doc_);
56 DCHECK(locale_);
57 }
58
59 CXFA_XMLLocale::~CXFA_XMLLocale() = default;
60
Trace(cppgc::Visitor * visitor) const61 void CXFA_XMLLocale::Trace(cppgc::Visitor* visitor) const {
62 GCedLocaleIface::Trace(visitor);
63 }
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
GetTimeZoneInMinutes() const116 int CXFA_XMLLocale::GetTimeZoneInMinutes() const {
117 return CXFA_TimeZoneProvider().GetTimeZoneInMinutes();
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(DateTimeSubcategory eType) const156 WideString CXFA_XMLLocale::GetDatePattern(DateTimeSubcategory eType) const {
157 CFX_XMLElement* patterns = locale_->GetFirstChildNamed(L"datePatterns");
158 if (!patterns)
159 return WideString();
160
161 WideString wsName;
162 switch (eType) {
163 case DateTimeSubcategory::kShort:
164 wsName = L"short";
165 break;
166 case DateTimeSubcategory::kDefault:
167 case DateTimeSubcategory::kMedium:
168 wsName = L"med";
169 break;
170 case DateTimeSubcategory::kFull:
171 wsName = L"full";
172 break;
173 case DateTimeSubcategory::kLong:
174 wsName = L"long";
175 break;
176 }
177 return GetPattern(patterns, L"datePattern", wsName.AsStringView());
178 }
179
GetTimePattern(DateTimeSubcategory eType) const180 WideString CXFA_XMLLocale::GetTimePattern(DateTimeSubcategory eType) const {
181 CFX_XMLElement* patterns = locale_->GetFirstChildNamed(L"timePatterns");
182 if (!patterns)
183 return WideString();
184
185 WideString wsName;
186 switch (eType) {
187 case DateTimeSubcategory::kShort:
188 wsName = L"short";
189 break;
190 case DateTimeSubcategory::kDefault:
191 case DateTimeSubcategory::kMedium:
192 wsName = L"med";
193 break;
194 case DateTimeSubcategory::kFull:
195 wsName = L"full";
196 break;
197 case DateTimeSubcategory::kLong:
198 wsName = L"long";
199 break;
200 }
201 return GetPattern(patterns, L"timePattern", wsName.AsStringView());
202 }
203
GetNumPattern(NumSubcategory eType) const204 WideString CXFA_XMLLocale::GetNumPattern(NumSubcategory eType) const {
205 CFX_XMLElement* patterns = locale_->GetFirstChildNamed(L"numberPatterns");
206 return patterns ? XFA_PatternToString(eType) : WideString();
207 }
208
GetPattern(CFX_XMLElement * patterns,WideStringView bsTag,WideStringView wsName) const209 WideString CXFA_XMLLocale::GetPattern(CFX_XMLElement* patterns,
210 WideStringView bsTag,
211 WideStringView wsName) const {
212 for (auto* child = patterns->GetFirstChild(); child;
213 child = child->GetNextSibling()) {
214 CFX_XMLElement* pattern = ToXMLElement(child);
215 if (pattern && pattern->GetName() == bsTag &&
216 pattern->GetAttribute(L"name") == wsName) {
217 return pattern->GetTextData();
218 }
219 }
220 return WideString();
221 }
222