1 //========================================================================
2 //
3 // pdfattach.cc
4 //
5 // This file is licensed under the GPLv2 or later
6 //
7 // Copyright (C) 2019-2021 Albert Astals Cid <aacid@kde.org>
8 // Copyright (C) 2019 Oliver Sander <oliver.sander@tu-dresden.de>
9 //
10 // To see a description of the changes please see the Changelog file that
11 // came with your tarball or type make ChangeLog if you are building from git
12 //
13 //========================================================================
14 
15 #include "config.h"
16 #include <poppler-config.h>
17 #include "gbasename.h"
18 #include "parseargs.h"
19 #include "GlobalParams.h"
20 #include "PDFDoc.h"
21 #include "PDFDocFactory.h"
22 #include "Error.h"
23 #include "ErrorCodes.h"
24 #include "Win32Console.h"
25 
26 static bool doReplace = false;
27 static bool printVersion = false;
28 static bool printHelp = false;
29 
30 static const ArgDesc argDesc[] = { { "-replace", argFlag, &doReplace, 0, "replace embedded file with same name (if it exists)" },
31                                    { "-v", argFlag, &printVersion, 0, "print copyright and version info" },
32                                    { "-h", argFlag, &printHelp, 0, "print usage information" },
33                                    { "-help", argFlag, &printHelp, 0, "print usage information" },
34                                    { "--help", argFlag, &printHelp, 0, "print usage information" },
35                                    { "-?", argFlag, &printHelp, 0, "print usage information" },
36                                    {} };
37 
fileExists(const char * filePath)38 static bool fileExists(const char *filePath)
39 {
40     FILE *f = openFile(filePath, "r");
41     if (f != nullptr) {
42         fclose(f);
43         return true;
44     }
45     return false;
46 }
47 
main(int argc,char * argv[])48 int main(int argc, char *argv[])
49 {
50     Win32Console win32Console(&argc, &argv);
51 
52     // parse args
53     const bool ok = parseArgs(argDesc, &argc, argv);
54     if (!ok || argc != 4 || printVersion || printHelp) {
55         fprintf(stderr, "pdfattach version %s\n", PACKAGE_VERSION);
56         fprintf(stderr, "%s\n", popplerCopyright);
57         fprintf(stderr, "%s\n", xpdfCopyright);
58         if (!printVersion) {
59             printUsage("pdfattach", "<input-PDF-file> <file-to-attach> <output-PDF-file>", argDesc);
60         }
61         return 99;
62     }
63     const GooString pdfFileName(argv[1]);
64     const std::string attachFilePath(argv[2]);
65 
66     // init GlobalParams
67     globalParams = std::make_unique<GlobalParams>();
68 
69     // open PDF file
70     std::unique_ptr<PDFDoc> doc(PDFDocFactory().createPDFDoc(pdfFileName, nullptr, nullptr));
71 
72     if (!doc->isOk()) {
73         fprintf(stderr, "Couldn't open %s\n", pdfFileName.c_str());
74         return 1;
75     }
76 
77     std::unique_ptr<GooFile> attachFile(GooFile::open(attachFilePath));
78     if (!attachFile) {
79         fprintf(stderr, "Couldn't open %s\n", attachFilePath.c_str());
80         return 2;
81     }
82 
83     if (fileExists(argv[3])) {
84         fprintf(stderr, "File %s already exists.\n", argv[3]);
85         return 3;
86     }
87 
88     const std::string attachFileName = gbasename(attachFilePath.c_str());
89 
90     if (!doReplace && doc->getCatalog()->hasEmbeddedFile(attachFileName)) {
91         fprintf(stderr, "There is already an embedded file named %s.\n", attachFileName.c_str());
92         return 4;
93     }
94 
95     doc->getCatalog()->addEmbeddedFile(attachFile.get(), attachFileName);
96 
97     const GooString outputPdfFilePath(argv[3]);
98     const int saveResult = doc->saveAs(&outputPdfFilePath);
99     if (saveResult != errNone) {
100         fprintf(stderr, "Couldn't save the file properly.\n");
101         return 5;
102     }
103 
104     return 0;
105 }
106