toolkit/mozapps/update/common/readstrings.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:5b35992c7e43
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include <limits.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include "readstrings.h"
11 #include "errors.h"
12
13 #ifdef XP_WIN
14 # define NS_tfopen _wfopen
15 # define OPEN_MODE L"rb"
16 #else
17 # define NS_tfopen fopen
18 # define OPEN_MODE "r"
19 #endif
20
21 // stack based FILE wrapper to ensure that fclose is called.
22 class AutoFILE {
23 public:
24 AutoFILE(FILE *fp) : fp_(fp) {}
25 ~AutoFILE() { if (fp_) fclose(fp_); }
26 operator FILE *() { return fp_; }
27 private:
28 FILE *fp_;
29 };
30
31 class AutoCharArray {
32 public:
33 AutoCharArray(size_t len) { ptr_ = new char[len]; }
34 ~AutoCharArray() { delete[] ptr_; }
35 operator char *() { return ptr_; }
36 private:
37 char *ptr_;
38 };
39
40 static const char kNL[] = "\r\n";
41 static const char kEquals[] = "=";
42 static const char kWhitespace[] = " \t";
43 static const char kRBracket[] = "]";
44
45 static const char*
46 NS_strspnp(const char *delims, const char *str)
47 {
48 const char *d;
49 do {
50 for (d = delims; *d != '\0'; ++d) {
51 if (*str == *d) {
52 ++str;
53 break;
54 }
55 }
56 } while (*d);
57
58 return str;
59 }
60
61 static char*
62 NS_strtok(const char *delims, char **str)
63 {
64 if (!*str)
65 return nullptr;
66
67 char *ret = (char*) NS_strspnp(delims, *str);
68
69 if (!*ret) {
70 *str = ret;
71 return nullptr;
72 }
73
74 char *i = ret;
75 do {
76 for (const char *d = delims; *d != '\0'; ++d) {
77 if (*i == *d) {
78 *i = '\0';
79 *str = ++i;
80 return ret;
81 }
82 }
83 ++i;
84 } while (*i);
85
86 *str = nullptr;
87 return ret;
88 }
89
90 /**
91 * Find a key in a keyList containing zero-delimited keys ending with "\0\0".
92 * Returns a zero-based index of the key in the list, or -1 if the key is not found.
93 */
94 static int
95 find_key(const char *keyList, char* key)
96 {
97 if (!keyList)
98 return -1;
99
100 int index = 0;
101 const char *p = keyList;
102 while (*p)
103 {
104 if (strcmp(key, p) == 0)
105 return index;
106
107 p += strlen(p) + 1;
108 index++;
109 }
110
111 // The key was not found if we came here
112 return -1;
113 }
114
115 /**
116 * A very basic parser for updater.ini taken mostly from nsINIParser.cpp
117 * that can be used by standalone apps.
118 *
119 * @param path Path to the .ini file to read
120 * @param keyList List of zero-delimited keys ending with two zero characters
121 * @param numStrings Number of strings to read into results buffer - must be equal to the number of keys
122 * @param results Two-dimensional array of strings to be filled in the same order as the keys provided
123 * @param section Optional name of the section to read; defaults to "Strings"
124 */
125 int
126 ReadStrings(const NS_tchar *path,
127 const char *keyList,
128 unsigned int numStrings,
129 char results[][MAX_TEXT_LEN],
130 const char *section)
131 {
132 AutoFILE fp = NS_tfopen(path, OPEN_MODE);
133
134 if (!fp)
135 return READ_ERROR;
136
137 /* get file size */
138 if (fseek(fp, 0, SEEK_END) != 0)
139 return READ_ERROR;
140
141 long len = ftell(fp);
142 if (len <= 0)
143 return READ_ERROR;
144
145 size_t flen = size_t(len);
146 AutoCharArray fileContents(flen + 1);
147 if (!fileContents)
148 return READ_STRINGS_MEM_ERROR;
149
150 /* read the file in one swoop */
151 if (fseek(fp, 0, SEEK_SET) != 0)
152 return READ_ERROR;
153
154 size_t rd = fread(fileContents, sizeof(char), flen, fp);
155 if (rd != flen)
156 return READ_ERROR;
157
158 fileContents[flen] = '\0';
159
160 char *buffer = fileContents;
161 bool inStringsSection = false;
162
163 unsigned int read = 0;
164
165 while (char *token = NS_strtok(kNL, &buffer)) {
166 if (token[0] == '#' || token[0] == ';') // it's a comment
167 continue;
168
169 token = (char*) NS_strspnp(kWhitespace, token);
170 if (!*token) // empty line
171 continue;
172
173 if (token[0] == '[') { // section header!
174 ++token;
175 char const * currSection = token;
176
177 char *rb = NS_strtok(kRBracket, &token);
178 if (!rb || NS_strtok(kWhitespace, &token)) {
179 // there's either an unclosed [Section or a [Section]Moretext!
180 // we could frankly decide that this INI file is malformed right
181 // here and stop, but we won't... keep going, looking for
182 // a well-formed [section] to continue working with
183 inStringsSection = false;
184 }
185 else {
186 if (section)
187 inStringsSection = strcmp(currSection, section) == 0;
188 else
189 inStringsSection = strcmp(currSection, "Strings") == 0;
190 }
191
192 continue;
193 }
194
195 if (!inStringsSection) {
196 // If we haven't found a section header (or we found a malformed
197 // section header), or this isn't the [Strings] section don't bother
198 // parsing this line.
199 continue;
200 }
201
202 char *key = token;
203 char *e = NS_strtok(kEquals, &token);
204 if (!e)
205 continue;
206
207 int keyIndex = find_key(keyList, key);
208 if (keyIndex >= 0 && (unsigned int)keyIndex < numStrings)
209 {
210 strncpy(results[keyIndex], token, MAX_TEXT_LEN - 1);
211 results[keyIndex][MAX_TEXT_LEN - 1] = '\0';
212 read++;
213 }
214 }
215
216 return (read == numStrings) ? OK : PARSE_ERROR;
217 }
218
219 // A wrapper function to read strings for the updater.
220 // Added for compatibility with the original code.
221 int
222 ReadStrings(const NS_tchar *path, StringTable *results)
223 {
224 const unsigned int kNumStrings = 2;
225 const char *kUpdaterKeys = "Title\0Info\0";
226 char updater_strings[kNumStrings][MAX_TEXT_LEN];
227
228 int result = ReadStrings(path, kUpdaterKeys, kNumStrings, updater_strings);
229
230 strncpy(results->title, updater_strings[0], MAX_TEXT_LEN - 1);
231 results->title[MAX_TEXT_LEN - 1] = '\0';
232 strncpy(results->info, updater_strings[1], MAX_TEXT_LEN - 1);
233 results->info[MAX_TEXT_LEN - 1] = '\0';
234
235 return result;
236 }

mercurial