static void BencTestArrayAppend() { BencArray *array = new BencArray(); for (size_t i = 1; i <= ITERATION_COUNT; i++) { array->Add(i); utassert(array->Length() == i); } array->Add(new BencDict()); for (size_t i = 1; i <= ITERATION_COUNT; i++) { BencInt *obj = array->GetInt(i - 1); utassert(obj && obj->Type() == BT_INT); utassert(obj->Value() == (int64_t)i); utassert(!array->GetString(i - 1)); utassert(!array->GetArray(i - 1)); utassert(!array->GetDict(i - 1)); } utassert(!array->GetInt(ITERATION_COUNT)); utassert(array->GetDict(ITERATION_COUNT)); BencTestRoundtrip(array); delete array->Remove(ITERATION_COUNT); delete array->Remove(0); delete array->Remove(ITERATION_COUNT + 13); utassert(array->Length() == ITERATION_COUNT - 1); utassert(array->GetInt(0)->Value() == 2); utassert(array->GetInt(ITERATION_COUNT - 2)->Value() == ITERATION_COUNT); BencTestRoundtrip(array); delete array; }
static void BencTestDictAppend() { /* test insertion in ascending order */ BencDict *dict = new BencDict(); for (size_t i = 1; i <= ITERATION_COUNT; i++) { ScopedMem<char> key(str::Format("%04u", i)); utassert(str::Len(key) == 4); dict->Add(key, i); utassert(dict->Length() == i); utassert(dict->GetInt(key)); utassert(!dict->GetString(key)); utassert(!dict->GetArray(key)); utassert(!dict->GetDict(key)); } BencInt *intObj = dict->GetInt("0123"); utassert(intObj && intObj->Value() == 123); BencTestRoundtrip(dict); delete dict; /* test insertion in descending order */ dict = new BencDict(); for (size_t i = ITERATION_COUNT; i > 0; i--) { ScopedMem<char> key(str::Format("%04u", i)); utassert(str::Len(key) == 4); BencObj *obj = new BencInt(i); dict->Add(key, obj); utassert(dict->Length() == ITERATION_COUNT + 1 - i); utassert(dict->GetInt(key)); } intObj = dict->GetInt("0123"); utassert(intObj && intObj->Value() == 123); BencTestRoundtrip(dict); delete dict; dict = new BencDict(); dict->Add("ab", 1); dict->Add("KL", 2); dict->Add("gh", 3); dict->Add("YZ", 4); dict->Add("ab", 5); BencTestSerialization(dict, "d2:KLi2e2:YZi4e2:abi5e2:ghi3ee"); delete dict->Remove("gh"); delete dict->Remove("YZ"); delete dict->Remove("missing"); BencTestSerialization(dict, "d2:KLi2e2:abi5ee"); delete dict; }
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 DeserializeToc(BencDict *dict, DisplayState *ds) { BencArray *tocState = dict->GetArray(TOC_STATE_STR); if (!tocState) return; size_t len = tocState->Length(); ds->tocState = new Vec<int>(len); if (!ds->tocState) return; for (size_t i = 0; i < len; i++) { BencInt *intObj = tocState->GetInt(i); if (intObj) ds->tocState->Append((int)intObj->Value()); } }
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; }
static void Retrieve(BencDict *dict, const char *key, bool& value) { BencInt *intObj = dict->GetInt(key); if (intObj) value = intObj->Value() != 0; }
static void Retrieve(BencDict *dict, const char *key, int& value) { BencInt *intObj = dict->GetInt(key); if (intObj) value = (int)intObj->Value(); }
static void DeserializeStruct(PrefInfo *info, size_t count, void *structBase, BencDict *prefs) { char *base = (char *)structBase; BencInt *intObj; BencString *strObj; BencArray *arrObj; for (size_t i = 0; i < count; i++) { PrefInfo& meta = info[i]; switch (meta.type) { case Pref_Bool: if ((intObj = prefs->GetInt(meta.name))) *(bool *)(base + meta.offset) = intObj->Value() != 0; break; case Pref_Int: if ((intObj = prefs->GetInt(meta.name))) *(int *)(base + meta.offset) = (int)intObj->Value(); break; case Pref_Str: if ((strObj = prefs->GetString(meta.name))) str::ReplacePtr((char **)(base + meta.offset), strObj->RawValue()); break; case Pref_WStr: if ((strObj = prefs->GetString(meta.name))) { ScopedMem<WCHAR> str(strObj->Value()); if (str) str::ReplacePtr((WCHAR **)(base + meta.offset), str); } break; case Pref_DisplayMode: if ((strObj = prefs->GetString(meta.name))) { ScopedMem<WCHAR> mode(strObj->Value()); if (mode) DisplayModeConv::EnumFromName(mode, (DisplayMode *)(base + meta.offset)); } break; case Pref_Float: if ((strObj = prefs->GetString(meta.name))) { // note: this might round the value for files produced with versions // prior to 1.6 and on a system where the decimal mark isn't a '.' // (the difference should be hardly notable, though) *(float *)(base + meta.offset) = (float)atof(strObj->RawValue()); } break; case Pref_IntVec: if ((arrObj = prefs->GetArray(meta.name))) { size_t len = arrObj->Length(); Vec<int> *intVec = new Vec<int>(len); if (intVec) { for (size_t idx = 0; idx < len; idx++) { if ((intObj = arrObj->GetInt(idx))) intVec->Append((int)intObj->Value()); } delete *(Vec<int> **)(base + meta.offset); *(Vec<int> **)(base + meta.offset) = intVec; } } break; case Pref_UILang: if ((strObj = prefs->GetString(meta.name))) { // ensure language code is valid const char *langCode = trans::ValidateLangCode(strObj->RawValue()); if (langCode) *(const char **)(base + meta.offset) = langCode; } break; } } }