auto import from //depot/cupcake/@135843
diff --git a/tools/localize/Values.cpp b/tools/localize/Values.cpp
new file mode 100644
index 0000000..e396f8b
--- /dev/null
+++ b/tools/localize/Values.cpp
@@ -0,0 +1,134 @@
+#include "Values.h"
+#include <stdlib.h>
+
+
+// =====================================================================================
+StringResource::StringResource(const SourcePos& p, const string& f, const Configuration& c, 
+                    const string& i, int ix, XMLNode* v, const int ve, const string& vs,
+                    const string& cmnt)
+    :pos(p),
+     file(f),
+     config(c),
+     id(i),
+     index(ix),
+     value(v),
+     version(ve),
+     versionString(vs),
+     comment(cmnt)
+{
+}
+
+StringResource::StringResource()
+    :pos(),
+     file(),
+     config(),
+     id(),
+     index(-1),
+     value(NULL),
+     version(),
+     versionString(),
+     comment()
+{
+}
+
+StringResource::StringResource(const StringResource& that)
+    :pos(that.pos),
+     file(that.file),
+     config(that.config),
+     id(that.id),
+     index(that.index),
+     value(that.value),
+     version(that.version),
+     versionString(that.versionString),
+     comment(that.comment)
+{
+}
+
+int
+StringResource::Compare(const StringResource& that) const
+{
+    if (file != that.file) {
+        return file < that.file ? -1 : 1;
+    }
+    if (id != that.id) {
+        return id < that.id ? -1 : 1;
+    }
+    if (index != that.index) {
+        return index - that.index;
+    }
+    if (config != that.config) {
+        return config < that.config ? -1 : 1;
+    }
+    if (version != that.version) {
+        return version < that.version ? -1 : 1;
+    }
+    return 0;
+}
+
+string
+StringResource::TypedID() const
+{
+    string result;
+    if (index < 0) {
+        result = "string:";
+    } else {
+        char n[20];
+        sprintf(n, "%d:", index);
+        result = "array:";
+        result += n;
+    }
+    result += id;
+    return result;
+}
+
+static void
+split(const string& raw, vector<string>*parts)
+{
+    size_t index = 0;
+    while (true) {
+        size_t next = raw.find(':', index);
+        if (next != raw.npos) {
+            parts->push_back(string(raw, index, next-index));
+            index = next + 1;
+        } else {
+            parts->push_back(string(raw, index));
+            break;
+        }
+    }
+}
+
+bool
+StringResource::ParseTypedID(const string& raw, string* id, int* index)
+{
+    vector<string> parts;
+    split(raw, &parts);
+
+    const size_t N = parts.size();
+
+    for (size_t i=0; i<N; i++) {
+        if (parts[i].length() == 0) {
+            return false;
+        }
+    }
+
+    if (N == 2 && parts[0] == "string") {
+        *id = parts[1];
+        *index = -1;
+        return true;
+    }
+    else if (N == 3 && parts[0] == "array") {
+        char* p;
+        int n = (int)strtol(parts[1].c_str(), &p, 0);
+        if (*p == '\0') {
+            *id = parts[2];
+            *index = n;
+            return true;
+        } else {
+            return false;
+        }
+    }
+    else {
+        return false;
+    }
+}
+