summaryrefslogtreecommitdiff
path: root/toolkit/mozapps/update/common/readstrings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/update/common/readstrings.cpp')
-rw-r--r--toolkit/mozapps/update/common/readstrings.cpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/toolkit/mozapps/update/common/readstrings.cpp b/toolkit/mozapps/update/common/readstrings.cpp
new file mode 100644
index 0000000000..428c91c0ba
--- /dev/null
+++ b/toolkit/mozapps/update/common/readstrings.cpp
@@ -0,0 +1,236 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include "readstrings.h"
+#include "errors.h"
+
+#ifdef XP_WIN
+# define NS_tfopen _wfopen
+# define OPEN_MODE L"rb"
+#else
+# define NS_tfopen fopen
+# define OPEN_MODE "r"
+#endif
+
+// stack based FILE wrapper to ensure that fclose is called.
+class AutoFILE {
+public:
+ explicit AutoFILE(FILE *fp) : fp_(fp) {}
+ ~AutoFILE() { if (fp_) fclose(fp_); }
+ operator FILE *() { return fp_; }
+private:
+ FILE *fp_;
+};
+
+class AutoCharArray {
+public:
+ explicit AutoCharArray(size_t len) { ptr_ = new char[len]; }
+ ~AutoCharArray() { delete[] ptr_; }
+ operator char *() { return ptr_; }
+private:
+ char *ptr_;
+};
+
+static const char kNL[] = "\r\n";
+static const char kEquals[] = "=";
+static const char kWhitespace[] = " \t";
+static const char kRBracket[] = "]";
+
+static const char*
+NS_strspnp(const char *delims, const char *str)
+{
+ const char *d;
+ do {
+ for (d = delims; *d != '\0'; ++d) {
+ if (*str == *d) {
+ ++str;
+ break;
+ }
+ }
+ } while (*d);
+
+ return str;
+}
+
+static char*
+NS_strtok(const char *delims, char **str)
+{
+ if (!*str)
+ return nullptr;
+
+ char *ret = (char*) NS_strspnp(delims, *str);
+
+ if (!*ret) {
+ *str = ret;
+ return nullptr;
+ }
+
+ char *i = ret;
+ do {
+ for (const char *d = delims; *d != '\0'; ++d) {
+ if (*i == *d) {
+ *i = '\0';
+ *str = ++i;
+ return ret;
+ }
+ }
+ ++i;
+ } while (*i);
+
+ *str = nullptr;
+ return ret;
+}
+
+/**
+ * Find a key in a keyList containing zero-delimited keys ending with "\0\0".
+ * Returns a zero-based index of the key in the list, or -1 if the key is not found.
+ */
+static int
+find_key(const char *keyList, char* key)
+{
+ if (!keyList)
+ return -1;
+
+ int index = 0;
+ const char *p = keyList;
+ while (*p)
+ {
+ if (strcmp(key, p) == 0)
+ return index;
+
+ p += strlen(p) + 1;
+ index++;
+ }
+
+ // The key was not found if we came here
+ return -1;
+}
+
+/**
+ * A very basic parser for updater.ini taken mostly from nsINIParser.cpp
+ * that can be used by standalone apps.
+ *
+ * @param path Path to the .ini file to read
+ * @param keyList List of zero-delimited keys ending with two zero characters
+ * @param numStrings Number of strings to read into results buffer - must be equal to the number of keys
+ * @param results Two-dimensional array of strings to be filled in the same order as the keys provided
+ * @param section Optional name of the section to read; defaults to "Strings"
+ */
+int
+ReadStrings(const NS_tchar *path,
+ const char *keyList,
+ unsigned int numStrings,
+ char results[][MAX_TEXT_LEN],
+ const char *section)
+{
+ AutoFILE fp(NS_tfopen(path, OPEN_MODE));
+
+ if (!fp)
+ return READ_ERROR;
+
+ /* get file size */
+ if (fseek(fp, 0, SEEK_END) != 0)
+ return READ_ERROR;
+
+ long len = ftell(fp);
+ if (len <= 0)
+ return READ_ERROR;
+
+ size_t flen = size_t(len);
+ AutoCharArray fileContents(flen + 1);
+ if (!fileContents)
+ return READ_STRINGS_MEM_ERROR;
+
+ /* read the file in one swoop */
+ if (fseek(fp, 0, SEEK_SET) != 0)
+ return READ_ERROR;
+
+ size_t rd = fread(fileContents, sizeof(char), flen, fp);
+ if (rd != flen)
+ return READ_ERROR;
+
+ fileContents[flen] = '\0';
+
+ char *buffer = fileContents;
+ bool inStringsSection = false;
+
+ unsigned int read = 0;
+
+ while (char *token = NS_strtok(kNL, &buffer)) {
+ if (token[0] == '#' || token[0] == ';') // it's a comment
+ continue;
+
+ token = (char*) NS_strspnp(kWhitespace, token);
+ if (!*token) // empty line
+ continue;
+
+ if (token[0] == '[') { // section header!
+ ++token;
+ char const * currSection = token;
+
+ char *rb = NS_strtok(kRBracket, &token);
+ if (!rb || NS_strtok(kWhitespace, &token)) {
+ // there's either an unclosed [Section or a [Section]Moretext!
+ // we could frankly decide that this INI file is malformed right
+ // here and stop, but we won't... keep going, looking for
+ // a well-formed [section] to continue working with
+ inStringsSection = false;
+ }
+ else {
+ if (section)
+ inStringsSection = strcmp(currSection, section) == 0;
+ else
+ inStringsSection = strcmp(currSection, "Strings") == 0;
+ }
+
+ continue;
+ }
+
+ if (!inStringsSection) {
+ // If we haven't found a section header (or we found a malformed
+ // section header), or this isn't the [Strings] section don't bother
+ // parsing this line.
+ continue;
+ }
+
+ char *key = token;
+ char *e = NS_strtok(kEquals, &token);
+ if (!e)
+ continue;
+
+ int keyIndex = find_key(keyList, key);
+ if (keyIndex >= 0 && (unsigned int)keyIndex < numStrings)
+ {
+ strncpy(results[keyIndex], token, MAX_TEXT_LEN - 1);
+ results[keyIndex][MAX_TEXT_LEN - 1] = '\0';
+ read++;
+ }
+ }
+
+ return (read == numStrings) ? OK : PARSE_ERROR;
+}
+
+// A wrapper function to read strings for the updater.
+// Added for compatibility with the original code.
+int
+ReadStrings(const NS_tchar *path, StringTable *results)
+{
+ const unsigned int kNumStrings = 2;
+ const char *kUpdaterKeys = "Title\0Info\0";
+ char updater_strings[kNumStrings][MAX_TEXT_LEN];
+
+ int result = ReadStrings(path, kUpdaterKeys, kNumStrings, updater_strings);
+
+ strncpy(results->title, updater_strings[0], MAX_TEXT_LEN - 1);
+ results->title[MAX_TEXT_LEN - 1] = '\0';
+ strncpy(results->info, updater_strings[1], MAX_TEXT_LEN - 1);
+ results->info[MAX_TEXT_LEN - 1] = '\0';
+
+ return result;
+}