void LaunchWithSumatra(InstanceData *data, const char *url_utf8) { if (!file::Exists(data->filepath)) plogf("sp: NPP_StreamAsFile() error: file doesn't exist"); ScopedMem<WCHAR> url(str::conv::FromUtf8(url_utf8)); // escape quotation marks and backslashes for CmdLineParser.cpp's ParseQuoted if (str::FindChar(url, '"')) { WStrVec parts; parts.Split(url, L"\""); url.Set(parts.Join(L"%22")); } if (str::EndsWith(url, L"\\")) { url[str::Len(url) - 1] = '\0'; url.Set(str::Join(url, L"%5c")); } // prevent overlong URLs from making LaunchProcess fail if (str::Len(url) > 4096) url.Set(NULL); ScopedMem<WCHAR> cmdLine(str::Format(L"\"%s\" -plugin \"%s\" %d \"%s\"", data->exepath, url ? url : L"", (HWND)data->npwin->window, data->filepath)); data->hProcess = LaunchProcess(cmdLine); if (!data->hProcess) { plogf("sp: NPP_StreamAsFile() error: couldn't run SumatraPDF!"); data->message = _TR("Error: Couldn't run SumatraPDF!"); } }
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.Count() - 1) // skip the first arg (exe path) for (size_t i = 1; i < argList.Count(); 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::ToLower(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 } }
/* Make a string safe to be displayed as a menu item (preserving all & so that they don't get swallowed) Caller needs to free() the result. */ WCHAR *ToSafeString(const WCHAR *str) { if (!str::FindChar(str, '&')) return str::Dup(str); WStrVec ampSplitter; ampSplitter.Split(str, L"&"); return ampSplitter.Join(L"&&"); }
void DumpProperties(BaseEngine *engine, bool fullDump) { Out("\t<Properties\n"); ScopedMem<char> str; str.Set(Escape(str::Dup(engine->FileName()))); Out("\t\tFilePath=\"%s\"\n", str.Get()); str.Set(Escape(engine->GetProperty(Prop_Title))); if (str) Out("\t\tTitle=\"%s\"\n", str.Get()); str.Set(Escape(engine->GetProperty(Prop_Subject))); if (str) Out("\t\tSubject=\"%s\"\n", str.Get()); str.Set(Escape(engine->GetProperty(Prop_Author))); if (str) Out("\t\tAuthor=\"%s\"\n", str.Get()); str.Set(Escape(engine->GetProperty(Prop_Copyright))); if (str) Out("\t\tCopyright=\"%s\"\n", str.Get()); str.Set(Escape(engine->GetProperty(Prop_CreationDate))); if (str) Out("\t\tCreationDate=\"%s\"\n", str.Get()); str.Set(Escape(engine->GetProperty(Prop_ModificationDate))); if (str) Out("\t\tModDate=\"%s\"\n", str.Get()); str.Set(Escape(engine->GetProperty(Prop_CreatorApp))); if (str) Out("\t\tCreator=\"%s\"\n", str.Get()); str.Set(Escape(engine->GetProperty(Prop_PdfProducer))); if (str) Out("\t\tPdfProducer=\"%s\"\n", str.Get()); str.Set(Escape(engine->GetProperty(Prop_PdfVersion))); if (str) Out("\t\tPdfVersion=\"%s\"\n", str.Get()); str.Set(Escape(engine->GetProperty(Prop_PdfFileStructure))); if (str) Out("\t\tPdfFileStructure=\"%s\"\n", str.Get()); if (!engine->AllowsPrinting()) Out("\t\tPrintingAllowed=\"no\"\n"); if (!engine->AllowsCopyingText()) Out("\t\tCopyingTextAllowed=\"no\"\n"); if (engine->IsImageCollection()) Out("\t\tImageCollection=\"yes\"\n"); if (engine->PreferredLayout()) Out("\t\tPreferredLayout=\"%d\"\n", engine->PreferredLayout()); Out("\t/>\n"); if (fullDump) { ScopedMem<WCHAR> fontlist(engine->GetProperty(Prop_FontList)); if (fontlist) { WStrVec fonts; fonts.Split(fontlist, L"\n"); str.Set(Escape(fonts.Join(L"\n\t\t"))); Out("\t<FontList>\n\t\t%s\n\t</FontList>\n", str.Get()); } } }
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.exitWhenDone = false; gGlobalPrefs->reuseInstance = false; // always display the toolbar when embedded (as there's no menubar in that case) gGlobalPrefs->showToolbar = true; // never allow esc as a shortcut to quit gGlobalPrefs->escToExit = false; // never show the sidebar by default gGlobalPrefs->showToc = false; if (DM_AUTOMATIC == gGlobalPrefs->defaultDisplayModeEnum) { // 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->defaultDisplayModeEnum = DM_CONTINUOUS; gGlobalPrefs->defaultZoomFloat = ZOOM_FIT_WIDTH; } // use fixed page UI for all document types (so that the context menu always // contains all plugin specific entries and the main window is never closed) gGlobalPrefs->ebookUI.useFixedPageUI = gGlobalPrefs->chmUI.useFixedPageUI = true; // 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<WCHAR> args(str::Dup(str::FindChar(i.pluginURL, '#') + 1)); str::TransChars(args, L"#", L"&"); WStrVec parts; parts.Split(args, L"&", true); for (size_t k = 0; k < parts.Count(); k++) { WCHAR *part = parts.At(k); int pageNo; if (str::StartsWithI(part, L"page=") && str::Parse(part + 4, L"=%d%$", &pageNo)) i.pageNumber = pageNo; else if (str::StartsWithI(part, L"nameddest=") && part[10]) str::ReplacePtr(&i.destName, part + 10); else if (!str::FindChar(part, '=') && part[0]) str::ReplacePtr(&i.destName, part); } } return true; }
static void ApplyPrintSettings(const WCHAR *settings, int pageCount, Vec<PRINTPAGERANGE> &ranges, Print_Advanced_Data &advanced, LPDEVMODE devMode) { WStrVec rangeList; if (settings) rangeList.Split(settings, L",", true); for (size_t i = 0; i < rangeList.Count(); i++) { int val; PRINTPAGERANGE pr; if (str::Parse(rangeList.At(i), L"%d-%d%$", &pr.nFromPage, &pr.nToPage)) { pr.nFromPage = limitValue(pr.nFromPage, (DWORD)1, (DWORD)pageCount); pr.nToPage = limitValue(pr.nToPage, (DWORD)1, (DWORD)pageCount); ranges.Append(pr); } else if (str::Parse(rangeList.At(i), L"%d%$", &pr.nFromPage)) { pr.nFromPage = pr.nToPage = limitValue(pr.nFromPage, (DWORD)1, (DWORD)pageCount); ranges.Append(pr); } else if (str::EqI(rangeList.At(i), L"even")) advanced.range = PrintRangeEven; else if (str::EqI(rangeList.At(i), L"odd")) advanced.range = PrintRangeOdd; else if (str::EqI(rangeList.At(i), L"noscale")) advanced.scale = PrintScaleNone; else if (str::EqI(rangeList.At(i), L"shrink")) advanced.scale = PrintScaleShrink; else if (str::EqI(rangeList.At(i), L"fit")) advanced.scale = PrintScaleFit; else if (str::Parse(rangeList.At(i), L"%dx%$", &val) && 0 < val && val < 1000) devMode->dmCopies = (short)val; else if (str::EqI(rangeList.At(i), L"simplex")) devMode->dmDuplex = DMDUP_SIMPLEX; else if (str::EqI(rangeList.At(i), L"duplex") || str::EqI(rangeList.At(i), L"duplexlong")) devMode->dmDuplex = DMDUP_VERTICAL; else if (str::EqI(rangeList.At(i), L"duplexshort")) devMode->dmDuplex = DMDUP_HORIZONTAL; else if (str::EqI(rangeList.At(i), L"color")) devMode->dmColor = DMCOLOR_COLOR; else if (str::EqI(rangeList.At(i), L"monochrome")) devMode->dmColor = DMCOLOR_MONOCHROME; else if (str::StartsWithI(rangeList.At(i), L"bin=")) devMode->dmDefaultSource = GetPaperSourceByName(rangeList.At(i) + 4, devMode); else if (str::StartsWithI(rangeList.At(i), L"paper=")) devMode->dmPaperSize = GetPaperByName(rangeList.At(i) + 6); } if (ranges.Count() == 0) { PRINTPAGERANGE pr = { 1, (DWORD)pageCount }; ranges.Append(pr); } }
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.Count() - 1) // skip the first arg (exe path) for (size_t i = 1; i < argList.Count(); 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::ToLower(opts); str::TransChars(opts, L" ;", L",,"); WStrVec optlist; optlist.Split(opts, L",", true); if (optlist.Find(L"plugin") != -1) gGlobalData.installBrowserPlugin = true; if (optlist.Find(L"pdffilter") != -1) gGlobalData.installPdfFilter = true; if (optlist.Find(L"pdfpreviewer") != -1) gGlobalData.installPdfPreviewer = 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 } }
static void ApplyPrintSettings(const WCHAR *settings, int pageCount, Vec<PRINTPAGERANGE>& ranges, Print_Advanced_Data& advanced, LPDEVMODE devMode) { WStrVec rangeList; if (settings) rangeList.Split(settings, L",", true); for (size_t i = 0; i < rangeList.Count(); i++) { int val; PRINTPAGERANGE pr; if (str::Parse(rangeList.At(i), L"%d-%d%$", &pr.nFromPage, &pr.nToPage)) { pr.nFromPage = limitValue(pr.nFromPage, (DWORD)1, (DWORD)pageCount); pr.nToPage = limitValue(pr.nToPage, (DWORD)1, (DWORD)pageCount); ranges.Append(pr); } else if (str::Parse(rangeList.At(i), L"%d%$", &pr.nFromPage)) { pr.nFromPage = pr.nToPage = limitValue(pr.nFromPage, (DWORD)1, (DWORD)pageCount); ranges.Append(pr); } else if (str::Eq(rangeList.At(i), L"even")) advanced.range = PrintRangeEven; else if (str::Eq(rangeList.At(i), L"odd")) advanced.range = PrintRangeOdd; else if (str::Eq(rangeList.At(i), L"noscale")) advanced.scale = PrintScaleNone; else if (str::Eq(rangeList.At(i), L"shrink")) advanced.scale = PrintScaleShrink; else if (str::Eq(rangeList.At(i), L"fit")) advanced.scale = PrintScaleFit; else if (str::Eq(rangeList.At(i), L"compat")) advanced.asImage = true; else if (str::Parse(rangeList.At(i), L"%dx%$", &val) && 0 < val && val < 1000) devMode->dmCopies = (short)val; else if (str::Eq(rangeList.At(i), L"duplex") || str::Eq(rangeList.At(i), L"duplexlong")) devMode->dmDuplex = DMDUP_VERTICAL; else if (str::Eq(rangeList.At(i), L"duplexshort")) devMode->dmDuplex = DMDUP_HORIZONTAL; } if (ranges.Count() == 0) { PRINTPAGERANGE pr = { 1, pageCount }; ranges.Append(pr); } }
// 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; }
static WCHAR *FormatPdfFileStructure(Doc doc) { ScopedMem<WCHAR> fstruct(doc.GetProperty(Prop_PdfFileStructure)); if (str::IsEmpty(fstruct.Get())) return NULL; WStrVec parts; parts.Split(fstruct, L",", true); WStrVec props; if (parts.Find(L"linearized") != -1) props.Push(str::Dup(_TR("Fast Web View"))); if (parts.Find(L"tagged") != -1) props.Push(str::Dup(_TR("Tagged PDF"))); if (parts.Find(L"PDFX") != -1) props.Push(str::Dup(L"PDF/X (ISO 15930)")); if (parts.Find(L"PDFA1") != -1) props.Push(str::Dup(L"PDF/A (ISO 19005)")); if (parts.Find(L"PDFE1") != -1) props.Push(str::Dup(L"PDF/E (ISO 24517)")); return props.Join(L", "); }
static WCHAR *FormatPdfFileStructure(Controller *ctrl) { ScopedMem<WCHAR> fstruct(ctrl->GetProperty(Prop_PdfFileStructure)); if (str::IsEmpty(fstruct.Get())) return nullptr; WStrVec parts; parts.Split(fstruct, L",", true); WStrVec props; if (parts.Contains(L"linearized")) props.Push(str::Dup(_TR("Fast Web View"))); if (parts.Contains(L"tagged")) props.Push(str::Dup(_TR("Tagged PDF"))); if (parts.Contains(L"PDFX")) props.Push(str::Dup(L"PDF/X (ISO 15930)")); if (parts.Contains(L"PDFA1")) props.Push(str::Dup(L"PDF/A (ISO 19005)")); if (parts.Contains(L"PDFE1")) props.Push(str::Dup(L"PDF/E (ISO 24517)")); return props.Join(L", "); }
static void ApplyPrintSettings(const WCHAR *settings, int pageCount, Vec<PRINTPAGERANGE>& ranges, Print_Advanced_Data& advanced) { WStrVec rangeList; if (settings) rangeList.Split(settings, L",", true); for (size_t i = 0; i < rangeList.Count(); i++) { PRINTPAGERANGE pr; if (str::Parse(rangeList.At(i), L"%d-%d%$", &pr.nFromPage, &pr.nToPage)) { pr.nFromPage = limitValue(pr.nFromPage, (DWORD)1, (DWORD)pageCount); pr.nToPage = limitValue(pr.nToPage, (DWORD)1, (DWORD)pageCount); ranges.Append(pr); } else if (str::Parse(rangeList.At(i), L"%d%$", &pr.nFromPage)) { pr.nFromPage = pr.nToPage = limitValue(pr.nFromPage, (DWORD)1, (DWORD)pageCount); ranges.Append(pr); } else if (str::Eq(rangeList.At(i), L"even")) advanced.range = PrintRangeEven; else if (str::Eq(rangeList.At(i), L"odd")) advanced.range = PrintRangeOdd; else if (str::Eq(rangeList.At(i), L"noscale")) advanced.scale = PrintScaleNone; else if (str::Eq(rangeList.At(i), L"shrink")) advanced.scale = PrintScaleShrink; else if (str::Eq(rangeList.At(i), L"fit")) advanced.scale = PrintScaleFit; else if (str::Eq(rangeList.At(i), L"compat")) advanced.asImage = true; } if (ranges.Count() == 0) { PRINTPAGERANGE pr = { 1, pageCount }; ranges.Append(pr); } }
static WCHAR *GetGhostscriptPath() { WCHAR *gsProducts[] = { L"AFPL Ghostscript", L"Aladdin Ghostscript", L"GPL Ghostscript", L"GNU Ghostscript", }; // find all installed Ghostscript versions WStrVec versions; REGSAM access = KEY_READ | KEY_WOW64_32KEY; TryAgain64Bit: for (int i = 0; i < dimof(gsProducts); i++) { HKEY hkey; ScopedMem<WCHAR> keyName(str::Join(L"Software\\", gsProducts[i])); if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, access, &hkey) != ERROR_SUCCESS) continue; WCHAR subkey[32]; for (DWORD ix = 0; RegEnumKey(hkey, ix, subkey, dimof(subkey)) == ERROR_SUCCESS; ix++) versions.Append(str::Dup(subkey)); RegCloseKey(hkey); } if ((access & KEY_WOW64_32KEY)) { // also look for 64-bit Ghostscript versions under 64-bit Windows access = KEY_READ | KEY_WOW64_64KEY; #ifndef _WIN64 // (unless this is 32-bit Windows) if (IsRunningInWow64()) #endif goto TryAgain64Bit; } versions.SortNatural(); // return the path to the newest installation for (size_t ix = versions.Count(); ix > 0; ix--) { for (int i = 0; i < dimof(gsProducts); i++) { ScopedMem<WCHAR> keyName(str::Format(L"Software\\%s\\%s", gsProducts[i], versions.At(ix - 1))); ScopedMem<WCHAR> GS_DLL(ReadRegStr(HKEY_LOCAL_MACHINE, keyName, L"GS_DLL")); if (!GS_DLL) continue; ScopedMem<WCHAR> dir(path::GetDir(GS_DLL)); ScopedMem<WCHAR> exe(path::Join(dir, L"gswin32c.exe")); if (file::Exists(exe)) return exe.StealData(); exe.Set(path::Join(dir, L"gswin64c.exe")); if (file::Exists(exe)) return exe.StealData(); } } // if Ghostscript isn't found in the Registry, try finding it in the %PATH% DWORD size = GetEnvironmentVariable(L"PATH", NULL, 0); ScopedMem<WCHAR> envpath(AllocArray<WCHAR>(size)); if (size > 0 && envpath) { GetEnvironmentVariable(L"PATH", envpath, size); WStrVec paths; paths.Split(envpath, L";", true); for (size_t ix = 0; ix < paths.Count(); ix++) { ScopedMem<WCHAR> exe(path::Join(paths.At(ix), L"gswin32c.exe")); if (file::Exists(exe)) return exe.StealData(); exe.Set(path::Join(paths.At(ix), L"gswin64c.exe")); if (file::Exists(exe)) return exe.StealData(); } } return NULL; }