1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4*******************************************************************************
5*
6* Copyright (C) 1997-2012, International Business Machines
7* Corporation and others. All Rights Reserved.
8*
9*******************************************************************************
10* file name: loclikely.cpp
11* encoding: UTF-8
12* tab size: 8 (not used)
13* indentation:4
14*
15* created on: 2010feb25
16* created by: Markus W. Scherer
17*
18* Code for miscellaneous locale-related resource bundle data access,
19* separated out from other .cpp files
20* that then do not depend on resource bundle code and this data.
21*/
22
23#include "unicode/utypes.h"
24#include "unicode/putil.h"
25#include "unicode/uloc.h"
26#include "unicode/ures.h"
27#include "cstring.h"
28#include "ulocimp.h"
29#include "uresimp.h"
30
31/*
32 * Lookup a resource bundle table item with fallback on the table level.
33 * Regular resource bundle lookups perform fallback to parent locale bundles
34 * and eventually the root bundle, but only for top-level items.
35 * This function takes the name of a top-level table and of an item in that table
36 * and performs a lookup of both, falling back until a bundle contains a table
37 * with this item.
38 *
39 * Note: Only the opening of entire bundles falls back through the default locale
40 * before root. Once a bundle is open, item lookups do not go through the
41 * default locale because that would result in a mix of languages that is
42 * unpredictable to the programmer and most likely useless.
43 */
44U_CAPI const char16_t * U_EXPORT2
45uloc_getTableStringWithFallback(const char *path, const char *locale,
46 const char *tableKey, const char *subTableKey,
47 const char *itemKey,
48 int32_t *pLength,
49 UErrorCode *pErrorCode)
50{
51/* char localeBuffer[ULOC_FULLNAME_CAPACITY*4];*/
52 const char16_t *item=nullptr;
53 UErrorCode errorCode;
54 char explicitFallbackName[ULOC_FULLNAME_CAPACITY] = {0};
55
56 /*
57 * open the bundle for the current locale
58 * this falls back through the locale's chain to root
59 */
60 errorCode=U_ZERO_ERROR;
61 icu::LocalUResourceBundlePointer rb(ures_open(path, locale, &errorCode));
62
63 if(U_FAILURE(errorCode)) {
64 /* total failure, not even root could be opened */
65 *pErrorCode=errorCode;
66 return nullptr;
67 } else if(errorCode==U_USING_DEFAULT_WARNING ||
68 (errorCode==U_USING_FALLBACK_WARNING && *pErrorCode!=U_USING_DEFAULT_WARNING)
69 ) {
70 /* set the "strongest" error code (success->fallback->default->failure) */
71 *pErrorCode=errorCode;
72 }
73
74 for(;;){
75 icu::StackUResourceBundle table;
76 icu::StackUResourceBundle subTable;
77 ures_getByKeyWithFallback(rb.getAlias(), tableKey, table.getAlias(), &errorCode);
78
79 if (subTableKey != nullptr) {
80 /*
81 ures_getByKeyWithFallback(table.getAlias(), subTableKey, subTable.getAlias(), &errorCode);
82 item = ures_getStringByKeyWithFallback(subTable.getAlias(), itemKey, pLength, &errorCode);
83 if(U_FAILURE(errorCode)){
84 *pErrorCode = errorCode;
85 }
86
87 break;*/
88
89 ures_getByKeyWithFallback(table.getAlias(), subTableKey, table.getAlias(), &errorCode);
90 }
91 if(U_SUCCESS(errorCode)){
92 item = ures_getStringByKeyWithFallback(table.getAlias(), itemKey, pLength, &errorCode);
93 if(U_FAILURE(errorCode)){
94 const char* replacement = nullptr;
95 *pErrorCode = errorCode; /*save the errorCode*/
96 errorCode = U_ZERO_ERROR;
97 /* may be a deprecated code */
98 if(uprv_strcmp(tableKey, "Countries")==0){
99 replacement = uloc_getCurrentCountryID(itemKey);
100 }else if(uprv_strcmp(tableKey, "Languages")==0){
101 replacement = uloc_getCurrentLanguageID(itemKey);
102 }
103 /*pointer comparison is ok since uloc_getCurrentCountryID & uloc_getCurrentLanguageID return the key itself is replacement is not found*/
104 if(replacement!=nullptr && itemKey != replacement){
105 item = ures_getStringByKeyWithFallback(table.getAlias(), replacement, pLength, &errorCode);
106 if(U_SUCCESS(errorCode)){
107 *pErrorCode = errorCode;
108 break;
109 }
110 }
111 }else{
112 break;
113 }
114 }
115
116 if(U_FAILURE(errorCode)){
117
118 /* still can't figure out ?.. try the fallback mechanism */
119 int32_t len = 0;
120 const char16_t* fallbackLocale = nullptr;
121 *pErrorCode = errorCode;
122 errorCode = U_ZERO_ERROR;
123
124 fallbackLocale = ures_getStringByKeyWithFallback(table.getAlias(), "Fallback", &len, &errorCode);
125 if(U_FAILURE(errorCode)){
126 *pErrorCode = errorCode;
127 break;
128 }
129
130 u_UCharsToChars(fallbackLocale, explicitFallbackName, len);
131
132 /* guard against recursive fallback */
133 if(uprv_strcmp(explicitFallbackName, locale)==0){
134 *pErrorCode = U_INTERNAL_PROGRAM_ERROR;
135 break;
136 }
137 rb.adoptInstead(ures_open(path, explicitFallbackName, &errorCode));
138 if(U_FAILURE(errorCode)){
139 *pErrorCode = errorCode;
140 break;
141 }
142 /* succeeded in opening the fallback bundle .. continue and try to fetch the item */
143 }else{
144 break;
145 }
146 }
147
148 return item;
149}
150
151static ULayoutType
152_uloc_getOrientationHelper(const char* localeId,
153 const char* key,
154 UErrorCode *status)
155{
156 ULayoutType result = ULOC_LAYOUT_UNKNOWN;
157
158 if (!U_FAILURE(*status)) {
159 int32_t length = 0;
160 char localeBuffer[ULOC_FULLNAME_CAPACITY];
161
162 uloc_canonicalize(localeId, localeBuffer, sizeof(localeBuffer), status);
163
164 if (!U_FAILURE(*status)) {
165 const char16_t* const value =
166 uloc_getTableStringWithFallback(
167 nullptr,
168 localeBuffer,
169 "layout",
170 nullptr,
171 key,
172 &length,
173 status);
174
175 if (!U_FAILURE(*status) && length != 0) {
176 switch(value[0])
177 {
178 case 0x0062: /* 'b' */
179 result = ULOC_LAYOUT_BTT;
180 break;
181 case 0x006C: /* 'l' */
182 result = ULOC_LAYOUT_LTR;
183 break;
184 case 0x0072: /* 'r' */
185 result = ULOC_LAYOUT_RTL;
186 break;
187 case 0x0074: /* 't' */
188 result = ULOC_LAYOUT_TTB;
189 break;
190 default:
191 *status = U_INTERNAL_PROGRAM_ERROR;
192 break;
193 }
194 }
195 }
196 }
197
198 return result;
199}
200
201U_CAPI ULayoutType U_EXPORT2
202uloc_getCharacterOrientation(const char* localeId,
203 UErrorCode *status)
204{
205 return _uloc_getOrientationHelper(localeId, "characters", status);
206}
207
208/**
209 * Get the layout line orientation for the specified locale.
210 *
211 * @param localeID locale name
212 * @param status Error status
213 * @return an enum indicating the layout orientation for lines.
214 */
215U_CAPI ULayoutType U_EXPORT2
216uloc_getLineOrientation(const char* localeId,
217 UErrorCode *status)
218{
219 return _uloc_getOrientationHelper(localeId, "lines", status);
220}
221