16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/*
26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project
36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License.
66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at
76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software
116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and
146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License.
156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Locale.h"
186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <ctype.h>
20ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
21cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#include <algorithm>
226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <string>
236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <vector>
246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
25ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "util/Util.h"
26ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
27b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinskiusing ::android::ResTable_config;
28b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinskiusing ::android::StringPiece;
296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
30b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinskinamespace aapt {
316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
32ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskivoid LocaleValue::set_language(const char* language_chars) {
33cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  size_t i = 0;
34ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  while ((*language_chars) != '\0') {
35ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    language[i++] = ::tolower(*language_chars);
36ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    language_chars++;
37cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
40ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskivoid LocaleValue::set_region(const char* region_chars) {
41cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  size_t i = 0;
42ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  while ((*region_chars) != '\0') {
43ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    region[i++] = ::toupper(*region_chars);
44ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    region_chars++;
45cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
48ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskivoid LocaleValue::set_script(const char* script_chars) {
49cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  size_t i = 0;
50ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  while ((*script_chars) != '\0') {
51cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (i == 0) {
52ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      script[i++] = ::toupper(*script_chars);
53cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    } else {
54ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      script[i++] = ::tolower(*script_chars);
556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
56ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    script_chars++;
57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
60ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskivoid LocaleValue::set_variant(const char* variant_chars) {
61cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  size_t i = 0;
62ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  while ((*variant_chars) != '\0') {
63ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    variant[i++] = *variant_chars;
64ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    variant_chars++;
65cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
68ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic inline bool is_alpha(const std::string& str) {
69cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return std::all_of(std::begin(str), std::end(str), ::isalpha);
706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
72ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic inline bool is_number(const std::string& str) {
73cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return std::all_of(std::begin(str), std::end(str), ::isdigit);
746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
76b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinskibool LocaleValue::InitFromFilterString(const StringPiece& str) {
77cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // A locale (as specified in the filter) is an underscore separated name such
78cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // as "en_US", "en_Latn_US", or "en_US_POSIX".
79ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::vector<std::string> parts = util::SplitAndLowercase(str, '_');
80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
81ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const int num_tags = parts.size();
82cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  bool valid = false;
83ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (num_tags >= 1) {
84cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    const std::string& lang = parts[0];
85ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (is_alpha(lang) && (lang.length() == 2 || lang.length() == 3)) {
86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      set_language(lang.c_str());
87cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      valid = true;
88cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
89cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
90cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
91ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (!valid || num_tags == 1) {
92cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return valid;
93cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
94cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
95cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // At this point, valid == true && numTags > 1.
96cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const std::string& part2 = parts[1];
97ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if ((part2.length() == 2 && is_alpha(part2)) ||
98ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      (part2.length() == 3 && is_number(part2))) {
99ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    set_region(part2.c_str());
100ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  } else if (part2.length() == 4 && is_alpha(part2)) {
101ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    set_script(part2.c_str());
102cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  } else if (part2.length() >= 4 && part2.length() <= 8) {
103ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    set_variant(part2.c_str());
104cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  } else {
105cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    valid = false;
106cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
107cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
108ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (!valid || num_tags == 2) {
109cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return valid;
110cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
111cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
112cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // At this point, valid == true && numTags > 1.
113cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const std::string& part3 = parts[2];
114ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (((part3.length() == 2 && is_alpha(part3)) ||
115ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski       (part3.length() == 3 && is_number(part3))) &&
116cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      script[0]) {
117ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    set_region(part3.c_str());
118cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  } else if (part3.length() >= 4 && part3.length() <= 8) {
119ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    set_variant(part3.c_str());
120cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  } else {
121cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    valid = false;
122cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
123cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
124ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (!valid || num_tags == 3) {
125cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return valid;
126cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
127cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
128cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const std::string& part4 = parts[3];
129cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (part4.length() >= 4 && part4.length() <= 8) {
130ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    set_variant(part4.c_str());
131cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  } else {
132cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    valid = false;
133cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
134cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
135ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (!valid || num_tags > 4) {
136cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return false;
137cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
138cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
139cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return true;
1406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
142b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinskibool LocaleValue::InitFromBcp47Tag(const StringPiece& bcp47tag) {
143b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski  return InitFromBcp47TagImpl(bcp47tag, '-');
144b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski}
145b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski
146b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinskibool LocaleValue::InitFromBcp47TagImpl(const StringPiece& bcp47tag, const char separator) {
147b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski  std::vector<std::string> subtags = util::SplitAndLowercase(bcp47tag, separator);
148b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski  if (subtags.size() == 1) {
149b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    set_language(subtags[0].c_str());
150b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski  } else if (subtags.size() == 2) {
151b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    set_language(subtags[0].c_str());
152b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski
153b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    // The second tag can either be a region, a variant or a script.
154b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    switch (subtags[1].size()) {
155b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      case 2:
156b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      case 3:
157b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski        set_region(subtags[1].c_str());
158b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski        break;
159b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      case 4:
160b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski        if ('0' <= subtags[1][0] && subtags[1][0] <= '9') {
161b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski          // This is a variant: fall through
162b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski        } else {
163b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski          set_script(subtags[1].c_str());
164b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski          break;
165b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski        }
166b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      case 5:
167b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      case 6:
168b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      case 7:
169b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      case 8:
170b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski        set_variant(subtags[1].c_str());
171b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski        break;
172b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      default:
173b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski        return false;
174b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    }
175b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski  } else if (subtags.size() == 3) {
176b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    // The language is always the first subtag.
177b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    set_language(subtags[0].c_str());
178b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski
179b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    // The second subtag can either be a script or a region code.
180b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    // If its size is 4, it's a script code, else it's a region code.
181b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    if (subtags[1].size() == 4) {
182b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      set_script(subtags[1].c_str());
183b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    } else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
184b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      set_region(subtags[1].c_str());
185b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    } else {
186b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      return false;
187b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    }
188b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski
189b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    // The third tag can either be a region code (if the second tag was
190b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    // a script), else a variant code.
191b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    if (subtags[2].size() >= 4) {
192b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      set_variant(subtags[2].c_str());
193b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    } else {
194b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski      set_region(subtags[2].c_str());
195b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    }
196b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski  } else if (subtags.size() == 4) {
197b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    set_language(subtags[0].c_str());
198b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    set_script(subtags[1].c_str());
199b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    set_region(subtags[2].c_str());
200b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    set_variant(subtags[3].c_str());
201b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski  } else {
202b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    return false;
203b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski  }
204b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski  return true;
205b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski}
206b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski
207ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskissize_t LocaleValue::InitFromParts(std::vector<std::string>::iterator iter,
208cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                                   std::vector<std::string>::iterator end) {
209ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const std::vector<std::string>::iterator start_iter = iter;
210cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
211cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string& part = *iter;
212cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (part[0] == 'b' && part[1] == '+') {
213cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // This is a "modified" BCP 47 language tag. Same semantics as BCP 47 tags,
214b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    // except that the separator is "+" and not "-". Skip the prefix 'b+'.
215b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    if (!InitFromBcp47TagImpl(StringPiece(part).substr(2), '+')) {
216cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return -1;
217cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
218cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    ++iter;
219cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  } else {
220b58c3ef023acf3851e4a0557d04d65d52835d2dfAdam Lesinski    if ((part.length() == 2 || part.length() == 3) && is_alpha(part) && part != "car") {
221ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      set_language(part.c_str());
222cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      ++iter;
223cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
224cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      if (iter != end) {
225ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        const std::string& region_part = *iter;
226ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        if (region_part.c_str()[0] == 'r' && region_part.length() == 3) {
227ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          set_region(region_part.c_str() + 1);
228cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          ++iter;
2296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
230cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
2316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
232cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
233ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  return static_cast<ssize_t>(iter - start_iter);
2346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
236ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskivoid LocaleValue::InitFromResTable(const ResTable_config& config) {
237cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  config.unpackLanguage(language);
238cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  config.unpackRegion(region);
239cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (config.localeScript[0] && !config.localeScriptWasComputed) {
240cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    memcpy(script, config.localeScript, sizeof(config.localeScript));
241cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
242cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
243cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (config.localeVariant[0]) {
244cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    memcpy(variant, config.localeVariant, sizeof(config.localeVariant));
245cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
2466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
248ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskivoid LocaleValue::WriteTo(ResTable_config* out) const {
249cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  out->packLanguage(language);
250cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  out->packRegion(region);
2516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
252cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (script[0]) {
253cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    memcpy(out->localeScript, script, sizeof(out->localeScript));
254cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
2556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
256cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (variant[0]) {
257cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    memcpy(out->localeVariant, variant, sizeof(out->localeVariant));
258cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
2596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
261cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
262