xpcom/glue/nsINIParser.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 // Moz headers (alphabetical)
michael@0 7 #include "nsCRTGlue.h"
michael@0 8 #include "nsError.h"
michael@0 9 #include "nsIFile.h"
michael@0 10 #include "nsINIParser.h"
michael@0 11 #include "mozilla/FileUtils.h" // AutoFILE
michael@0 12
michael@0 13 // System headers (alphabetical)
michael@0 14 #include <stdio.h>
michael@0 15 #include <stdlib.h>
michael@0 16 #ifdef XP_WIN
michael@0 17 #include <windows.h>
michael@0 18 #endif
michael@0 19
michael@0 20 #if defined(XP_WIN)
michael@0 21 #define READ_BINARYMODE L"rb"
michael@0 22 #else
michael@0 23 #define READ_BINARYMODE "r"
michael@0 24 #endif
michael@0 25
michael@0 26 #ifdef XP_WIN
michael@0 27 inline FILE *TS_tfopen (const char *path, const wchar_t *mode)
michael@0 28 {
michael@0 29 wchar_t wPath[MAX_PATH];
michael@0 30 MultiByteToWideChar(CP_UTF8, 0, path, -1, wPath, MAX_PATH);
michael@0 31 return _wfopen(wPath, mode);
michael@0 32 }
michael@0 33 #else
michael@0 34 inline FILE *TS_tfopen (const char *path, const char *mode)
michael@0 35 {
michael@0 36 return fopen(path, mode);
michael@0 37 }
michael@0 38 #endif
michael@0 39
michael@0 40 // Stack based FILE wrapper to ensure that fclose is called, copied from
michael@0 41 // toolkit/mozapps/update/updater/readstrings.cpp
michael@0 42
michael@0 43 class AutoFILE {
michael@0 44 public:
michael@0 45 AutoFILE(FILE *fp = nullptr) : fp_(fp) {}
michael@0 46 ~AutoFILE() { if (fp_) fclose(fp_); }
michael@0 47 operator FILE *() { return fp_; }
michael@0 48 FILE** operator &() { return &fp_; }
michael@0 49 void operator=(FILE *fp) { fp_ = fp; }
michael@0 50 private:
michael@0 51 FILE *fp_;
michael@0 52 };
michael@0 53
michael@0 54 nsresult
michael@0 55 nsINIParser::Init(nsIFile* aFile)
michael@0 56 {
michael@0 57 /* open the file. Don't use OpenANSIFileDesc, because you mustn't
michael@0 58 pass FILE* across shared library boundaries, which may be using
michael@0 59 different CRTs */
michael@0 60
michael@0 61 AutoFILE fd;
michael@0 62
michael@0 63 #ifdef XP_WIN
michael@0 64 nsAutoString path;
michael@0 65 nsresult rv = aFile->GetPath(path);
michael@0 66 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 67 return rv;
michael@0 68
michael@0 69 fd = _wfopen(path.get(), READ_BINARYMODE);
michael@0 70 #else
michael@0 71 nsAutoCString path;
michael@0 72 aFile->GetNativePath(path);
michael@0 73
michael@0 74 fd = fopen(path.get(), READ_BINARYMODE);
michael@0 75 #endif
michael@0 76
michael@0 77 if (!fd)
michael@0 78 return NS_ERROR_FAILURE;
michael@0 79
michael@0 80 return InitFromFILE(fd);
michael@0 81 }
michael@0 82
michael@0 83 nsresult
michael@0 84 nsINIParser::Init(const char *aPath)
michael@0 85 {
michael@0 86 /* open the file */
michael@0 87 AutoFILE fd = TS_tfopen(aPath, READ_BINARYMODE);
michael@0 88
michael@0 89 if (!fd)
michael@0 90 return NS_ERROR_FAILURE;
michael@0 91
michael@0 92 return InitFromFILE(fd);
michael@0 93 }
michael@0 94
michael@0 95 static const char kNL[] = "\r\n";
michael@0 96 static const char kEquals[] = "=";
michael@0 97 static const char kWhitespace[] = " \t";
michael@0 98 static const char kRBracket[] = "]";
michael@0 99
michael@0 100 nsresult
michael@0 101 nsINIParser::InitFromFILE(FILE *fd)
michael@0 102 {
michael@0 103 /* get file size */
michael@0 104 if (fseek(fd, 0, SEEK_END) != 0)
michael@0 105 return NS_ERROR_FAILURE;
michael@0 106
michael@0 107 long flen = ftell(fd);
michael@0 108 if (flen == 0)
michael@0 109 return NS_ERROR_FAILURE;
michael@0 110
michael@0 111 /* malloc an internal buf the size of the file */
michael@0 112 mFileContents = new char[flen + 2];
michael@0 113 if (!mFileContents)
michael@0 114 return NS_ERROR_OUT_OF_MEMORY;
michael@0 115
michael@0 116 /* read the file in one swoop */
michael@0 117 if (fseek(fd, 0, SEEK_SET) != 0)
michael@0 118 return NS_BASE_STREAM_OSERROR;
michael@0 119
michael@0 120 int rd = fread(mFileContents, sizeof(char), flen, fd);
michael@0 121 if (rd != flen)
michael@0 122 return NS_BASE_STREAM_OSERROR;
michael@0 123
michael@0 124 // We write a UTF16 null so that the file is easier to convert to UTF8
michael@0 125 mFileContents[flen] = mFileContents[flen + 1] = '\0';
michael@0 126
michael@0 127 char *buffer = &mFileContents[0];
michael@0 128
michael@0 129 if (flen >= 3
michael@0 130 && mFileContents[0] == static_cast<char>(0xEF)
michael@0 131 && mFileContents[1] == static_cast<char>(0xBB)
michael@0 132 && mFileContents[2] == static_cast<char>(0xBF)) {
michael@0 133 // Someone set us up the Utf-8 BOM
michael@0 134 // This case is easy, since we assume that BOM-less
michael@0 135 // files are Utf-8 anyway. Just skip the BOM and process as usual.
michael@0 136 buffer = &mFileContents[3];
michael@0 137 }
michael@0 138
michael@0 139 #ifdef XP_WIN
michael@0 140 if (flen >= 2
michael@0 141 && mFileContents[0] == static_cast<char>(0xFF)
michael@0 142 && mFileContents[1] == static_cast<char>(0xFE)) {
michael@0 143 // Someone set us up the Utf-16LE BOM
michael@0 144 buffer = &mFileContents[2];
michael@0 145 // Get the size required for our Utf8 buffer
michael@0 146 flen = WideCharToMultiByte(CP_UTF8,
michael@0 147 0,
michael@0 148 reinterpret_cast<LPWSTR>(buffer),
michael@0 149 -1,
michael@0 150 nullptr,
michael@0 151 0,
michael@0 152 nullptr,
michael@0 153 nullptr);
michael@0 154 if (0 == flen) {
michael@0 155 return NS_ERROR_FAILURE;
michael@0 156 }
michael@0 157
michael@0 158 nsAutoArrayPtr<char> utf8Buffer(new char[flen]);
michael@0 159 if (0 == WideCharToMultiByte(CP_UTF8,
michael@0 160 0,
michael@0 161 reinterpret_cast<LPWSTR>(buffer),
michael@0 162 -1,
michael@0 163 utf8Buffer,
michael@0 164 flen,
michael@0 165 nullptr,
michael@0 166 nullptr)) {
michael@0 167 return NS_ERROR_FAILURE;
michael@0 168 }
michael@0 169 mFileContents = utf8Buffer.forget();
michael@0 170 buffer = mFileContents;
michael@0 171 }
michael@0 172 #endif
michael@0 173
michael@0 174 char *currSection = nullptr;
michael@0 175
michael@0 176 // outer loop tokenizes into lines
michael@0 177 while (char *token = NS_strtok(kNL, &buffer)) {
michael@0 178 if (token[0] == '#' || token[0] == ';') // it's a comment
michael@0 179 continue;
michael@0 180
michael@0 181 token = (char*) NS_strspnp(kWhitespace, token);
michael@0 182 if (!*token) // empty line
michael@0 183 continue;
michael@0 184
michael@0 185 if (token[0] == '[') { // section header!
michael@0 186 ++token;
michael@0 187 currSection = token;
michael@0 188
michael@0 189 char *rb = NS_strtok(kRBracket, &token);
michael@0 190 if (!rb || NS_strtok(kWhitespace, &token)) {
michael@0 191 // there's either an unclosed [Section or a [Section]Moretext!
michael@0 192 // we could frankly decide that this INI file is malformed right
michael@0 193 // here and stop, but we won't... keep going, looking for
michael@0 194 // a well-formed [section] to continue working with
michael@0 195 currSection = nullptr;
michael@0 196 }
michael@0 197
michael@0 198 continue;
michael@0 199 }
michael@0 200
michael@0 201 if (!currSection) {
michael@0 202 // If we haven't found a section header (or we found a malformed
michael@0 203 // section header), don't bother parsing this line.
michael@0 204 continue;
michael@0 205 }
michael@0 206
michael@0 207 char *key = token;
michael@0 208 char *e = NS_strtok(kEquals, &token);
michael@0 209 if (!e || !token)
michael@0 210 continue;
michael@0 211
michael@0 212 INIValue *v;
michael@0 213 if (!mSections.Get(currSection, &v)) {
michael@0 214 v = new INIValue(key, token);
michael@0 215 if (!v)
michael@0 216 return NS_ERROR_OUT_OF_MEMORY;
michael@0 217
michael@0 218 mSections.Put(currSection, v);
michael@0 219 continue;
michael@0 220 }
michael@0 221
michael@0 222 // Check whether this key has already been specified; overwrite
michael@0 223 // if so, or append if not.
michael@0 224 while (v) {
michael@0 225 if (!strcmp(key, v->key)) {
michael@0 226 v->value = token;
michael@0 227 break;
michael@0 228 }
michael@0 229 if (!v->next) {
michael@0 230 v->next = new INIValue(key, token);
michael@0 231 if (!v->next)
michael@0 232 return NS_ERROR_OUT_OF_MEMORY;
michael@0 233 break;
michael@0 234 }
michael@0 235 v = v->next;
michael@0 236 }
michael@0 237 NS_ASSERTION(v, "v should never be null coming out of this loop");
michael@0 238 }
michael@0 239
michael@0 240 return NS_OK;
michael@0 241 }
michael@0 242
michael@0 243 nsresult
michael@0 244 nsINIParser::GetString(const char *aSection, const char *aKey,
michael@0 245 nsACString &aResult)
michael@0 246 {
michael@0 247 INIValue *val;
michael@0 248 mSections.Get(aSection, &val);
michael@0 249
michael@0 250 while (val) {
michael@0 251 if (strcmp(val->key, aKey) == 0) {
michael@0 252 aResult.Assign(val->value);
michael@0 253 return NS_OK;
michael@0 254 }
michael@0 255
michael@0 256 val = val->next;
michael@0 257 }
michael@0 258
michael@0 259 return NS_ERROR_FAILURE;
michael@0 260 }
michael@0 261
michael@0 262 nsresult
michael@0 263 nsINIParser::GetString(const char *aSection, const char *aKey,
michael@0 264 char *aResult, uint32_t aResultLen)
michael@0 265 {
michael@0 266 INIValue *val;
michael@0 267 mSections.Get(aSection, &val);
michael@0 268
michael@0 269 while (val) {
michael@0 270 if (strcmp(val->key, aKey) == 0) {
michael@0 271 strncpy(aResult, val->value, aResultLen);
michael@0 272 aResult[aResultLen - 1] = '\0';
michael@0 273 if (strlen(val->value) >= aResultLen)
michael@0 274 return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
michael@0 275
michael@0 276 return NS_OK;
michael@0 277 }
michael@0 278
michael@0 279 val = val->next;
michael@0 280 }
michael@0 281
michael@0 282 return NS_ERROR_FAILURE;
michael@0 283 }
michael@0 284
michael@0 285 PLDHashOperator
michael@0 286 nsINIParser::GetSectionsCB(const char *aKey, INIValue *aData,
michael@0 287 void *aClosure)
michael@0 288 {
michael@0 289 GSClosureStruct *cs = reinterpret_cast<GSClosureStruct*>(aClosure);
michael@0 290
michael@0 291 return cs->usercb(aKey, cs->userclosure) ? PL_DHASH_NEXT : PL_DHASH_STOP;
michael@0 292 }
michael@0 293
michael@0 294 nsresult
michael@0 295 nsINIParser::GetSections(INISectionCallback aCB, void *aClosure)
michael@0 296 {
michael@0 297 GSClosureStruct gs = {
michael@0 298 aCB,
michael@0 299 aClosure
michael@0 300 };
michael@0 301
michael@0 302 mSections.EnumerateRead(GetSectionsCB, &gs);
michael@0 303 return NS_OK;
michael@0 304 }
michael@0 305
michael@0 306 nsresult
michael@0 307 nsINIParser::GetStrings(const char *aSection,
michael@0 308 INIStringCallback aCB, void *aClosure)
michael@0 309 {
michael@0 310 INIValue *val;
michael@0 311
michael@0 312 for (mSections.Get(aSection, &val);
michael@0 313 val;
michael@0 314 val = val->next) {
michael@0 315
michael@0 316 if (!aCB(val->key, val->value, aClosure))
michael@0 317 return NS_OK;
michael@0 318 }
michael@0 319
michael@0 320 return NS_OK;
michael@0 321 }

mercurial