Validation for part of language tag. 95/85095/3
authorPiotr Ganicz <p.ganicz@samsung.com>
Tue, 23 Aug 2016 11:01:30 +0000 (13:01 +0200)
committerPiotr Ganicz <p.ganicz@samsung.com>
Tue, 23 Aug 2016 15:53:00 +0000 (17:53 +0200)
This patch provides validation for extension and private use tag.

Change-Id: Iea3e561b49279085323fa3b84f94fc4b0edf5bad

src/manifest_parser/utils/language_tag_validator.cc

index d134ef8bf7961796ef5169bd49abd6466c462941..174a1b8c1ab9071c4ec44b8be1a1fe718cd21d70 100644 (file)
@@ -14,7 +14,8 @@ namespace ba = boost::algorithm;
 namespace {
 const char kTagDelimiter[] = "-";
 const int kSingletonTagSize = 1;
-const int kMaximumExtensionTagSize = 8;
+const int kMaximumExtensionTagSize = 16;
+const int kMaximumPrivateTagSize = 8;
 
 std::string Capitalized(const std::string& input) {
   std::string output = input;
@@ -34,7 +35,96 @@ std::string ToUpper(const std::string& input) {
   ba::to_upper(output);
   return output;
 }
-
+bool CheckSingleton(std::vector<std::string>::iterator * current_item,
+                    std::string *error) {
+  if ((*(*current_item)).size() != kSingletonTagSize) {
+    if (error)
+      *error = std::string("Singletion subtag should be of size ") +
+        std::to_string(kSingletonTagSize);
+    return false;
+  }
+  return true;
+}
+bool CheckProperExtensionLength(std::vector<std::string>::iterator
+        *current_item, std::string *error) {
+  auto tag_length = (*(*current_item)).size();
+  if (tag_length > kMaximumExtensionTagSize) {
+    if (error)
+      *error = std::string("Any extensions should be maximum ") +
+        std::to_string(kMaximumExtensionTagSize) + "characters";
+    return false;
+  }
+  return true;
+}
+bool CheckProperPrivateTagLength(std::vector<std::string>::iterator
+        *current_item, std::string *error) {
+  auto tag_length = (*(*current_item)).size();
+  if (tag_length > kMaximumPrivateTagSize) {
+    if (error)
+      *error = std::string("Any private tag should be maximum ") +
+        std::to_string(kMaximumPrivateTagSize) + "characters";
+    return false;
+  }
+  return true;
+}
+bool ValidateExtension(std::vector<std::string>::iterator *current_item,
+                    const std::vector<std::string> &splitted,
+                    std::string *error,
+                    std::unordered_set<std::string> *usedTags) {
+  if (*(*current_item) != "x") {
+    if (!CheckSingleton(current_item, error))
+      return false;
+    if (usedTags->find(*(*current_item)) != usedTags->end()) {
+      if (error)
+        *error = std::string("You can't use the same singleton") +
+          std::string(" more than once.");
+      return false;
+    }
+    usedTags->insert(*(*current_item));
+    ++(*current_item);
+    if ((*current_item) == splitted.end() ||
+            (*(*current_item)).size() == kSingletonTagSize) {
+      if (error)
+        *error = std::string("At least one extension should be provided");
+      return false;
+    }
+    if (!CheckProperExtensionLength(current_item, error))
+      return false;
+    ++(*current_item);
+    while ((*current_item) != splitted.end()) {
+      if (!CheckProperExtensionLength(current_item, error)) {
+        return false;
+      }
+      if ((*(*current_item)).size() == kSingletonTagSize) {
+        if (*(*current_item) != "x")
+          return ValidateExtension(current_item, splitted, error,
+                    usedTags);
+        return true;
+      }
+      ++(*current_item);
+    }
+  }
+  return true;
+}
+bool ValidatePrivateUse(std::vector<std::string>::iterator *current_item,
+                    const std::vector<std::string> &splitted,
+                    std::string *error) {
+  if (*(*current_item) == "x") {
+    ++(*current_item);
+    if ((*current_item) == splitted.end() ||
+            (*(*current_item)).size() == kSingletonTagSize) {
+      if (error)
+        *error = std::string("At least one private use tag should be provided");
+      return false;
+    }
+    if (!CheckProperPrivateTagLength(current_item, error))
+      return false;
+    ++(*current_item);
+    if ((*current_item) != splitted.end())
+      return false;
+  }
+  return true;
+}
 }  // namespace
 
 namespace utils {
@@ -87,32 +177,21 @@ bool ValidateLanguageTag(const std::string& tag, std::string* error) {
       return true;
   }
 
-  // TODO(w.kosowicz): variant prefix check
-  if (kW3CVariant.find(ToLower(*current_item)) != kW3CVariant.end()) {
+  while (kW3CVariant.find(ToLower(*current_item)) != kW3CVariant.end()) {
     ++current_item;
     if (current_item == splitted_tag.end())
       return true;
   }
-  // extension private tag validation
-  if ((*current_item).size() != kSingletonTagSize) {
-    if (error)
-      *error = std::string("Singletion subtag should be of size ") +
-        std::to_string(kSingletonTagSize);
+  std::unordered_set<std::string> usedTags;
+  if (!ValidateExtension(&current_item, splitted_tag, error, &usedTags))
     return false;
-  }
-  ++current_item;
   if (current_item == splitted_tag.end())
+    return true;
+  if (!ValidatePrivateUse(&current_item, splitted_tag, error))
     return false;
-  for (auto it = current_item; it != splitted_tag.end(); ++current_item) {
-    auto tag_length = (*current_item).size();
-    if (tag_length > kMaximumExtensionTagSize) {
-      if (error)
-        *error = std::string("Any extensions should be maximum ") +
-            std::to_string(kMaximumExtensionTagSize) + "characters";
-      return false;
-    }
-  }
-  return true;
+  if (current_item == splitted_tag.end())
+    return true;
+  return false;
 }
 
 }  // namespace w3c_languages