void CmdLineParserTest() {
    WStrVec args;

    ParseCmdLine(L"test.exe -arg foo.pdf", args);
    utassert(3 == args.size());
    utassert(str::Eq(args.at(0), L"test.exe"));
    utassert(str::Eq(args.at(1), L"-arg"));
    utassert(str::Eq(args.at(2), L"foo.pdf"));
    args.Reset();

    ParseCmdLine(L"test.exe \"foo \\\" bar \\\\.pdf\" un\\\"quoted.pdf", args);
    utassert(3 == args.size());
    utassert(str::Eq(args.at(0), L"test.exe"));
    utassert(str::Eq(args.at(1), L"foo \" bar \\\\.pdf"));
    utassert(str::Eq(args.at(2), L"un\"quoted.pdf"));
    args.Reset();

    ParseCmdLine(L"test.exe \"foo\".pdf foo\" bar.pdf ", args);
    utassert(3 == args.size());
    utassert(str::Eq(args.at(0), L"test.exe"));
    utassert(str::Eq(args.at(1), L"foo.pdf"));
    utassert(str::Eq(args.at(2), L"foo bar.pdf "));
    args.Reset();

    ParseCmdLine(L"test.exe -arg \"%1\" -more", args, 2);
    utassert(2 == args.size());
    utassert(str::Eq(args.at(0), L"test.exe"));
    utassert(str::Eq(args.at(1), L"-arg \"%1\" -more"));
    args.Reset();
}
Beispiel #2
0
static void SetCloseProcessMsg() {
    AutoFreeW procNames(str::Dup(ReadableProcName(gProcessesToClose.at(0))));
    for (size_t i = 1; i < gProcessesToClose.size(); i++) {
        const WCHAR* name = ReadableProcName(gProcessesToClose.at(i));
        if (i < gProcessesToClose.size() - 1)
            procNames.Set(str::Join(procNames, L", ", name));
        else
            procNames.Set(str::Join(procNames, L" and ", name));
    }
    AutoFreeW s(str::Format(_TR("Please close %s to proceed!"), procNames));
    SetMsg(s, COLOR_MSG_FAILED);
}
Beispiel #3
0
// 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 WCHAR* srcfilename, UINT line, UINT col, Vec<size_t>& records) {
    UNUSED(col);
    if (!srcfilename)
        return PDFSYNCERR_INVALID_ARGUMENT;

    AutoFreeW srcfilepath;
    // convert the source file to an absolute path
    if (PathIsRelative(srcfilename))
        srcfilepath.Set(PrependDir(srcfilename));
    else
        srcfilepath.SetCopy(srcfilename);
    if (!srcfilepath)
        return PDFSYNCERR_OUTOFMEMORY;

    // find the source file entry
    size_t isrc;
    for (isrc = 0; isrc < srcfiles.size(); isrc++)
        if (path::IsSame(srcfilepath, srcfiles.at(isrc)))
            break;
    if (isrc == srcfiles.size())
        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.size() && lines.at(i).line == lines.at(lineIx).line; i++)
        records.Push(lines.at(i).record);

    return PDFSYNCERR_SUCCESS;
}
// 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.size(); 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.size() - 1;
        }
        filesPerType.at(typeNo)->Append(str::Dup(file));
    }

    for (size_t j = 0; j < filesPerType.size(); j++) {
        WStrVec* all = filesPerType.at(j);
        WStrVec* random = new WStrVec();

        for (int n = 0; n < maxPerType && all->size() > 0; n++) {
            int idx = rand() % all->size();
            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.size(); j++) {
            WStrVec* random = filesPerType.at(j);
            if (random->size() > 0) {
                gotAll = false;
                WCHAR* file = random->at(0);
                files.Append(file);
                random->RemoveAtFast(0);
            }
        }
    }

    for (size_t j = 0; j < filesPerType.size(); j++) {
        delete filesPerType.at(j);
    }
}
WCHAR* DirFileProvider::NextFile() {
    if (filesToOpen.size() > 0) {
        return filesToOpen.PopAt(0);
    }

    if (dirsToVisit.size() > 0) {
        // test next directory
        AutoFreeW path(dirsToVisit.PopAt(0));
        OpenDir(path);
        return NextFile();
    }

    return nullptr;
}
static void BenchDir(WCHAR* dir) {
    WStrVec files;
    CollectFilesToBench(dir, files);
    for (size_t i = 0; i < files.size(); i++) {
        BenchFile(files.at(i), nullptr);
    }
}
 FilesProvider(WStrVec& newFiles, int n, int offset) {
     // get every n-th file starting at offset
     for (size_t i = offset; i < newFiles.size(); i += n) {
         const WCHAR* f = newFiles.at(i);
         files.Append(str::Dup(f));
     }
     provided = 0;
 }
