void CalcSha2DigestWin(const void *data, size_t byteCount, unsigned char digest[32]) { HCRYPTPROV hProv = 0; HCRYPTHASH hHash = 0; BOOL ok = CryptAcquireContext(&hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); if (!ok) { // TODO: test this on XP SP3 ok = CryptAcquireContext(&hProv, NULL, MS_ENH_RSA_AES_PROV_XP, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); } CrashAlwaysIf(!ok); ok = CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash); CrashAlwaysIf(!ok); #ifdef _WIN64 for (; byteCount > DWORD_MAX; data = (const BYTE *)data + DWORD_MAX, byteCount -= DWORD_MAX) { ok = CryptHashData(hHash, (const BYTE *)data, DWORD_MAX, 0); CrashAlwaysIf(!ok); } #endif CrashAlwaysIf(byteCount > DWORD_MAX); ok = CryptHashData(hHash, (const BYTE*)data, (DWORD)byteCount, 0); CrashAlwaysIf(!ok); DWORD hashLen; DWORD argSize = sizeof(DWORD); ok = CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&hashLen, &argSize, 0); CrashIf(sizeof(DWORD) != argSize); CrashAlwaysIf(!ok); CrashAlwaysIf(32 != hashLen); ok = CryptGetHashParam(hHash, HP_HASHVAL, digest, &hashLen, 0); CrashAlwaysIf(!ok); CrashAlwaysIf(32 != hashLen); CryptDestroyHash(hHash); CryptReleaseContext(hProv,0); }
// MD5 digest that uses Windows' CryptoAPI. It's good for code that doesn't already // have MD5 code (smaller code) and it's probably faster than most other implementations // TODO: could try to use CryptoNG available starting in Vista. But then again, would that be worth it? void CalcMD5DigestWin(const void *data, size_t byteCount, unsigned char digest[16]) { HCRYPTPROV hProv = 0; HCRYPTHASH hHash = 0; // http://stackoverflow.com/questions/9794745/ms-cryptoapi-doesnt-work-on-windows-xp-with-cryptacquirecontext BOOL ok = CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); if (!ok) ok = CryptAcquireContext(&hProv, NULL, MS_ENH_RSA_AES_PROV_XP, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); CrashAlwaysIf(!ok); ok = CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash); CrashAlwaysIf(!ok); #ifdef _WIN64 for (; byteCount > DWORD_MAX; data = (const BYTE *)data + DWORD_MAX, byteCount -= DWORD_MAX) { ok = CryptHashData(hHash, (const BYTE *)data, DWORD_MAX, 0); CrashAlwaysIf(!ok); } #endif CrashAlwaysIf(byteCount > DWORD_MAX); ok = CryptHashData(hHash, (const BYTE*)data, (DWORD)byteCount, 0); CrashAlwaysIf(!ok); DWORD hashLen; DWORD argSize = sizeof(DWORD); ok = CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&hashLen, &argSize, 0); CrashIf(sizeof(DWORD) != argSize); CrashAlwaysIf(!ok); CrashAlwaysIf(16 != hashLen); ok = CryptGetHashParam(hHash, HP_HASHVAL, digest, &hashLen, 0); CrashAlwaysIf(!ok); CrashAlwaysIf(16 != hashLen); CryptDestroyHash(hHash); CryptReleaseContext(hProv,0); }
static void OnButtonInstall() { CrashAlwaysIf(gForceCrash); if (gShowOptions) OnButtonOptions(); KillSumatra(); if (!CheckInstallUninstallPossible()) return; WCHAR *userInstallDir = win::GetText(gHwndTextboxInstDir); if (!str::IsEmpty(userInstallDir)) str::ReplacePtr(&gGlobalData.installDir, userInstallDir); free(userInstallDir); // note: this checkbox isn't created if we're already registered as default // (in which case we're just going to re-register) gGlobalData.registerAsDefault = gHwndCheckboxRegisterDefault == nullptr || IsCheckboxChecked(gHwndCheckboxRegisterDefault); // note: this checkbox isn't created when running inside Wow64 gGlobalData.installPdfFilter = gHwndCheckboxRegisterPdfFilter != nullptr && IsCheckboxChecked(gHwndCheckboxRegisterPdfFilter); // note: this checkbox isn't created on Windows 2000 and XP gGlobalData.installPdfPreviewer = gHwndCheckboxRegisterPdfPreviewer != nullptr && IsCheckboxChecked(gHwndCheckboxRegisterPdfPreviewer); // note: this checkbox isn't created if the browser plugin hasn't been installed before gGlobalData.keepBrowserPlugin = gHwndCheckboxKeepBrowserPlugin != nullptr && IsCheckboxChecked(gHwndCheckboxKeepBrowserPlugin); // create a progress bar in place of the Options button RectI rc(0, 0, dpiAdjust(INSTALLER_WIN_DX / 2), gButtonDy); rc = MapRectToWindow(rc, gHwndButtonOptions, gHwndFrame); gHwndProgressBar = CreateWindow(PROGRESS_CLASS, nullptr, WS_CHILD | WS_VISIBLE, rc.x, rc.y, rc.dx, rc.dy, gHwndFrame, 0, GetModuleHandle(nullptr), nullptr); SendMessage(gHwndProgressBar, PBM_SETRANGE32, 0, GetInstallationStepCount()); SendMessage(gHwndProgressBar, PBM_SETSTEP, 1, 0); // disable the install button and remove all the installation options SafeDestroyWindow(&gHwndStaticInstDir); SafeDestroyWindow(&gHwndTextboxInstDir); SafeDestroyWindow(&gHwndButtonBrowseDir); SafeDestroyWindow(&gHwndCheckboxRegisterDefault); SafeDestroyWindow(&gHwndCheckboxRegisterPdfFilter); SafeDestroyWindow(&gHwndCheckboxRegisterPdfPreviewer); SafeDestroyWindow(&gHwndCheckboxKeepBrowserPlugin); SafeDestroyWindow(&gHwndButtonOptions); EnableWindow(gHwndButtonInstUninst, FALSE); SetMsg(_TR("Installation in progress..."), COLOR_MSG_INSTALLATION); InvalidateFrame(); gGlobalData.hThread = CreateThread(nullptr, 0, InstallerThread, nullptr, 0, 0); }
static void MobiSaveImage(const WCHAR *filePathBase, size_t imgNo, ImageData *img) { // it's valid to not have image data at a given index if (!img || !img->data) return; const WCHAR *ext = GfxFileExtFromData(img->data, img->len); CrashAlwaysIf(!ext); ScopedMem<WCHAR> fileName(str::Format(L"%s_img_%d%s", filePathBase, imgNo, ext)); file::WriteAll(fileName.Get(), img->data, img->len); }
/* Caller needs to prefs::CleanUp() */ bool Load() { CrashIf(gGlobalPrefs); ScopedMem<WCHAR> path(GetSettingsPath()); ScopedMem<char> prefsData(file::ReadAll(path, NULL)); gGlobalPrefs = (GlobalPrefs *)DeserializeStruct(&gGlobalPrefsInfo, prefsData); CrashAlwaysIf(!gGlobalPrefs); #ifdef DISABLE_EBOOK_UI if (!file::Exists(path)) gGlobalPrefs->ebookUI.useFixedPageUI = gGlobalPrefs->chmUI.useFixedPageUI = true; #endif #ifdef DISABLE_TABS if (!file::Exists(path)) gGlobalPrefs->useTabs = false; #endif if (!gGlobalPrefs->uiLanguage || !trans::ValidateLangCode(gGlobalPrefs->uiLanguage)) { // guess the ui language on first start str::ReplacePtr(&gGlobalPrefs->uiLanguage, trans::DetectUserLang()); } gGlobalPrefs->lastPrefUpdate = file::GetModificationTime(path); gGlobalPrefs->defaultDisplayModeEnum = conv::ToDisplayMode(gGlobalPrefs->defaultDisplayMode, DM_AUTOMATIC); gGlobalPrefs->defaultZoomFloat = conv::ToZoom(gGlobalPrefs->defaultZoom, ZOOM_ACTUAL_SIZE); CrashIf(!IsValidZoom(gGlobalPrefs->defaultZoomFloat)); int weekDiff = GetWeekCount() - gGlobalPrefs->openCountWeek; gGlobalPrefs->openCountWeek = GetWeekCount(); if (weekDiff > 0) { // "age" openCount statistics (cut in in half after every week) for (DisplayState **ds = gGlobalPrefs->fileStates->IterStart(); ds; ds = gGlobalPrefs->fileStates->IterNext()) { (*ds)->openCount >>= weekDiff; } } // make sure that zoom levels are in the order expected by DisplayModel gGlobalPrefs->zoomLevels->Sort(cmpFloat); while (gGlobalPrefs->zoomLevels->Count() > 0 && gGlobalPrefs->zoomLevels->At(0) < ZOOM_MIN) { gGlobalPrefs->zoomLevels->PopAt(0); } while (gGlobalPrefs->zoomLevels->Count() > 0 && gGlobalPrefs->zoomLevels->Last() > ZOOM_MAX) { gGlobalPrefs->zoomLevels->Pop(); } // TODO: verify that all states have a non-NULL file path? gFileHistory.UpdateStatesSource(gGlobalPrefs->fileStates); SetDefaultEbookFont(gGlobalPrefs->ebookUI.fontName, gGlobalPrefs->ebookUI.fontSize); if (!file::Exists(path)) Save(); return true; }
// refresh the preferences when a different SumatraPDF process saves them // or if they are edited by the user using a text editor bool Reload() { ScopedMem<WCHAR> path(GetSettingsPath()); if (!file::Exists(path)) return false; // make sure that the settings file is readable - else wait // a short while to prevent accidental dataloss int tryAgainCount = 5; HANDLE h = file::OpenReadOnly(path); while (INVALID_HANDLE_VALUE == h && tryAgainCount-- > 0) { Sleep(200); h = file::OpenReadOnly(path); } if (INVALID_HANDLE_VALUE == h) { // prefer not reloading to resetting all settings return false; } ScopedHandle hScope(h); FILETIME time = file::GetModificationTime(path); if (FileTimeEq(time, gGlobalPrefs->lastPrefUpdate)) return true; ScopedMem<char> uiLanguage(str::Dup(gGlobalPrefs->uiLanguage)); bool showToolbar = gGlobalPrefs->showToolbar; bool invertColors = gGlobalPrefs->fixedPageUI.invertColors; gFileHistory.UpdateStatesSource(NULL); CleanUp(); bool ok = Load(); CrashAlwaysIf(!ok || !gGlobalPrefs); gGlobalPrefs->fixedPageUI.invertColors = invertColors; // TODO: about window doesn't have to be at position 0 if (gWindows.Count() > 0 && gWindows.At(0)->IsAboutWindow()) { gWindows.At(0)->DeleteInfotip(); gWindows.At(0)->staticLinks.Reset(); gWindows.At(0)->RedrawAll(true); } if (!str::Eq(uiLanguage, gGlobalPrefs->uiLanguage)) SetCurrentLanguageAndRefreshUi(gGlobalPrefs->uiLanguage); if (gGlobalPrefs->showToolbar != showToolbar) ShowOrHideToolbarGlobally(); UpdateDocumentColors(); UpdateFavoritesTreeForAllWindows(); return true; }
// Select random files to test. We want to test each file type equally, so // we first group them by file extension and then select up to maxPerType // for each extension, randomly, and inter-leave the files with different // extensions, so their testing is evenly distributed. // Returns result in <files>. static void RandomizeFiles(WStrVec& files, int maxPerType) { WStrVec fileExts; Vec<WStrVec *> filesPerType; for (size_t i = 0; i < files.Count(); i++) { const WCHAR *file = files.At(i); const WCHAR *ext = path::GetExt(file); CrashAlwaysIf(!ext); int typeNo = fileExts.FindI(ext); if (-1 == typeNo) { fileExts.Append(str::Dup(ext)); filesPerType.Append(new WStrVec()); typeNo = (int)filesPerType.Count() - 1; } filesPerType.At(typeNo)->Append(str::Dup(file)); } for (size_t j = 0; j < filesPerType.Count(); j++) { WStrVec *all = filesPerType.At(j); WStrVec *random = new WStrVec(); for (int n = 0; n < maxPerType && all->Count() > 0; n++) { int idx = rand() % all->Count(); WCHAR *file = all->At(idx); random->Append(file); all->RemoveAtFast(idx); } filesPerType.At(j) = random; delete all; } files.Reset(); bool gotAll = false; while (!gotAll) { gotAll = true; for (size_t j = 0; j < filesPerType.Count(); j++) { WStrVec *random = filesPerType.At(j); if (random->Count() > 0) { gotAll = false; WCHAR *file = random->At(0); files.Append(file); random->RemoveAtFast(0); } } } for (size_t j = 0; j < filesPerType.Count(); j++) { delete filesPerType.At(j); } }
Simple *DeserializeSimple(const uint8_t *data, int dataLen, bool *usedDefaultOut) { void *res = NULL; res = Deserialize(data, dataLen, SimpleVersion, &gSimpleMetadata); if (res) { *usedDefaultOut = false; return (Simple*)res; } res = Deserialize(&gSimpleDefault[0], sizeof(gSimpleDefault), SimpleVersion, &gSimpleMetadata); CrashAlwaysIf(!res); *usedDefaultOut = true; return (Simple*)res; }
static void BenchMD5Size(void *data, size_t dataSize, char *desc) { unsigned char d1[16], d2[16]; Timer t1; CalcMD5Digest((unsigned char*)data, dataSize, d1); double dur1 = t1.GetTimeInMs(); Timer t2; CalcMD5DigestWin(data, dataSize, d2); bool same = memeq(d1, d2, 16); CrashAlwaysIf(!same); double dur2 = t2.GetTimeInMs(); double diff = dur1 - dur2; printf("%s\nCalcMD5Digest : %f ms\nCalcMD5DigestWin: %f ms\ndiff: %f\n", desc, dur1, dur2, diff); }
static void MobiSaveHtml(const WCHAR *filePathBase, MobiDoc *mb) { CrashAlwaysIf(!gSaveHtml); ScopedMem<WCHAR> outFile(str::Join(filePathBase, L"_pp.html")); size_t htmlLen; const char *html = mb->GetHtmlData(htmlLen); size_t ppHtmlLen; char *ppHtml = PrettyPrintHtml(html, htmlLen, ppHtmlLen); file::WriteAll(outFile.Get(), ppHtml, ppHtmlLen); outFile.Set(str::Join(filePathBase, L".html")); file::WriteAll(outFile.Get(), html, htmlLen); }
static void RemoveWatchedDirIfNotReferenced(WatchedDir *wd) { if (IsWatchedDirReferenced(wd)) return; WatchedDir **currPtr = &g_firstDir; WatchedDir *curr; for (;;) { curr = *currPtr; CrashAlwaysIf(!curr); if (curr == wd) break; currPtr = &(curr->next); } WatchedDir *toRemove = curr; *currPtr = toRemove->next; DeleteWatchedDir(toRemove); }
static void RemoveWatchedFile(WatchedFile *wf) { WatchedDir *wd = wf->watchedDir; WatchedFile **currPtr = &g_firstFile; WatchedFile *curr; for (;;) { curr = *currPtr; CrashAlwaysIf(!curr); if (curr == wf) break; currPtr = &(curr->next); } WatchedFile *toRemove = curr; *currPtr = toRemove->next; DeleteWatchedFile(toRemove); RemoveWatchedDirIfNotReferenced(wd); }
// Should be called from WM_PAINT. Recursively paints a given window and // all its children. Control must be the top-level window associated // with HWND. // Note: maybe should be split into BeginPaint()/Paint()/EndPaint() // calls so that the caller can do more drawing after Paint() void Painter::Paint(HWND hwnd, bool isDirty) { CrashAlwaysIf(hwnd != wnd->hwndParent); PAINTSTRUCT ps; HDC dc = BeginPaint(hwnd, &ps); Region clip; // TODO: be intelligent about only repainting changed // parts for perf. Note: if cacheBmp changes, we need // to repaint everything Graphics gDC(dc); gDC.GetClip(&clip); ClientRect r(hwnd); // TODO: fix showing black parts when resizing a window. // my theory is that we see black background on right/bottom // of the window when we resize the window because the os paints // it black and we take too long to perform the whole paint so the // black part persists long enough for human eye to notice. // To fix that we could try to paint the black part immediately // to gDC using the same color as the background. This is problematic // for two reasons: // - I don't know which part exactly needs to be repainted // - it can be tricky if background is a gradient // I thought I could just do PaintBackground(&gDC, Rect(0, 0, r.dx, r.dy)) // but that generates flickr which leads me to believe that either // Graphics::FillRectangle() ignores clip region or clip region is not set // properly. Current solution detects a resize, paints a background and the // last version of page, which somewhat eliminates the problem but also // sometimes causes flickr // See http://www.catch22.net/tuts/flicker for info on win repainting if (cacheBmp && !sizeDuringLastPaint.Equals(Size(r.dx, r.dy))) { PaintBackground(&gDC, Rect(0, 0, r.dx, r.dy)); gDC.DrawImage(cacheBmp, 0, 0); sizeDuringLastPaint = Size(r.dx, r.dy); } if (BitmapNotBigEnough(cacheBmp, r.dx, r.dy)) { ::delete cacheBmp; cacheBmp = ::new Bitmap(r.dx, r.dy, &gDC); isDirty = true; } //TODO: log clipBounds for debugging //Rect clipBounds; //clip.GetBounds(&cliBounds) // draw to a bitmap cache unless we were asked to skip // this step and just blit cached bitmap because the caller // knows it didn't change if (isDirty) { Graphics g((Image*)cacheBmp); InitGraphicsMode(&g); g.SetClip(&clip, CombineModeReplace); PaintBackground(&g, Rect(0, 0, r.dx, r.dy)); PaintWindowsInZOrder(&g, wnd); } // TODO: try to manually draw only the part that falls within // clipBounds or is it done automatically by DrawImage() ? gDC.DrawImage(cacheBmp, 0, 0); EndPaint(hwnd, &ps); }