toolkit/mozapps/update/common/readstrings.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/mozapps/update/common/readstrings.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,236 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include <limits.h>
    1.11 +#include <string.h>
    1.12 +#include <stdio.h>
    1.13 +#include "readstrings.h"
    1.14 +#include "errors.h"
    1.15 +
    1.16 +#ifdef XP_WIN
    1.17 +# define NS_tfopen _wfopen
    1.18 +# define OPEN_MODE L"rb"
    1.19 +#else
    1.20 +# define NS_tfopen fopen
    1.21 +# define OPEN_MODE "r"
    1.22 +#endif
    1.23 +
    1.24 +// stack based FILE wrapper to ensure that fclose is called.
    1.25 +class AutoFILE {
    1.26 +public:
    1.27 +  AutoFILE(FILE *fp) : fp_(fp) {}
    1.28 +  ~AutoFILE() { if (fp_) fclose(fp_); }
    1.29 +  operator FILE *() { return fp_; }
    1.30 +private:
    1.31 +  FILE *fp_;
    1.32 +};
    1.33 +
    1.34 +class AutoCharArray {
    1.35 +public:
    1.36 +  AutoCharArray(size_t len) { ptr_ = new char[len]; }
    1.37 +  ~AutoCharArray() { delete[] ptr_; }
    1.38 +  operator char *() { return ptr_; }
    1.39 +private:
    1.40 +  char *ptr_;
    1.41 +};
    1.42 +
    1.43 +static const char kNL[] = "\r\n";
    1.44 +static const char kEquals[] = "=";
    1.45 +static const char kWhitespace[] = " \t";
    1.46 +static const char kRBracket[] = "]";
    1.47 +
    1.48 +static const char*
    1.49 +NS_strspnp(const char *delims, const char *str)
    1.50 +{
    1.51 +  const char *d;
    1.52 +  do {
    1.53 +    for (d = delims; *d != '\0'; ++d) {
    1.54 +      if (*str == *d) {
    1.55 +        ++str;
    1.56 +        break;
    1.57 +      }
    1.58 +    }
    1.59 +  } while (*d);
    1.60 +
    1.61 +  return str;
    1.62 +}
    1.63 +
    1.64 +static char*
    1.65 +NS_strtok(const char *delims, char **str)
    1.66 +{
    1.67 +  if (!*str)
    1.68 +    return nullptr;
    1.69 +
    1.70 +  char *ret = (char*) NS_strspnp(delims, *str);
    1.71 +
    1.72 +  if (!*ret) {
    1.73 +    *str = ret;
    1.74 +    return nullptr;
    1.75 +  }
    1.76 +
    1.77 +  char *i = ret;
    1.78 +  do {
    1.79 +    for (const char *d = delims; *d != '\0'; ++d) {
    1.80 +      if (*i == *d) {
    1.81 +        *i = '\0';
    1.82 +        *str = ++i;
    1.83 +        return ret;
    1.84 +      }
    1.85 +    }
    1.86 +    ++i;
    1.87 +  } while (*i);
    1.88 +
    1.89 +  *str = nullptr;
    1.90 +  return ret;
    1.91 +}
    1.92 +
    1.93 +/**
    1.94 + * Find a key in a keyList containing zero-delimited keys ending with "\0\0".
    1.95 + * Returns a zero-based index of the key in the list, or -1 if the key is not found.
    1.96 + */
    1.97 +static int
    1.98 +find_key(const char *keyList, char* key)
    1.99 +{
   1.100 +  if (!keyList)
   1.101 +    return -1;
   1.102 +
   1.103 +  int index = 0;
   1.104 +  const char *p = keyList;
   1.105 +  while (*p)
   1.106 +  {
   1.107 +    if (strcmp(key, p) == 0)
   1.108 +      return index;
   1.109 +
   1.110 +    p += strlen(p) + 1;
   1.111 +    index++;
   1.112 +  }
   1.113 +
   1.114 +  // The key was not found if we came here
   1.115 +  return -1;
   1.116 +}
   1.117 +
   1.118 +/**
   1.119 + * A very basic parser for updater.ini taken mostly from nsINIParser.cpp
   1.120 + * that can be used by standalone apps.
   1.121 + *
   1.122 + * @param path       Path to the .ini file to read
   1.123 + * @param keyList    List of zero-delimited keys ending with two zero characters
   1.124 + * @param numStrings Number of strings to read into results buffer - must be equal to the number of keys
   1.125 + * @param results    Two-dimensional array of strings to be filled in the same order as the keys provided
   1.126 + * @param section    Optional name of the section to read; defaults to "Strings"
   1.127 + */
   1.128 +int
   1.129 +ReadStrings(const NS_tchar *path,
   1.130 +            const char *keyList,
   1.131 +            unsigned int numStrings,
   1.132 +            char results[][MAX_TEXT_LEN],
   1.133 +            const char *section)
   1.134 +{
   1.135 +  AutoFILE fp = NS_tfopen(path, OPEN_MODE);
   1.136 +
   1.137 +  if (!fp)
   1.138 +    return READ_ERROR;
   1.139 +
   1.140 +  /* get file size */
   1.141 +  if (fseek(fp, 0, SEEK_END) != 0)
   1.142 +    return READ_ERROR;
   1.143 +
   1.144 +  long len = ftell(fp);
   1.145 +  if (len <= 0)
   1.146 +    return READ_ERROR;
   1.147 +
   1.148 +  size_t flen = size_t(len);
   1.149 +  AutoCharArray fileContents(flen + 1);
   1.150 +  if (!fileContents)
   1.151 +    return READ_STRINGS_MEM_ERROR;
   1.152 +
   1.153 +  /* read the file in one swoop */
   1.154 +  if (fseek(fp, 0, SEEK_SET) != 0)
   1.155 +    return READ_ERROR;
   1.156 +
   1.157 +  size_t rd = fread(fileContents, sizeof(char), flen, fp);
   1.158 +  if (rd != flen)
   1.159 +    return READ_ERROR;
   1.160 +
   1.161 +  fileContents[flen] = '\0';
   1.162 +
   1.163 +  char *buffer = fileContents;
   1.164 +  bool inStringsSection = false;
   1.165 +
   1.166 +  unsigned int read = 0;
   1.167 +
   1.168 +  while (char *token = NS_strtok(kNL, &buffer)) {
   1.169 +    if (token[0] == '#' || token[0] == ';') // it's a comment
   1.170 +      continue;
   1.171 +
   1.172 +    token = (char*) NS_strspnp(kWhitespace, token);
   1.173 +    if (!*token) // empty line
   1.174 +      continue;
   1.175 +
   1.176 +    if (token[0] == '[') { // section header!
   1.177 +      ++token;
   1.178 +      char const * currSection = token;
   1.179 +
   1.180 +      char *rb = NS_strtok(kRBracket, &token);
   1.181 +      if (!rb || NS_strtok(kWhitespace, &token)) {
   1.182 +        // there's either an unclosed [Section or a [Section]Moretext!
   1.183 +        // we could frankly decide that this INI file is malformed right
   1.184 +        // here and stop, but we won't... keep going, looking for
   1.185 +        // a well-formed [section] to continue working with
   1.186 +        inStringsSection = false;
   1.187 +      }
   1.188 +      else {
   1.189 +        if (section)
   1.190 +          inStringsSection = strcmp(currSection, section) == 0;
   1.191 +        else
   1.192 +          inStringsSection = strcmp(currSection, "Strings") == 0;
   1.193 +      }
   1.194 +
   1.195 +      continue;
   1.196 +    }
   1.197 +
   1.198 +    if (!inStringsSection) {
   1.199 +      // If we haven't found a section header (or we found a malformed
   1.200 +      // section header), or this isn't the [Strings] section don't bother
   1.201 +      // parsing this line.
   1.202 +      continue;
   1.203 +    }
   1.204 +
   1.205 +    char *key = token;
   1.206 +    char *e = NS_strtok(kEquals, &token);
   1.207 +    if (!e)
   1.208 +      continue;
   1.209 +
   1.210 +    int keyIndex = find_key(keyList, key);
   1.211 +    if (keyIndex >= 0 && (unsigned int)keyIndex < numStrings)
   1.212 +    {
   1.213 +      strncpy(results[keyIndex], token, MAX_TEXT_LEN - 1);
   1.214 +      results[keyIndex][MAX_TEXT_LEN - 1] = '\0';
   1.215 +      read++;
   1.216 +    }
   1.217 +  }
   1.218 +
   1.219 +  return (read == numStrings) ? OK : PARSE_ERROR;
   1.220 +}
   1.221 +
   1.222 +// A wrapper function to read strings for the updater.
   1.223 +// Added for compatibility with the original code.
   1.224 +int
   1.225 +ReadStrings(const NS_tchar *path, StringTable *results)
   1.226 +{
   1.227 +  const unsigned int kNumStrings = 2;
   1.228 +  const char *kUpdaterKeys = "Title\0Info\0";
   1.229 +  char updater_strings[kNumStrings][MAX_TEXT_LEN];
   1.230 +
   1.231 +  int result = ReadStrings(path, kUpdaterKeys, kNumStrings, updater_strings);
   1.232 +
   1.233 +  strncpy(results->title, updater_strings[0], MAX_TEXT_LEN - 1);
   1.234 +  results->title[MAX_TEXT_LEN - 1] = '\0';
   1.235 +  strncpy(results->info, updater_strings[1], MAX_TEXT_LEN - 1);
   1.236 +  results->info[MAX_TEXT_LEN - 1] = '\0';
   1.237 +
   1.238 +  return result;
   1.239 +}

mercurial