bool StressTest::GoToNextFile() { for (;;) { while (filesToOpen.Count() > 0) { // test next file ScopedMem<TCHAR> path(filesToOpen.At(0)); filesToOpen.RemoveAt(0); if (!IsInRange(fileRanges, ++fileIndex)) continue; if (OpenFile(path)) return true; } if (dirsToVisit.Count() > 0) { // test next directory ScopedMem<TCHAR> path(dirsToVisit.At(0)); dirsToVisit.RemoveAt(0); OpenDir(path); continue; } if (--cycles <= 0) return false; // start next cycle if (file::Exists(basePath)) filesToOpen.Append(str::Dup(basePath)); else OpenDir(basePath); } }
/* The html looks like: <li> <object type="text/sitemap"> <param name="Keyword" value="- operator"> <param name="Name" value="Subtraction Operator (-)"> <param name="Local" value="html/vsoprsubtract.htm"> <param name="Name" value="Subtraction Operator (-)"> <param name="Local" value="html/js56jsoprsubtract.htm"> </object> <ul> ... optional children ... </ul> <li> ... siblings ... */ static bool VisitChmIndexItem(EbookTocVisitor *visitor, HtmlElement *el, UINT cp, int level) { CrashIf(!el->NameIs("li")); el = el->GetChildByName("object"); if (!el) return false; StrVec references; ScopedMem<TCHAR> keyword, name; for (el = el->GetChildByName("param"); el; el = el->next) { if (!el->NameIs("param")) continue; ScopedMem<TCHAR> attrName(el->GetAttribute("name")); ScopedMem<TCHAR> attrVal(el->GetAttribute("value")); #ifdef UNICODE if (attrName && attrVal && cp != CP_CHM_DEFAULT) { ScopedMem<char> bytes(str::conv::ToCodePage(attrVal, CP_CHM_DEFAULT)); attrVal.Set(str::conv::FromCodePage(bytes, cp)); } #endif if (!attrName || !attrVal) /* ignore incomplete/unneeded <param> */; else if (str::EqI(attrName, _T("Keyword"))) keyword.Set(attrVal.StealData()); else if (str::EqI(attrName, _T("Name"))) { name.Set(attrVal.StealData()); // some CHM documents seem to use a lonely Name instead of Keyword if (!keyword) keyword.Set(str::Dup(name)); } else if (str::EqI(attrName, _T("Local")) && name) { // remove the ITS protocol and any filename references from the URLs if (str::Find(attrVal, _T("::/"))) attrVal.Set(str::Dup(str::Find(attrVal, _T("::/")) + 3)); references.Append(name.StealData()); references.Append(attrVal.StealData()); } } if (!keyword) return false; if (references.Count() == 2) { visitor->visit(keyword, references.At(1), level); return true; } visitor->visit(keyword, NULL, level); for (size_t i = 0; i < references.Count(); i += 2) { visitor->visit(references.At(i), references.At(i + 1), level + 1); } return true; }
int Pdfsync::DocToSource(UINT pageNo, PointI pt, ScopedMem<TCHAR>& filename, UINT *line, UINT *col) { if (IsIndexDiscarded()) if (RebuildIndex() != PDFSYNCERR_SUCCESS) return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED; // find the entry in the index corresponding to this page if (pageNo <= 0 || pageNo >= sheetIndex.Count() || pageNo > (UINT)engine->PageCount()) return PDFSYNCERR_INVALID_PAGE_NUMBER; // PdfSync coordinates are y-inversed RectI mbox = engine->PageMediabox(pageNo).Round(); pt.y = mbox.dy - pt.y; // distance to the closest pdf location (in the range <PDFSYNC_EPSILON_SQUARE) UINT closest_xydist = UINT_MAX; UINT selected_record = UINT_MAX; // If no record is found within a distance^2 of PDFSYNC_EPSILON_SQUARE // (selected_record == -1) then we pick up the record that is closest // vertically to the hit-point. UINT closest_ydist = UINT_MAX; // vertical distance between the hit point and the vertically-closest record UINT closest_xdist = UINT_MAX; // horizontal distance between the hit point and the vertically-closest record UINT closest_ydist_record = UINT_MAX; // vertically-closest record // read all the sections of 'p' declarations for this pdf sheet for (size_t i = sheetIndex.At(pageNo); i < points.Count() && points.At(i).page == pageNo; i++) { // check whether it is closer than the closest point found so far UINT dx = abs(pt.x - (int)SYNC_TO_PDF_COORDINATE(points.At(i).x)); UINT dy = abs(pt.y - (int)SYNC_TO_PDF_COORDINATE(points.At(i).y)); UINT dist = dx * dx + dy * dy; if (dist < PDFSYNC_EPSILON_SQUARE && dist < closest_xydist) { selected_record = points.At(i).record; closest_xydist = dist; } else if ((closest_xydist == UINT_MAX) && dy < PDFSYNC_EPSILON_Y && (dy < closest_ydist || (dy == closest_ydist && dx < closest_xdist))) { closest_ydist_record = points.At(i).record; closest_ydist = dy; closest_xdist = dx; } } if (selected_record == UINT_MAX) selected_record = closest_ydist_record; if (selected_record == UINT_MAX) return PDFSYNCERR_NO_SYNC_AT_LOCATION; // no record was found close enough to the hit point // We have a record number, we need to find its declaration ('l ...') in the syncfile PdfsyncLine cmp; cmp.record = selected_record; PdfsyncLine *found = (PdfsyncLine *)bsearch(&cmp, lines.LendData(), lines.Count(), sizeof(PdfsyncLine), cmpLineRecords); assert(found); if (!found) return PDFSYNCERR_NO_SYNC_AT_LOCATION; filename.Set(str::Dup(srcfiles.At(found->file))); *line = found->line; *col = found->column; return PDFSYNCERR_SUCCESS; }
void BenchFileOrDir(StrVec& pathsToBench) { gLog = new slog::StderrLogger(); size_t n = pathsToBench.Count() / 2; for (size_t i = 0; i < n; i++) { TCHAR *path = pathsToBench.At(2 * i); if (file::Exists(path)) BenchFile(path, pathsToBench.At(2 * i + 1)); else if (dir::Exists(path)) BenchDir(path); else logbench("Error: file or dir %s doesn't exist", path); } delete gLog; }
TCHAR *ImageDirEngineImpl::GetPageLabel(int pageNo) { if (pageNo < 1 || PageCount() < pageNo) return BaseEngine::GetPageLabel(pageNo); const TCHAR *fileName = path::GetBaseName(pageFileNames.At(pageNo - 1)); return str::DupN(fileName, path::GetExt(fileName) - fileName); }
static void StrVecTest() { StrVec v; v.Append(str::Dup(_T("foo"))); v.Append(str::Dup(_T("bar"))); TCHAR *s = v.Join(); assert(v.Count() == 2); assert(str::Eq(_T("foobar"), s)); free(s); s = v.Join(_T(";")); assert(v.Count() == 2); assert(str::Eq(_T("foo;bar"), s)); free(s); v.Append(str::Dup(_T("glee"))); s = v.Join(_T("_ _")); assert(v.Count() == 3); assert(str::Eq(_T("foo_ _bar_ _glee"), s)); free(s); v.Sort(); s = v.Join(); assert(str::Eq(_T("barfooglee"), s)); free(s); { StrVec v2(v); assert(str::Eq(v2.At(1), _T("foo"))); v2.Append(str::Dup(_T("nobar"))); assert(str::Eq(v2.At(3), _T("nobar"))); v2 = v; assert(v2.Count() == 3 && v2.At(0) != v.At(0)); assert(str::Eq(v2.At(1), _T("foo"))); assert(&v2.At(2) == v2.AtPtr(2) && str::Eq(*v2.AtPtr(2), _T("glee"))); } { StrVec v2; size_t count = v2.Split(_T("a,b,,c,"), _T(",")); assert(count == 5 && v2.Find(_T("c")) == 3); assert(v2.Find(_T("")) == 2 && v2.Find(_T(""), 3) == 4 && v2.Find(_T(""), 5) == -1); assert(v2.Find(_T("B")) == -1 && v2.FindI(_T("B")) == 1); ScopedMem<TCHAR> joined(v2.Join(_T(";"))); assert(str::Eq(joined, _T("a;b;;c;"))); } { StrVec v2; size_t count = v2.Split(_T("a,b,,c,"), _T(","), true); assert(count == 3 && v2.Find(_T("c")) == 2); ScopedMem<TCHAR> joined(v2.Join(_T(";"))); assert(str::Eq(joined, _T("a;b;c"))); ScopedMem<TCHAR> last(v2.Pop()); assert(v2.Count() == 2 && str::Eq(last, _T("c"))); } }
static void BenchDir(TCHAR *dir) { StrVec files; ScopedMem<TCHAR> pattern(str::Format(_T("%s\\*.pdf"), dir)); CollectPathsFromDirectory(pattern, files, false); for (size_t i = 0; i < files.Count(); i++) { BenchFile(files.At(i), NULL); } }
int ImageDirEngineImpl::GetPageByLabel(const TCHAR *label) { for (size_t i = 0; i < pageFileNames.Count(); i++) { const TCHAR *fileName = path::GetBaseName(pageFileNames.At(i)); const TCHAR *fileExt = path::GetExt(fileName); if (str::StartsWithI(fileName, label) && (fileName + str::Len(label) == fileExt || fileName[str::Len(label)] == '\0')) return (int)i + 1; } return BaseEngine::GetPageByLabel(label); }
// Find a record corresponding to the given source file, line number and optionally column number. // (at the moment the column parameter is ignored) // // If there are several *consecutively declared* records for the same line then they are all returned. // The list of records is added to the vector 'records' // // If there is no record for that line, the record corresponding to the nearest line is selected // (within a range of EPSILON_LINE) // // The function returns PDFSYNCERR_SUCCESS if a matching record was found. UINT Pdfsync::SourceToRecord(const TCHAR* srcfilename, UINT line, UINT col, Vec<size_t> &records) { if (!srcfilename) return PDFSYNCERR_INVALID_ARGUMENT; ScopedMem<TCHAR> srcfilepath; // convert the source file to an absolute path if (PathIsRelative(srcfilename)) srcfilepath.Set(PrependDir(srcfilename)); else srcfilepath.Set(str::Dup(srcfilename)); if (!srcfilepath) return PDFSYNCERR_OUTOFMEMORY; // find the source file entry size_t isrc; for (isrc = 0; isrc < srcfiles.Count(); isrc++) if (path::IsSame(srcfilepath, srcfiles.At(isrc))) break; if (isrc == srcfiles.Count()) return PDFSYNCERR_UNKNOWN_SOURCEFILE; if (fileIndex.At(isrc).start == fileIndex.At(isrc).end) return PDFSYNCERR_NORECORD_IN_SOURCEFILE; // there is not any record declaration for that particular source file // look for sections belonging to the specified file // starting with the first section that is declared within the scope of the file. UINT min_distance = EPSILON_LINE; // distance to the closest record size_t lineIx = (size_t)-1; // closest record-line index for (size_t isec = fileIndex.At(isrc).start; isec < fileIndex.At(isrc).end; isec++) { // does this section belong to the desired file? if (lines.At(isec).file != isrc) continue; UINT d = abs((int)lines.At(isec).line - (int)line); if (d < min_distance) { min_distance = d; lineIx = isec; if (0 == d) break; // We have found a record for the requested line! } } if (lineIx == (size_t)-1) return PDFSYNCERR_NORECORD_FOR_THATLINE; // we read all the consecutive records until we reach a record belonging to another line for (size_t i = lineIx; i < lines.Count() && lines.At(i).line == lines.At(lineIx).line; i++) records.Push(lines.At(i).record); return PDFSYNCERR_SUCCESS; }
Bitmap *ImageDirEngineImpl::LoadImage(int pageNo) { assert(1 <= pageNo && pageNo <= PageCount()); if (pages.At(pageNo - 1)) return pages.At(pageNo - 1); size_t len; ScopedMem<char> bmpData(file::ReadAll(pageFileNames.At(pageNo - 1), &len)); if (bmpData) pages.At(pageNo - 1) = BitmapFromData(bmpData, len); return pages.At(pageNo - 1); }
bool GetExePath(LPTSTR lpPath, int len) { // Search the plugin's directory first GetModuleFileName(g_hInstance, lpPath, len - 2); str::BufSet((TCHAR *)path::GetBaseName(lpPath), len - 2 - (path::GetBaseName(lpPath) - lpPath), _T("SumatraPDF.exe")); if (file::Exists(lpPath)) return true; *lpPath = '\0'; // Try to get the path from the registry (set e.g. when making the default PDF viewer) ScopedMem<TCHAR> path(ReadRegStr(HKEY_CURRENT_USER, _T("Software\\Classes\\SumatraPDF\\Shell\\Open\\Command"), NULL)); if (!path) return false; StrVec args; ParseCmdLine(path, args); if (!file::Exists(args.At(0))) return false; str::BufSet(lpPath, len, args.At(0)); return true; }
// parses a list of page ranges such as 1,3-5,7- (i..e all but pages 2 and 6) // into an interable list (returns NULL on parsing errors) // caller must delete the result static bool ParsePageRanges(const TCHAR *ranges, Vec<PageRange>& result) { if (!ranges) return false; StrVec rangeList; rangeList.Split(ranges, _T(","), true); rangeList.SortNatural(); for (size_t i = 0; i < rangeList.Count(); i++) { int start, end; if (str::Parse(rangeList.At(i), _T("%d-%d%$"), &start, &end) && 0 < start && start <= end) result.Append(PageRange(start, end)); else if (str::Parse(rangeList.At(i), _T("%d-%$"), &start) && 0 < start) result.Append(PageRange(start, INT_MAX)); else if (str::Parse(rangeList.At(i), _T("%d%$"), &start) && 0 < start) result.Append(PageRange(start, start)); else return false; } return result.Count() > 0; }
RectD ImageDirEngineImpl::PageMediabox(int pageNo) { assert(1 <= pageNo && pageNo <= PageCount()); if (!mediaboxes.At(pageNo - 1).IsEmpty()) return mediaboxes.At(pageNo - 1); size_t len; ScopedMem<char> bmpData(file::ReadAll(pageFileNames.At(pageNo - 1), &len)); if (bmpData) { Size size = BitmapSizeFromData(bmpData, len); mediaboxes.At(pageNo - 1) = RectD(0, 0, size.Width, size.Height); } return mediaboxes.At(pageNo - 1); }
static bool SetupPluginMode(CommandLineInfo& i) { if (!IsWindow(i.hwndPluginParent) || i.fileNames.Count() == 0) return false; gPluginURL = i.pluginURL; if (!gPluginURL) gPluginURL = i.fileNames.At(0); assert(i.fileNames.Count() == 1); while (i.fileNames.Count() > 1) { free(i.fileNames.Pop()); } i.reuseInstance = i.exitOnPrint = false; // always display the toolbar when embedded (as there's no menubar in that case) gGlobalPrefs.toolbarVisible = true; // never allow esc as a shortcut to quit gGlobalPrefs.escToExit = false; // never show the sidebar by default gGlobalPrefs.tocVisible = false; if (DM_AUTOMATIC == gGlobalPrefs.defaultDisplayMode) { // if the user hasn't changed the default display mode, // display documents as single page/continuous/fit width // (similar to Adobe Reader, Google Chrome and how browsers display HTML) gGlobalPrefs.defaultDisplayMode = DM_CONTINUOUS; gGlobalPrefs.defaultZoom = ZOOM_FIT_WIDTH; } // extract some command line arguments from the URL's hash fragment where available // see http://www.adobe.com/devnet/acrobat/pdfs/pdf_open_parameters.pdf#nameddest=G4.1501531 if (i.pluginURL && str::FindChar(i.pluginURL, '#')) { ScopedMem<TCHAR> args(str::Dup(str::FindChar(i.pluginURL, '#') + 1)); str::TransChars(args, _T("#"), _T("&")); StrVec parts; parts.Split(args, _T("&"), true); for (size_t k = 0; k < parts.Count(); k++) { TCHAR *part = parts.At(k); int pageNo; if (str::StartsWithI(part, _T("page=")) && str::Parse(part + 4, _T("=%d%$"), &pageNo)) i.pageNumber = pageNo; else if (str::StartsWithI(part, _T("nameddest=")) && part[10]) str::ReplacePtr(&i.destName, part + 10); else if (!str::FindChar(part, '=') && part[0]) str::ReplacePtr(&i.destName, part); } } return true; }
/* parse argument list. we assume that all unrecognized arguments are file names. */ void CommandLineInfo::ParseCommandLine(TCHAR *cmdLine) { StrVec argList; ParseCmdLine(cmdLine, argList); size_t argCount = argList.Count(); #define is_arg(txt) str::EqI(_T(txt), argument) #define is_arg_with_param(txt) (is_arg(txt) && param != NULL) #define additional_param() argList.At(n + 1) #define has_additional_param() ((argCount > n + 1) && ('-' != additional_param()[0])) for (size_t n = 1; n < argCount; n++) { TCHAR *argument = argList.At(n); TCHAR *param = NULL; if (argCount > n + 1) param = argList.At(n + 1); if (is_arg("-register-for-pdf")) { makeDefault = true; exitImmediately = true; return; } else if (is_arg("-silent")) { // silences errors happening during -print-to and -print-to-default silent = true; } else if (is_arg("-print-to-default")) { TCHAR *name = GetDefaultPrinterName(); if (name) { str::ReplacePtr(&printerName, name); free(name); } } else if (is_arg_with_param("-print-to")) { str::ReplacePtr(&printerName, argList.At(++n)); } else if (is_arg("-print-dialog")) { printDialog = true; } else if (is_arg_with_param("-print-settings")) { // argument is a comma separated list of page ranges and // advanced options [even|odd] and [noscale|shrink|fit] // e.g. -print-settings "1-3,5,10-8,odd,fit" str::ReplacePtr(&printSettings, argList.At(++n)); str::RemoveChars(printSettings, _T(" ")); } else if (is_arg("-exit-on-print")) { // only affects -print-dialog (-print-to and -print-to-default // always exit on print) exitOnPrint = true; } else if (is_arg_with_param("-bgcolor") || is_arg_with_param("-bg-color")) { // -bgcolor is for backwards compat (was used pre-1.3) // -bg-color is for consistency ParseColor(&bgColor, argList.At(++n)); } else if (is_arg_with_param("-inverse-search")) { str::ReplacePtr(&inverseSearchCmdLine, argList.At(++n)); } else if ((is_arg_with_param("-forward-search") || is_arg_with_param("-fwdsearch")) && argCount > n + 2) { // -forward-search is for consistency with -inverse-search // -fwdsearch is for consistency with -fwdsearch-* str::ReplacePtr(&forwardSearchOrigin, argList.At(++n)); forwardSearchLine = _ttoi(argList.At(++n)); } else if (is_arg_with_param("-fwdsearch-offset")) { fwdSearch.offset = _ttoi(argList.At(++n)); } else if (is_arg_with_param("-fwdsearch-width")) { fwdSearch.width = _ttoi(argList.At(++n)); } else if (is_arg_with_param("-fwdsearch-color")) { ParseColor(&fwdSearch.color, argList.At(++n)); } else if (is_arg_with_param("-fwdsearch-permanent")) { fwdSearch.permanent = _ttoi(argList.At(++n)); } else if (is_arg("-esc-to-exit")) { escToExit = true; } else if (is_arg("-reuse-instance")) { // find the window handle of a running instance of SumatraPDF // TODO: there should be a mutex here to reduce possibility of // race condition and having more than one copy launch because // FindWindow() in one process is called before a window is created // in another process reuseInstance = (FindWindow(FRAME_CLASS_NAME, 0) != NULL); } else if (is_arg_with_param("-lang")) { free(lang); lang = str::conv::ToAnsi(argList.At(++n)); } else if (is_arg_with_param("-nameddest") || is_arg_with_param("-named-dest")) { // -nameddest is for backwards compat (was used pre-1.3) // -named-dest is for consistency str::ReplacePtr(&destName, argList.At(++n)); } else if (is_arg_with_param("-page")) { pageNumber = _ttoi(argList.At(++n)); } else if (is_arg("-restrict")) { restrictedUse = true; } // TODO: remove -invert-colors and -set-color-range in favor // of the UI settable gGlobalPrefs.useSysColors(?) else if (is_arg("-invertcolors") || is_arg("-invert-colors")) { // -invertcolors is for backwards compat (was used pre-1.3) // -invert-colors is for consistency // -invert-colors is a shortcut for -set-color-range 0xFFFFFF 0x000000 // (i.e. it sets white as foreground color and black as background color) colorRange[0] = WIN_COL_WHITE; colorRange[1] = WIN_COL_BLACK; } else if (is_arg("-set-color-range") && argCount > n + 2) { STATIC_ASSERT(sizeof(colorRange[0]) == sizeof(int), colorref_as_int); ParseColor((int *)&colorRange[0], argList.At(++n)); ParseColor((int *)&colorRange[1], argList.At(++n)); } else if (is_arg("-presentation")) { enterPresentation = true; } else if (is_arg("-fullscreen")) { enterFullscreen = true; } else if (is_arg_with_param("-view")) { ParseViewMode(&startView, argList.At(++n)); } else if (is_arg_with_param("-zoom")) { ParseZoomValue(&startZoom, argList.At(++n)); } else if (is_arg_with_param("-scroll")) { ParseScrollValue(&startScroll, argList.At(++n)); } else if (is_arg("-console")) { showConsole = true; } else if (is_arg_with_param("-plugin")) { // -plugin [<URL>] <parent HWND> if (!str::IsDigit(*param) && has_additional_param()) str::ReplacePtr(&pluginURL, argList.At(++n)); // the argument is a (numeric) window handle to // become the parent of a frameless SumatraPDF // (used e.g. for embedding it into a browser plugin) hwndPluginParent = (HWND)_ttol(argList.At(++n)); } else if (is_arg_with_param("-stress-test")) { // -stress-test <file or dir path> [<file filter>] [<page/file range(s)>] [<cycle count>x] // e.g. -stress-test file.pdf 25x for rendering file.pdf 25 times // -stress-test file.pdf 1-3 render only pages 1, 2 and 3 of file.pdf // -stress-test dir 301- 2x render all files in dir twice, skipping first 300 // -stress-test dir *.pdf;*.xps render all files in dir that are either PDF or XPS str::ReplacePtr(&stressTestPath, argList.At(++n)); int num; if (has_additional_param() && str::FindChar(additional_param(), '*')) { str::ReplacePtr(&stressTestFilter, additional_param()); n++; } if (has_additional_param() && IsValidPageRange(additional_param())) { str::ReplacePtr(&stressTestRanges, additional_param()); n++; } if (has_additional_param() && str::Parse(additional_param(), _T("%dx%$"), &num) && num > 0) { stressTestCycles = num; n++; } } else if (is_arg_with_param("-bench")) { TCHAR *s = str::Dup(argList.At(++n)); pathsToBenchmark.Push(s); s = NULL; if (has_additional_param() && IsBenchPagesInfo(additional_param())) { s = str::Dup(additional_param()); n++; } pathsToBenchmark.Push(s); exitImmediately = true; } else if (is_arg("-crash-on-open")) { // to make testing of crash reporting system in pre-release/release // builds possible crashOnOpen = true; } else if (is_arg_with_param("-manga-mode")) { // TODO: we should have a ui for this instead of remembering it globally // in prefs TCHAR *s = argList.At(++n); cbxR2L = str::EqI(_T("true"), s) || str::Eq(_T("1"), s); } #ifdef DEBUG else if (is_arg("-enum-printers")) { EnumeratePrinters(); /* this is for testing only, exit immediately */ exitImmediately = true; return; } #endif else { // Remember this argument as a filename to open TCHAR *filepath = NULL; if (str::EndsWithI(argList.At(n), _T(".lnk"))) filepath = ResolveLnk(argList.At(n)); if (!filepath) filepath = str::Dup(argList.At(n)); fileNames.Push(filepath); } } #undef is_arg #undef is_arg_with_param #undef additional_param #undef has_additional_param }