Home | History | Annotate | Download | only in src
      1 // Copyright (C) 2013 Google Inc.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 // http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "rule.h"
     16 
     17 #include <libaddressinput/address_field.h>
     18 #include <libaddressinput/util/scoped_ptr.h>
     19 
     20 #include <cassert>
     21 #include <cstddef>
     22 #include <string>
     23 #include <vector>
     24 
     25 #include "region_data_constants.h"
     26 #include "util/json.h"
     27 #include "util/string_util.h"
     28 
     29 namespace i18n {
     30 namespace addressinput {
     31 
     32 namespace {
     33 
     34 bool ParseToken(char c, AddressField* field) {
     35   assert(field != NULL);
     36   switch (c) {
     37     case 'R':
     38       *field = COUNTRY;
     39       return true;
     40     case 'S':
     41       *field = ADMIN_AREA;
     42       return true;
     43     case 'C':
     44       *field = LOCALITY;
     45       return true;
     46     case 'D':
     47       *field = DEPENDENT_LOCALITY;
     48       return true;
     49     case 'X':
     50       *field = SORTING_CODE;
     51       return true;
     52     case 'Z':
     53       *field = POSTAL_CODE;
     54       return true;
     55     case 'A':
     56       *field = STREET_ADDRESS;
     57       return true;
     58     case 'O':
     59       *field = ORGANIZATION;
     60       return true;
     61     case 'N':
     62       *field = RECIPIENT;
     63       return true;
     64     default:
     65       return false;
     66   }
     67 }
     68 
     69 // Clears |lines|, parses |format|, and adds the address fields and literals to
     70 // |lines|.
     71 //
     72 // For example, the address format in Finland is "%O%n%N%n%A%nAX-%Z %C%nLAND".
     73 // It includes the allowed fields prefixed with %, newlines denoted %n, and the
     74 // extra text that should be included on an envelope. It is parsed into:
     75 // {
     76 //     {ORGANIZATION},
     77 //     {RECIPIENT},
     78 //     {STREET_ADDRESS},
     79 //     {"AX-", POSTAL_CODE, " ", LOCALITY},
     80 //     {"LAND"}
     81 // }
     82 void ParseAddressFieldsFormat(const std::string& format,
     83                               std::vector<std::vector<FormatElement> >* lines) {
     84   assert(lines != NULL);
     85   lines->clear();
     86   lines->resize(1);
     87 
     88   std::vector<std::string> format_parts;
     89   SplitString(format, '%', &format_parts);
     90 
     91   // If the address format starts with a literal, then it will be in the first
     92   // element of |format_parts|. This literal does not begin with % and should
     93   // not be parsed as a token.
     94   if (!format_parts.empty() && !format_parts[0].empty()) {
     95     lines->back().push_back(FormatElement(format_parts[0]));
     96   }
     97 
     98   // The rest of the elements in |format_parts| begin with %.
     99   for (size_t i = 1; i < format_parts.size(); ++i) {
    100     if (format_parts[i].empty()) {
    101       continue;
    102     }
    103 
    104     // The first character after % denotes a field or a newline token.
    105     const char control_character = format_parts[i][0];
    106 
    107     // The rest of the string after the token is a literal.
    108     const std::string literal = format_parts[i].substr(1);
    109 
    110     AddressField field = COUNTRY;
    111     if (ParseToken(control_character, &field)) {
    112       lines->back().push_back(FormatElement(field));
    113     } else if (control_character == 'n') {
    114       lines->push_back(std::vector<FormatElement>());
    115     }
    116 
    117     if (!literal.empty()) {
    118       lines->back().push_back(FormatElement(literal));
    119     }
    120   }
    121 }
    122 
    123 // Clears |fields|, parses |required|, and adds the required fields to |fields|.
    124 // For example, parses "SCDX" into {ADMIN_AREA, LOCALITY, DEPENDENT_LOCALITY,
    125 // SORTING_CODE}.
    126 void ParseAddressFieldsRequired(const std::string& required,
    127                                 std::vector<AddressField>* fields) {
    128   assert(fields != NULL);
    129   fields->clear();
    130   for (size_t i = 0; i < required.length(); ++i) {
    131     AddressField field = COUNTRY;
    132     if (ParseToken(required[i], &field)) {
    133       fields->push_back(field);
    134     }
    135   }
    136 }
    137 
    138 // Finds |target| in |values_to_compare| and sets |selected_value| to the
    139 // associated value from |values_to_select|. Returns true if |target| is in
    140 // |values_to_compare|. |selected_value| should not be NULL. |values_to_compare|
    141 // should not be larger than |values_to_select|.
    142 bool GetMatchingValue(const std::string& target,
    143                       const std::vector<std::string>& values_to_compare,
    144                       const std::vector<std::string>& values_to_select,
    145                       std::string* selected_value) {
    146   assert(selected_value != NULL);
    147   assert(values_to_select.size() >= values_to_compare.size());
    148   for (size_t i = 0; i < values_to_compare.size(); ++i) {
    149     if (LooseStringCompare(values_to_compare[i], target)) {
    150       *selected_value = values_to_select[i];
    151       return true;
    152     }
    153   }
    154   return false;
    155 }
    156 
    157 }  // namespace
    158 
    159 FormatElement::FormatElement(AddressField field)
    160     : field(field), literal() {}
    161 
    162 FormatElement::FormatElement(const std::string& literal)
    163     : field(COUNTRY), literal(literal) {
    164   assert(!literal.empty());
    165 }
    166 
    167 FormatElement::~FormatElement() {}
    168 
    169 bool FormatElement::operator==(const FormatElement& other) const {
    170   return field == other.field && literal == other.literal;
    171 }
    172 
    173 Rule::Rule() {}
    174 
    175 Rule::~Rule() {}
    176 
    177 // static
    178 const Rule& Rule::GetDefault() {
    179   // Allocated once and leaked on shutdown.
    180   static Rule* default_rule = NULL;
    181   if (default_rule == NULL) {
    182     default_rule = new Rule;
    183     default_rule->ParseSerializedRule(
    184         RegionDataConstants::GetDefaultRegionData());
    185   }
    186   return *default_rule;
    187 }
    188 
    189 void Rule::CopyFrom(const Rule& rule) {
    190   key_ = rule.key_;
    191   name_ = rule.name_;
    192   latin_name_ = rule.latin_name_;
    193   format_ = rule.format_;
    194   latin_format_ = rule.latin_format_;
    195   required_ = rule.required_;
    196   sub_keys_ = rule.sub_keys_;
    197   languages_ = rule.languages_;
    198   input_languages_ = rule.input_languages_;
    199   language_ = rule.language_;
    200   sub_keys_ = rule.sub_keys_;
    201   sub_names_ = rule.sub_names_;
    202   sub_lnames_ = rule.sub_lnames_;
    203   postal_code_format_ = rule.postal_code_format_;
    204   admin_area_name_type_ = rule.admin_area_name_type_;
    205   postal_code_name_type_ = rule.postal_code_name_type_;
    206 }
    207 
    208 bool Rule::ParseSerializedRule(const std::string& serialized_rule) {
    209   scoped_ptr<Json> json(Json::Build());
    210   if (!json->ParseObject(serialized_rule)) {
    211     return false;
    212   }
    213   ParseJsonRule(*json);
    214   return true;
    215 }
    216 
    217 void Rule::ParseJsonRule(const Json& json_rule) {
    218   std::string value;
    219   if (json_rule.GetStringValueForKey("key", &value)) {
    220     key_.swap(value);
    221   }
    222 
    223   if (json_rule.GetStringValueForKey("name", &value)) {
    224     name_.swap(value);
    225   }
    226 
    227   if (json_rule.GetStringValueForKey("lname", &value)) {
    228     latin_name_.swap(value);
    229   }
    230 
    231   if (json_rule.GetStringValueForKey("fmt", &value)) {
    232     ParseAddressFieldsFormat(value, &format_);
    233   }
    234 
    235   if (json_rule.GetStringValueForKey("lfmt", &value)) {
    236     ParseAddressFieldsFormat(value, &latin_format_);
    237   }
    238 
    239   if (json_rule.GetStringValueForKey("require", &value)) {
    240     ParseAddressFieldsRequired(value, &required_);
    241   }
    242 
    243   // Used as a separator in a list of items. For example, the list of supported
    244   // languages can be "de~fr~it".
    245   static const char kSeparator = '~';
    246   if (json_rule.GetStringValueForKey("sub_keys", &value)) {
    247     SplitString(value, kSeparator, &sub_keys_);
    248   }
    249 
    250   if (json_rule.GetStringValueForKey("sub_names", &value)) {
    251     SplitString(value, kSeparator, &sub_names_);
    252     assert(sub_names_.size() == sub_keys_.size());
    253   }
    254 
    255   if (json_rule.GetStringValueForKey("sub_lnames", &value)) {
    256     SplitString(value, kSeparator, &sub_lnames_);
    257     assert(sub_lnames_.size() == sub_keys_.size());
    258   }
    259 
    260   if (json_rule.GetStringValueForKey("languages", &value)) {
    261     SplitString(value, kSeparator, &languages_);
    262   }
    263 
    264   if (json_rule.GetStringValueForKey("input_languages", &value)) {
    265     SplitString(value, kSeparator, &input_languages_);
    266   }
    267 
    268   if (json_rule.GetStringValueForKey("lang", &value)) {
    269     language_.swap(value);
    270   }
    271 
    272   if (json_rule.GetStringValueForKey("zip", &value)) {
    273     postal_code_format_.swap(value);
    274   }
    275 
    276   if (json_rule.GetStringValueForKey("state_name_type", &value)) {
    277     admin_area_name_type_.swap(value);
    278   }
    279 
    280   if (json_rule.GetStringValueForKey("zip_name_type", &value)) {
    281     postal_code_name_type_.swap(value);
    282   }
    283 }
    284 
    285 const std::string& Rule::GetIdentityField(IdentityField identity_field) const {
    286   switch (identity_field) {
    287     case KEY:
    288       return key_;
    289     case NAME:
    290       return name_;
    291     case LATIN_NAME:
    292       return latin_name_;
    293     case IDENTITY_FIELDS_SIZE:
    294       assert(false);
    295   }
    296   return key_;
    297 }
    298 
    299 bool Rule::CanonicalizeSubKey(const std::string& user_input,
    300                               bool keep_input_latin,
    301                               std::string* sub_key) const {
    302   assert(sub_key != NULL);
    303 
    304   if (sub_keys_.empty()) {
    305     *sub_key = user_input;
    306     return true;
    307   }
    308 
    309   return GetMatchingValue(user_input, sub_keys_, sub_keys_, sub_key) ||
    310       GetMatchingValue(user_input, sub_names_, sub_keys_, sub_key) ||
    311       (keep_input_latin &&
    312        GetMatchingValue(user_input, sub_lnames_, sub_lnames_, sub_key)) ||
    313       GetMatchingValue(user_input, sub_lnames_, sub_keys_, sub_key);
    314 }
    315 
    316 }  // namespace addressinput
    317 }  // namespace i18n
    318