static size_t GetAllMatchingFiles(const WCHAR* dir, const WCHAR* filter, WStrVec& files, bool showProgress) {
    WStrVec dirsToVisit;
    dirsToVisit.Append(str::Dup(dir));

    while (dirsToVisit.size() > 0) {
        if (showProgress) {
            wprintf(L".");
            fflush(stdout);
        }

        AutoFreeW path(dirsToVisit.PopAt(0));
        CollectStressTestSupportedFilesFromDirectory(path, filter, files);
        AutoFreeW pattern(str::Format(L"%s\\*", path));
        CollectPathsFromDirectory(pattern, dirsToVisit, true);
    }
    return files.size();
}
Beispiel #9
0
/* 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->tag != Tag_Object || level > 1 && (!el->up || el->up->tag != Tag_Li));

    WStrVec references;
    AutoFreeW keyword, name;
    for (el = el->GetChildByTag(Tag_Param); el; el = el->next) {
        if (Tag_Param != el->tag)
            continue;
        AutoFreeW attrName(el->GetAttribute("name"));
        AutoFreeW attrVal(el->GetAttribute("value"));
        if (attrName && attrVal && cp != CP_CHM_DEFAULT) {
            OwnedData bytes(str::conv::ToCodePage(attrVal, CP_CHM_DEFAULT));
            attrVal.Set(str::conv::FromCodePage(bytes.Get(), cp));
        }
        if (!attrName || !attrVal)
            /* ignore incomplete/unneeded <param> */;
        else if (str::EqI(attrName, L"Keyword"))
            keyword.Set(attrVal.StealData());
        else if (str::EqI(attrName, L"Name")) {
            name.Set(attrVal.StealData());
            // some CHM documents seem to use a lonely Name instead of Keyword
            if (!keyword)
                keyword.SetCopy(name);
        } else if (str::EqI(attrName, L"Local") && name) {
            // remove the ITS protocol and any filename references from the URLs
            if (str::Find(attrVal, L"::/"))
                attrVal.SetCopy(str::Find(attrVal, L"::/") + 3);
            references.Append(name.StealData());
            references.Append(attrVal.StealData());
        }
    }
    if (!keyword)
        return false;

    if (references.size() == 2) {
        visitor->Visit(keyword, references.at(1), level);
        return true;
    }
    visitor->Visit(keyword, nullptr, level);
    for (size_t i = 0; i < references.size(); i += 2) {
        visitor->Visit(references.at(i), references.at(i + 1), level + 1);
    }
    return true;
}
Beispiel #10
0
static void ParseCommandLine(WCHAR* cmdLine) {
    WStrVec argList;
    ParseCmdLine(cmdLine, argList);

#define is_arg(param) str::EqI(arg + 1, TEXT(param))
#define is_arg_with_param(param) (is_arg(param) && i < argList.size() - 1)

    // skip the first arg (exe path)
    for (size_t i = 1; i < argList.size(); i++) {
        WCHAR* arg = argList.at(i);
        if ('-' != *arg && '/' != *arg)
            continue;

        if (is_arg("s"))
            gGlobalData.silent = true;
        else if (is_arg_with_param("d"))
            str::ReplacePtr(&gGlobalData.installDir, argList.at(++i));
#ifndef BUILD_UNINSTALLER
        else if (is_arg("register"))
            gGlobalData.registerAsDefault = true;
        else if (is_arg_with_param("opt")) {
            WCHAR* opts = argList.at(++i);
            str::ToLowerInPlace(opts);
            str::TransChars(opts, L" ;", L",,");
            WStrVec optlist;
            optlist.Split(opts, L",", true);
            if (optlist.Contains(L"pdffilter"))
                gGlobalData.installPdfFilter = true;
            if (optlist.Contains(L"pdfpreviewer"))
                gGlobalData.installPdfPreviewer = true;
            // uninstall the deprecated browser plugin if it's not
            // explicitly listed (only applies if the /opt flag is used)
            if (!optlist.Contains(L"plugin"))
                gGlobalData.keepBrowserPlugin = false;
        } else if (is_arg("x")) {
            gGlobalData.justExtractFiles = true;
            // silently extract files to the current directory (if /d isn't used)
            gGlobalData.silent = true;
            if (!gGlobalData.installDir)
                str::ReplacePtr(&gGlobalData.installDir, L".");
        } else if (is_arg("autoupdate")) {
            gGlobalData.autoUpdate = true;
        }
#endif
        else if (is_arg("h") || is_arg("help") || is_arg("?"))
            gGlobalData.showUsageAndQuit = true;
#ifdef ENABLE_CRASH_TESTING
        else if (is_arg("crash")) {
            // will induce crash when 'Install' button is pressed
            // for testing crash handling
            gForceCrash = true;
        }
#endif
    }
}
Beispiel #11
0
bool DirFileProvider::OpenDir(const WCHAR* dirPath) {
    AssertCrash(filesToOpen.size() == 0);

    bool hasFiles = CollectStressTestSupportedFilesFromDirectory(dirPath, fileFilter, filesToOpen);
    filesToOpen.SortNatural();

    AutoFreeW pattern(str::Format(L"%s\\*", dirPath));
    bool hasSubDirs = CollectPathsFromDirectory(pattern, dirsToVisit, true);

    return hasFiles || hasSubDirs;
}
// removes thumbnails that don't belong to any frequently used item in file history
void CleanUpThumbnailCache(const FileHistory& fileHistory) {
    AutoFreeW thumbsPath(AppGenDataFilename(THUMBNAILS_DIR_NAME));
    if (!thumbsPath)
        return;
    AutoFreeW pattern(path::Join(thumbsPath, L"*.png"));

    WStrVec files;
    WIN32_FIND_DATA fdata;

    HANDLE hfind = FindFirstFile(pattern, &fdata);
    if (INVALID_HANDLE_VALUE == hfind)
        return;
    do {
        if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
            files.Append(str::Dup(fdata.cFileName));
    } while (FindNextFile(hfind, &fdata));
    FindClose(hfind);

    Vec<DisplayState*> list;
    fileHistory.GetFrequencyOrder(list);
    for (size_t i = 0; i < list.size() && i < FILE_HISTORY_MAX_FREQUENT * 2; i++) {
        AutoFreeW bmpPath(GetThumbnailPath(list.at(i)->filePath));
        if (!bmpPath)
            continue;
        int idx = files.Find(path::GetBaseName(bmpPath));
        if (idx != -1) {
            CrashIf(idx < 0 || files.size() <= (size_t)idx);
            free(files.PopAt(idx));
        }
    }

    for (size_t i = 0; i < files.size(); i++) {
        AutoFreeW bmpPath(path::Join(thumbsPath, files.at(i)));
        file::Delete(bmpPath);
    }
}
Beispiel #13
0
bool CheckInstallUninstallPossible(bool silent) {
    gProcessesToClose.Reset();
    ProcessesUsingInstallation(gProcessesToClose);

    bool possible = gProcessesToClose.size() == 0;
    if (possible) {
        SetDefaultMsg();
    } else {
        SetCloseProcessMsg();
        if (!silent)
            MessageBeep(MB_ICONEXCLAMATION);
    }
    InvalidateFrame();

    return possible;
}
Beispiel #14
0
void BenchFileOrDir(WStrVec& pathsToBench) {
    gLog = new slog::StderrLogger();

    size_t n = pathsToBench.size() / 2;
    for (size_t i = 0; i < n; i++) {
        WCHAR* 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(L"Error: file or dir %s doesn't exist", path);
    }

    delete gLog;
}
// 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 nullptr on parsing errors)
// caller must delete the result
bool ParsePageRanges(const WCHAR* ranges, Vec<PageRange>& result) {
    if (!ranges)
        return false;

    WStrVec rangeList;
    rangeList.Split(ranges, L",", true);
    rangeList.SortNatural();

    for (size_t i = 0; i < rangeList.size(); i++) {
        int start, end;
        if (str::Parse(rangeList.at(i), L"%d-%d%$", &start, &end) && 0 < start && start <= end)
            result.Append(PageRange(start, end));
        else if (str::Parse(rangeList.at(i), L"%d-%$", &start) && 0 < start)
            result.Append(PageRange(start, INT_MAX));
        else if (str::Parse(rangeList.at(i), L"%d%$", &start) && 0 < start)
            result.Append(PageRange(start, start));
        else
            return false;
    }

    return result.size() > 0;
}
/* parse argument list. we assume that all unrecognized arguments are file names. */
void CommandLineInfo::ParseCommandLine(const WCHAR* cmdLine) {
    WStrVec argList;
    ParseCmdLine(cmdLine, argList);
    size_t argCount = argList.size();

#define is_arg_with_param(_argNo) (param && _argNo == arg)
#define additional_param() argList.at(n + 1)
#define has_additional_param() ((argCount > n + 1) && ('-' != additional_param()[0]))
#define handle_string_param(name) name.SetCopy(argList.at(++n))
#define handle_int_param(name) name = _wtoi(argList.at(++n))

    for (size_t n = 1; n < argCount; n++) {
        WCHAR* argName = argList.at(n);
        int arg = GetArgNo(argName);
        WCHAR* param = nullptr;
        if (argCount > n + 1) {
            param = argList.at(n + 1);
        }
        if (RegisterForPdf == arg) {
            makeDefault = true;
            exitImmediately = true;
            return;
        } else if (Silent == arg) {
            // silences errors happening during -print-to and -print-to-default
            silent = true;
        } else if (PrintToDefault == arg) {
            printerName.Set(GetDefaultPrinterName());
            if (!printerName)
                printDialog = true;
            exitWhenDone = true;
        } else if (is_arg_with_param(PrintTo)) {
            handle_string_param(printerName);
            exitWhenDone = true;
        } else if (PrintDialog == arg) {
            printDialog = true;
        } else if (is_arg_with_param(PrintSettings)) {
            // argument is a comma separated list of page ranges and
            // advanced options [even|odd], [noscale|shrink|fit] and [autorotation|portrait|landscape]
            // e.g. -print-settings "1-3,5,10-8,odd,fit"
            handle_string_param(printSettings);
            str::RemoveChars(printSettings, L" ");
            str::TransChars(printSettings, L";", L",");
        } else if (ExitWhenDone == arg || ExitOnPrint == arg) {
            // only affects -print-dialog (-print-to and -print-to-default
            // always exit on print) and -stress-test (useful for profiling)
            exitWhenDone = true;
        } else if (is_arg_with_param(InverseSearch)) {
            inverseSearchCmdLine.SetCopy(argList.at(++n));
        } else if ((is_arg_with_param(ForwardSearch) || is_arg_with_param(FwdSearch)) && argCount > n + 2) {
            // -forward-search is for consistency with -inverse-search
            // -fwdsearch is for consistency with -fwdsearch-*
            handle_string_param(forwardSearchOrigin);
            handle_int_param(forwardSearchLine);
        } else if (is_arg_with_param(NamedDest) || is_arg_with_param(NamedDest2)) {
            // -nameddest is for backwards compat (was used pre-1.3)
            // -named-dest is for consistency
            handle_string_param(destName);
        } else if (is_arg_with_param(Page)) {
            handle_int_param(pageNumber);
        } else if (Restrict == arg) {
            restrictedUse = true;
        } else if (InvertColors1 == arg || InvertColors2 == arg) {
            // -invertcolors is for backwards compat (was used pre-1.3)
            // -invert-colors is for consistency
            // -invert-colors used to be a shortcut for -set-color-range 0xFFFFFF 0x000000
            // now it non-permanently swaps textColor and backgroundColor
            invertColors = true;
        } else if (Presentation == arg) {
            enterPresentation = true;
        } else if (Fullscreen == arg) {
            enterFullScreen = true;
        } else if (is_arg_with_param(View)) {
            ParseViewMode(&startView, param);
            ++n;
        } else if (is_arg_with_param(Zoom)) {
            ParseZoomValue(&startZoom, param);
            ++n;
        } else if (is_arg_with_param(Scroll)) {
            ParseScrollValue(&startScroll, param);
            ++n;
        } else if (Console == arg) {
            showConsole = true;
        } else if (is_arg_with_param(AppData)) {
            appdataDir.SetCopy(param);
            ++n;
        } else if (is_arg_with_param(Plugin)) {
            // -plugin [<URL>] <parent HWND>
            if (argCount > n + 2 && !str::IsDigit(*argList.at(n + 1)) && *argList.at(n + 2) != '-')
                handle_string_param(pluginURL);
            // 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)(INT_PTR)_wtol(argList.at(++n));
        } else if (is_arg_with_param(StressTest)) {
            // -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
            handle_string_param(stressTestPath);
            int num;
            if (has_additional_param() && str::FindChar(additional_param(), '*'))
                handle_string_param(stressTestFilter);
            if (has_additional_param() && IsValidPageRange(additional_param()))
                handle_string_param(stressTestRanges);
            if (has_additional_param() && str::Parse(additional_param(), L"%dx%$", &num) && num > 0) {
                stressTestCycles = num;
                n++;
            }
        } else if (is_arg_with_param(ArgN)) {
            handle_int_param(stressParallelCount);
        } else if (is_arg_with_param(Render)) {
            handle_int_param(pageNumber);
            testRenderPage = true;
        } else if (is_arg_with_param(ExtractText)) {
            handle_int_param(pageNumber);
            testExtractPage = true;
        } else if (Rand == arg) {
            stressRandomizeFiles = true;
        } else if (is_arg_with_param(Bench)) {
            WCHAR* s = str::Dup(param);
            ++n;
            pathsToBenchmark.Push(s);
            s = nullptr;
            if (has_additional_param() && IsBenchPagesInfo(additional_param())) {
                s = str::Dup(argList.at(++n));
            }
            pathsToBenchmark.Push(s);
            exitImmediately = true;
        } else if (CrashOnOpen == arg) {
            // to make testing of crash reporting system in pre-release/release
            // builds possible
            crashOnOpen = true;
        } else if (ReuseInstance == arg) {
            // for backwards compatibility, -reuse-instance reuses whatever
            // instance has registered as DDE server
            reuseDdeInstance = true;
        }
        // TODO: remove the following deprecated options within a release or two
        else if (is_arg_with_param(Lang)) {
            auto tmp = str::conv::ToAnsi(param);
            lang.Set(tmp.StealData());
            ++n;
        } else if (EscToExit == arg) {
            globalPrefArgs.Append(str::Dup(argList.at(n)));
        } else if (is_arg_with_param(BgColor) || is_arg_with_param(BgColor2) || is_arg_with_param(FwdSearchOffset) ||
                   is_arg_with_param(FwdSearchWidth) || is_arg_with_param(FwdSearchColor) ||
                   is_arg_with_param(FwdSearchPermanent) || is_arg_with_param(MangaMode)) {
            globalPrefArgs.Append(str::Dup(argList.at(n)));
            globalPrefArgs.Append(str::Dup(argList.at(++n)));
        } else if (SetColorRange == arg && argCount > n + 2) {
            globalPrefArgs.Append(str::Dup(argList.at(n)));
            globalPrefArgs.Append(str::Dup(argList.at(++n)));
            globalPrefArgs.Append(str::Dup(argList.at(++n)));
        }
#ifdef DEBUG
        else if (ArgEnumPrinters == arg) {
            EnumeratePrinters();
            /* this is for testing only, exit immediately */
            exitImmediately = true;
            return;
        }
#endif
        // this should have been handled already by AutoUpdateMain
        else if (is_arg_with_param(AutoUpdate)) {
            n++;
        } else {
            // Remember this argument as a filename to open
            WCHAR* filePath = nullptr;
            if (str::EndsWithI(argName, L".lnk"))
                filePath = ResolveLnk(argName);
            if (!filePath)
                filePath = str::Dup(argName);
            fileNames.Push(filePath);
        }
    }
#undef is_arg_with_param
#undef additional_param
#undef has_additional_param
#undef handle_string_param
#undef handle_int_param
}
Beispiel #17
0
 virtual WCHAR* NextFile() {
     if (provided >= files.size())
         return nullptr;
     return str::Dup(files.at(provided++));
 }
