static void DeserializePrefs(const char *prefsTxt, SerializableGlobalPrefs& globalPrefs, FileHistory& fh, Favorites *favs) { BencObj *obj = BencObj::Decode(prefsTxt); if (!obj || obj->Type() != BT_DICT) goto Exit; BencDict *prefs = static_cast<BencDict *>(obj); BencDict *global = prefs->GetDict(GLOBAL_PREFS_STR); if (!global) goto Exit; DeserializeStruct(gGlobalPrefInfo, dimof(gGlobalPrefInfo), &globalPrefs, global); free(globalPrefs.prevSerialization); globalPrefs.prevSerialization = global->Encode(); int weekDiff = GetWeekCount() - globalPrefs.openCountWeek; globalPrefs.openCountWeek = GetWeekCount(); BencArray *fileHistory = prefs->GetArray(FILE_HISTORY_STR); if (!fileHistory) goto Exit; size_t dlen = fileHistory->Length(); for (size_t i = 0; i < dlen; i++) { BencDict *dict = fileHistory->GetDict(i); assert(dict); if (!dict) continue; DisplayState *state = DeserializeDisplayState(dict, globalPrefs.globalPrefsOnly); if (state) { // "age" openCount statistics (cut in in half after every week) state->openCount >>= weekDiff; fh.Append(state); } } BencArray *favsArr = prefs->GetArray(FAVS_STR); if (!favsArr) goto Exit; for (size_t i = 0; i < favsArr->Length(); i += 2) { BencString *filePathBenc = favsArr->GetString(i); BencArray *favData = favsArr->GetArray(i+1); if (!filePathBenc || !favData) break; ScopedMem<WCHAR> filePath(filePathBenc->Value()); for (size_t j = 0; j < favData->Length(); j += 2) { // we're lenient about errors BencInt *pageNoBenc = favData->GetInt(j); BencString *nameBenc = favData->GetString(j + 1); if (!pageNoBenc || !nameBenc) break; int pageNo = (int)pageNoBenc->Value(); ScopedMem<WCHAR> name(nameBenc->Value()); favs->AddOrReplace(filePath, pageNo, EmptyToNull(name)); } } Exit: delete obj; }
static void BencTestParseDict(const char *benc, size_t expectedLen) { BencObj *obj = BencObj::Decode(benc); assert(obj); assert(obj->Type() == BT_DICT); assert(static_cast<BencDict *>(obj)->Length() == expectedLen); BencTestSerialization(obj, benc); delete obj; }
static void BencTestParseArray(const char *benc, size_t expectedLen) { BencObj *obj = BencObj::Decode(benc); utassert(obj); utassert(obj->Type() == BT_ARRAY); utassert(static_cast<BencArray *>(obj)->Length() == expectedLen); BencTestSerialization(obj, benc); delete obj; }
static void BencTestParseInt() { struct { const char * benc; bool valid; int64_t value; } testData[] = { { NULL, false }, { "", false }, { "a", false }, { "0", false }, { "i", false }, { "ie", false }, { "i0", false }, { "i1", false }, { "i23", false }, { "i-", false }, { "i-e", false }, { "i-0e", false }, { "i23f", false }, { "i2-3e", false }, { "i23-e", false }, { "i041e", false }, { "i9223372036854775808e", false }, { "i-9223372036854775809e", false }, { "i0e", true, 0 }, { "i1e", true, 1 }, { "i9823e", true, 9823 }, { "i-1e", true, -1 }, { "i-53e", true, -53 }, { "i123e", true, 123 }, { "i2147483647e", true, INT_MAX }, { "i2147483648e", true, (int64_t)INT_MAX + 1 }, { "i-2147483648e", true, INT_MIN }, { "i-2147483649e", true, (int64_t)INT_MIN - 1 }, { "i9223372036854775807e", true, _I64_MAX }, { "i-9223372036854775808e", true, _I64_MIN }, }; for (int i = 0; i < dimof(testData); i++) { BencObj *obj = BencObj::Decode(testData[i].benc); if (testData[i].valid) { assert(obj); assert(obj->Type() == BT_INT); assert(static_cast<BencInt *>(obj)->Value() == testData[i].value); BencTestSerialization(obj, testData[i].benc); delete obj; } else { assert(!obj); } } }
static void BencTestParseString() { struct { const char * benc; WCHAR * value; } testData[] = { { NULL, NULL }, { "", NULL }, { "0", NULL }, { "1234", NULL }, { "a", NULL }, { ":", NULL }, { ":z", NULL }, { "1:ab", NULL }, { "3:ab", NULL }, { "-2:ab", NULL }, { "2e:ab", NULL }, { "0:", L"" }, { "1:a", L"a" }, { "2::a", L":a" }, { "4:spam", L"spam" }, { "4:i23e", L"i23e" }, { "5:\xC3\xA4\xE2\x82\xAC", L"\u00E4\u20AC" }, }; for (int i = 0; i < dimof(testData); i++) { BencObj *obj = BencObj::Decode(testData[i].benc); if (testData[i].value) { assert(obj); assert(obj->Type() == BT_STRING); ScopedMem<WCHAR> value(static_cast<BencString *>(obj)->Value()); assert(str::Eq(value, testData[i].value)); BencTestSerialization(obj, testData[i].benc); delete obj; } else { assert(!obj); } } }
static void BencTestStress() { char key[64]; char val[64]; WCHAR tval[64]; Vec<BencObj*> stack(29); BencDict *startDict = new BencDict(); BencDict *d = startDict; BencArray *a = NULL; srand((unsigned int)time(NULL)); // generate new dict or array with 5% probability each, close an array or // dict with 8% probability (less than 10% probability of opening one, to // encourage nesting), generate int, string or raw strings uniformly // across the remaining 72% probability for (int i = 0; i < 10000; i++) { int n = rand() % 100; if (n < 5) { BencDict *nd = new BencDict(); if (a) { a->Add(nd); } else { GenRandStr(key, dimof(key)); d->Add(key, nd); } stack.Push(nd); d = nd; a = NULL; } else if (n < 10) { BencArray *na = new BencArray(); if (a) { a->Add(na); } else { GenRandStr(key, dimof(key)); d->Add(key, na); } stack.Push(na); d = NULL; a = na; } else if (n < 18) { if (stack.Count() > 0) { n = rand() % 100; stack.Pop(); BencObj *o = startDict; if (stack.Count() > 0) { o = stack.Last(); } a = NULL; d = NULL; if (BT_ARRAY == o->Type()) { a = static_cast<BencArray *>(o); } else { d = static_cast<BencDict *>(o); } } } else if (n < (18 + 24)) { int64_t v = rand(); if (a) { a->Add(v); } else { GenRandStr(key, dimof(key)); d->Add(key, v); } } else if (n < (18 + 24 + 24)) { GenRandStr(val, dimof(val)); if (a) { a->AddRaw((const char*)val); } else { GenRandStr(key, dimof(key)); d->AddRaw((const char*)key, val); } } else { GenRandTStr(tval, dimof(tval)); if (a) { a->Add(tval); } else { GenRandStr(key, dimof(key)); d->Add((const char*)key, (const WCHAR *)val); } } } char *s = startDict->Encode(); free(s); delete startDict; }
static void DeserializePrefs(const char *prefsTxt, SerializableGlobalPrefs& globalPrefs, FileHistory& fh, Favorites *favs) { BencObj *obj = BencObj::Decode(prefsTxt); if (!obj || obj->Type() != BT_DICT) goto Exit; BencDict *prefs = static_cast<BencDict *>(obj); BencDict *global = prefs->GetDict(GLOBAL_PREFS_STR); if (!global) goto Exit; Retrieve(global, TOOLBAR_VISIBLE_STR, globalPrefs.toolbarVisible); Retrieve(global, TOC_VISIBLE_STR, globalPrefs.tocVisible); Retrieve(global, FAV_VISIBLE_STR, globalPrefs.favVisible); Retrieve(global, SIDEBAR_DX_STR, globalPrefs.sidebarDx); Retrieve(global, TOC_DY_STR, globalPrefs.tocDy); Retrieve(global, PDF_ASSOCIATE_DONT_ASK_STR, globalPrefs.pdfAssociateDontAskAgain); Retrieve(global, PDF_ASSOCIATE_ASSOCIATE_STR, globalPrefs.pdfAssociateShouldAssociate); Retrieve(global, ESC_TO_EXIT_STR, globalPrefs.escToExit); Retrieve(global, USE_SYS_COLORS_STR, globalPrefs.useSysColors); Retrieve(global, BG_COLOR_STR, globalPrefs.bgColor); Retrieve(global, ENABLE_AUTO_UPDATE_STR, globalPrefs.enableAutoUpdate); Retrieve(global, REMEMBER_OPENED_FILES_STR, globalPrefs.rememberOpenedFiles); Retrieve(global, GLOBAL_PREFS_ONLY_STR, globalPrefs.globalPrefsOnly); Retrieve(global, SHOW_RECENT_FILES_STR, globalPrefs.showStartPage); Retrieve(global, DISPLAY_MODE_STR, globalPrefs.defaultDisplayMode); Retrieve(global, ZOOM_VIRTUAL_STR, globalPrefs.defaultZoom); Retrieve(global, WINDOW_STATE_STR, globalPrefs.windowState); Retrieve(global, WINDOW_X_STR, globalPrefs.windowPos.x); Retrieve(global, WINDOW_Y_STR, globalPrefs.windowPos.y); Retrieve(global, WINDOW_DX_STR, globalPrefs.windowPos.dx); Retrieve(global, WINDOW_DY_STR, globalPrefs.windowPos.dy); Retrieve(global, INVERSE_SEARCH_COMMANDLINE, globalPrefs.inverseSearchCmdLine); Retrieve(global, ENABLE_TEX_ENHANCEMENTS_STR, globalPrefs.enableTeXEnhancements); Retrieve(global, VERSION_TO_SKIP_STR, globalPrefs.versionToSkip); RetrieveRaw(global, LAST_UPDATE_STR, globalPrefs.lastUpdateTime); const char *lang = GetRawString(global, UI_LANGUAGE_STR); const char *langCode = trans::ValidateLanguageCode(lang); if (langCode) globalPrefs.currentLanguage = langCode; Retrieve(global, FWDSEARCH_OFFSET, globalPrefs.fwdSearch.offset); Retrieve(global, FWDSEARCH_COLOR, globalPrefs.fwdSearch.color); Retrieve(global, FWDSEARCH_WIDTH, globalPrefs.fwdSearch.width); Retrieve(global, FWDSEARCH_PERMANENT, globalPrefs.fwdSearch.permanent); Retrieve(global, CBX_RIGHT2LEFT, globalPrefs.cbxR2L); Retrieve(global, OPEN_COUNT_WEEK_STR, globalPrefs.openCountWeek); int weekDiff = GetWeekCount() - globalPrefs.openCountWeek; globalPrefs.openCountWeek = GetWeekCount(); BencArray *fileHistory = prefs->GetArray(FILE_HISTORY_STR); if (!fileHistory) goto Exit; size_t dlen = fileHistory->Length(); for (size_t i = 0; i < dlen; i++) { BencDict *dict = fileHistory->GetDict(i); assert(dict); if (!dict) continue; DisplayState *state = DeserializeDisplayState(dict, globalPrefs.globalPrefsOnly); if (state) { // "age" openCount statistics (cut in in half after every week) state->openCount >>= weekDiff; fh.Append(state); } } BencArray *favsArr = prefs->GetArray(FAVS_STR); if (!favsArr) goto Exit; for (size_t i = 0; i < favsArr->Length(); i += 2) { BencString *filePathBenc = favsArr->GetString(i); BencArray *favData = favsArr->GetArray(i+1); if (!filePathBenc || !favData) break; ScopedMem<WCHAR> filePath(filePathBenc->Value()); for (size_t j = 0; j < favData->Length(); j += 2) { // we're lenient about errors BencInt *pageNoBenc = favData->GetInt(j); BencString *nameBenc = favData->GetString(j + 1); if (!pageNoBenc || !nameBenc) break; int pageNo = (int)pageNoBenc->Value(); ScopedMem<WCHAR> name(nameBenc->Value()); favs->AddOrReplace(filePath, pageNo, EmptyToNull(name)); } } Exit: delete obj; }
void SelectTranslation(const WCHAR *exePath=NULL) { LANGID langId = GetUserDefaultUILanguage(); int idx = GetLanguageIndex(langId); if (-1 == idx) { // try a neutral language if the specific sublanguage isn't available langId = MAKELANGID(PRIMARYLANGID(langId), SUBLANG_NEUTRAL); idx = GetLanguageIndex(langId); } if (-1 != idx) { gTranslationIdx = idx; plogf("sp: Detected language %s (%d)", gLanguages[idx / gTranslationsCount], idx); } // try to extract the language used by SumatraPDF ScopedMem<WCHAR> path; if (exePath) { path.Set(path::GetDir(exePath)); path.Set(path::Join(path, PREFS_FILE_NAME)); } if (!file::Exists(path)) { path.Set(GetSpecialFolder(CSIDL_APPDATA)); path.Set(path::Join(path, L"SumatraPDF\\" PREFS_FILE_NAME)); } if (!file::Exists(path)) return; plogf("sp: Found preferences at %S", path); #ifndef USE_INI_SETTINGS ScopedMem<char> data(file::ReadAll(path, NULL)); if (data) { BencObj *root = BencObj::Decode(data); if (root && root->Type() == BT_DICT) { BencDict *global = static_cast<BencDict *>(root)->GetDict("gp"); BencString *string = global ? global->GetString("UILanguage") : NULL; if (string) { plogf("sp: UILanguage from preferences: %s", string->RawValue()); for (int i = 0; gLanguages[i]; i++) { if (str::Eq(gLanguages[i], string->RawValue())) { gTranslationIdx = i * gTranslationsCount; break; } } } } delete root; } #else IniFile ini(path); IniSection *section = ini.FindSection(NULL); IniLine *line = section ? section->FindLine("CurrLangCode") : NULL; if (line) { plogf("sp: UILanguage from preferences: %s", line->value); for (int i = 0; gLanguages[i]; i++) { if (str::Eq(gLanguages[i], line->value)) { gTranslationIdx = i * gTranslationsCount; break; } } } #endif }