Beispiel #18
0
 int Count() { return (int)text.size(); }
Beispiel #19
0
void StartStressTest(CommandLineInfo* i, WindowInfo* win) {
    gIsStressTesting = true;
    // TODO: for now stress testing only supports the non-ebook ui
    gGlobalPrefs->ebookUI.useFixedPageUI = true;
    gGlobalPrefs->chmUI.useFixedPageUI = true;
    // TODO: make stress test work with tabs?
    gGlobalPrefs->useTabs = false;
    // forbid entering sleep mode during tests
    SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
    srand((unsigned int)time(nullptr));
    // redirect stderr to NUL to disable (MuPDF) logging
    FILE* nul;
    freopen_s(&nul, "NUL", "w", stderr);

    int n = i->stressParallelCount;
    if (n > 1 || i->stressRandomizeFiles) {
        WindowInfo** windows = AllocArray<WindowInfo*>(n);
        windows[0] = win;
        for (int j = 1; j < n; j++) {
            windows[j] = CreateAndShowWindowInfo();
            if (!windows[j])
                return;
        }
        WStrVec filesToTest;

        wprintf(L"Scanning for files in directory %s\n", i->stressTestPath.Get());
        fflush(stdout);
        size_t filesCount = GetAllMatchingFiles(i->stressTestPath, i->stressTestFilter, filesToTest, true);
        if (0 == filesCount) {
            wprintf(L"Didn't find any files matching filter '%s'\n", i->stressTestFilter.Get());
            return;
        }
        wprintf(L"Found %d files", (int)filesCount);
        fflush(stdout);
        if (i->stressRandomizeFiles) {
            // TODO: should probably allow over-writing the 100 limit
            RandomizeFiles(filesToTest, 100);
            filesCount = filesToTest.size();
            wprintf(L"\nAfter randomization: %d files", (int)filesCount);
        }
        wprintf(L"\n");
        fflush(stdout);

        for (int j = 0; j < n; j++) {
            // dst will be deleted when the stress ends
            win = windows[j];
            StressTest* dst = new StressTest(win, i->exitWhenDone);
            win->stressTest = dst;
            // divide filesToTest among each window
            FilesProvider* filesProvider = new FilesProvider(filesToTest, n, j);
            dst->Start(filesProvider, i->stressTestCycles);
        }

        free(windows);
    } else {
        // dst will be deleted when the stress ends
        StressTest* dst = new StressTest(win, i->exitWhenDone);
        win->stressTest = dst;
        dst->Start(i->stressTestPath, i->stressTestFilter, i->stressTestRanges, i->stressTestCycles);
    }
}
Beispiel #20
0
// see http://itexmac.sourceforge.net/pdfsync.html for the specification
int Pdfsync::RebuildIndex() {
    OwnedData data(file::ReadFile(syncfilepath));
    if (!data.data) {
        return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;
    }
    // convert the file data into a list of zero-terminated strings
    str::TransChars(data.data, "\r\n", "\0\0");

    // parse preamble (jobname and version marker)
    char* line = data.data;
    char* dataEnd = data.data + data.size;

    // replace star by spaces (TeX uses stars instead of spaces in filenames)
    str::TransChars(line, "*/", " \\");
    AutoFreeW jobName(str::conv::FromAnsi(line));
    jobName.Set(str::Join(jobName, L".tex"));
    jobName.Set(PrependDir(jobName));

    line = Advance0Line(line, dataEnd);
    UINT versionNumber = 0;
    if (!line || !str::Parse(line, "version %u", &versionNumber) || versionNumber != 1) {
        return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;
    }

    // reset synchronizer database
    srcfiles.Reset();
    lines.Reset();
    points.Reset();
    fileIndex.Reset();
    sheetIndex.Reset();

    Vec<size_t> filestack;
    UINT page = 1;
    sheetIndex.Append(0);

    // add the initial tex file to the source file stack
    filestack.Push(srcfiles.size());
    srcfiles.Append(jobName.StealData());
    PdfsyncFileIndex findex = {0};
    fileIndex.Append(findex);

    PdfsyncLine psline;
    PdfsyncPoint pspoint;

    // parse data
    UINT maxPageNo = engine->PageCount();
    while ((line = Advance0Line(line, dataEnd)) != nullptr) {
        if (!line)
            break;
        switch (*line) {
            case 'l':
                psline.file = filestack.Last();
                if (str::Parse(line, "l %u %u %u", &psline.record, &psline.line, &psline.column))
                    lines.Append(psline);
                else if (str::Parse(line, "l %u %u", &psline.record, &psline.line)) {
                    psline.column = 0;
                    lines.Append(psline);
                }
                // else dbg("Bad 'l' line in the pdfsync file");
                break;

            case 's':
                if (str::Parse(line, "s %u", &page))
                    sheetIndex.Append(points.size());
                // else dbg("Bad 's' line in the pdfsync file");
                // if (0 == page || page > maxPageNo)
                //     dbg("'s' line with invalid page number in the pdfsync file");
                break;

            case 'p':
                pspoint.page = page;
                if (0 == page || page > maxPageNo)
                    /* ignore point for invalid page number */;
                else if (str::Parse(line, "p %u %u %u", &pspoint.record, &pspoint.x, &pspoint.y))
                    points.Append(pspoint);
                else if (str::Parse(line, "p* %u %u %u", &pspoint.record, &pspoint.x, &pspoint.y))
                    points.Append(pspoint);
                // else dbg("Bad 'p' line in the pdfsync file");
                break;

            case '(': {
                AutoFreeW filename(str::conv::FromAnsi(line + 1));
                // if the filename contains quotes then remove them
                // TODO: this should never happen!?
                if (filename[0] == '"' && filename[str::Len(filename) - 1] == '"')
                    filename.Set(str::DupN(filename + 1, str::Len(filename) - 2));
                // undecorate the filepath: replace * by space and / by \ (backslash)
                str::TransChars(filename, L"*/", L" \\");
                // if the file name extension is not specified then add the suffix '.tex'
                if (str::IsEmpty(path::GetExt(filename)))
                    filename.Set(str::Join(filename, L".tex"));
                // ensure that the path is absolute
                if (PathIsRelative(filename))
                    filename.Set(PrependDir(filename));

                filestack.Push(srcfiles.size());
                srcfiles.Append(filename.StealData());
                findex.start = findex.end = lines.size();
                fileIndex.Append(findex);
            } break;

            case ')':
                if (filestack.size() > 1)
                    fileIndex.at(filestack.Pop()).end = lines.size();
                // else dbg("Unbalanced ')' line in the pdfsync file");
                break;

            default:
                // dbg("Ignoring invalid pdfsync line starting with '%c'", *line);
                break;
        }
    }

    fileIndex.at(0).end = lines.size();
    AssertCrash(filestack.size() == 1);

    return Synchronizer::RebuildIndex();
}