pdfseparate.cc 5.13 KB
Newer Older
Thomas Freitag's avatar
Thomas Freitag committed
1 2
//========================================================================
//
3
// pdfseparate.cc
Thomas Freitag's avatar
Thomas Freitag committed
4 5 6
//
// This file is licensed under the GPLv2 or later
//
7
// Copyright (C) 2011, 2012, 2015 Thomas Freitag <Thomas.Freitag@alfa.de>
8
// Copyright (C) 2012-2014, 2017, 2018 Albert Astals Cid <aacid@kde.org>
Albert Astals Cid's avatar
Albert Astals Cid committed
9
// Copyright (C) 2013, 2016 Pino Toscano <pino@kde.org>
10
// Copyright (C) 2013 Daniel Kahn Gillmor <dkg@fifthhorseman.net>
11
// Copyright (C) 2013 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
Albert Astals Cid's avatar
Albert Astals Cid committed
12
// Copyright (C) 2017 Léonard Michelet <leonard.michelet@smile.fr>
Albert Astals Cid's avatar
Albert Astals Cid committed
13
// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
14
// Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
Thomas Freitag's avatar
Thomas Freitag committed
15 16 17 18 19 20 21 22 23 24 25 26
//
//========================================================================
#include "config.h"
#include <poppler-config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "parseargs.h"
#include "goo/GooString.h"
#include "PDFDoc.h"
#include "ErrorCodes.h"
27
#include "GlobalParams.h"
28
#include "Win32Console.h"
29
#include <ctype.h>
Thomas Freitag's avatar
Thomas Freitag committed
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

static int firstPage = 0;
static int lastPage = 0;
static GBool printVersion = gFalse;
static GBool printHelp = gFalse;

static const ArgDesc argDesc[] = {
  {"-f", argInt, &firstPage, 0,
   "first page to extract"},
  {"-l", argInt, &lastPage, 0,
   "last page to extract"},
  {"-v", argFlag, &printVersion, 0,
   "print copyright and version info"},
  {"-h", argFlag, &printHelp, 0,
   "print usage information"},
  {"-help", argFlag, &printHelp, 0,
   "print usage information"},
  {"--help", argFlag, &printHelp, 0,
   "print usage information"},
  {"-?", argFlag, &printHelp, 0,
   "print usage information"},
51
  {}
Thomas Freitag's avatar
Thomas Freitag committed
52 53
};

54
static bool extractPages (const char *srcFileName, const char *destFileName) {
55
  char pathName[4096];
Thomas Freitag's avatar
Thomas Freitag committed
56
  GooString *gfileName = new GooString (srcFileName);
57
  PDFDoc *doc = new PDFDoc (gfileName, nullptr, nullptr, nullptr);
Thomas Freitag's avatar
Thomas Freitag committed
58 59

  if (!doc->isOk()) {
60
    error(errSyntaxError, -1, "Could not extract page(s) from damaged file ('{0:s}')", srcFileName);
61
    delete doc;
Thomas Freitag's avatar
Thomas Freitag committed
62 63 64
    return false;
  }

65 66 67 68 69
  // destFileName can have multiple %% and one %d
  // We use auxDestFileName to replace all the valid % appearances
  // by 'A' (random char that is not %), if at the end of replacing
  // any of the valid appearances there is still any % around, the
  // pattern is wrong
Thomas Freitag's avatar
Thomas Freitag committed
70 71 72 73 74 75 76 77
  if (firstPage == 0 && lastPage == 0) {
    firstPage = 1;
    lastPage = doc->getNumPages();
  }
  if (lastPage == 0)
    lastPage = doc->getNumPages();
  if (firstPage == 0)
    firstPage = 1;
78 79 80 81
  if (lastPage < firstPage) {
    error(errCommandLine, -1,
          "Wrong page range given: the first page ({0:d}) can not be after the last page ({1:d}).",
          firstPage, lastPage);
82
    delete doc;
83 84
    return false;
  }
85
  bool foundmatch = false;
Albert Astals Cid's avatar
Albert Astals Cid committed
86
  char *auxDestFileName = strdup(destFileName);
87
  char *p = strstr(auxDestFileName, "%d");
88
  if (p != nullptr) {
89 90 91
    foundmatch = true;
    *p = 'A';
  } else {
92
    char pattern[6];
93 94 95
    for (int i = 2; i < 10; i++) {
      sprintf(pattern, "%%0%dd", i);
      p = strstr(auxDestFileName, pattern);
96
      if (p != nullptr) {
97 98 99
       foundmatch = true;
       *p = 'A';
       break;
100 101
      }
    }
102
  }
103
  if (!foundmatch && firstPage != lastPage) {
104
    error(errSyntaxError, -1, "'{0:s}' must contain '%d' (or any variant respecting printf format) if more than one page should be extracted, in order to print the page number", destFileName);
105
    free(auxDestFileName);
106
    delete doc;
107 108
    return false;
  }
109 110 111

  // at this point auxDestFileName can only contain %%
  p = strstr(auxDestFileName, "%%");
112
  while (p != nullptr) {
113 114 115 116
    *p = 'A';
    *(p + 1) = 'A';
    p = strstr(p, "%%"); 
  }
117

118 119
  // at this point any other % is wrong
  p = strstr(auxDestFileName, "%");
120
  if (p != nullptr) {
121 122
    error(errSyntaxError, -1, "'{0:s}' can only contain one '%d' pattern", destFileName);
    free(auxDestFileName);
123
    delete doc;
124 125 126 127
    return false;
  }
  free(auxDestFileName);
  
Thomas Freitag's avatar
Thomas Freitag committed
128
  for (int pageNo = firstPage; pageNo <= lastPage; pageNo++) {
129
    snprintf (pathName, sizeof (pathName) - 1, destFileName, pageNo);
Thomas Freitag's avatar
Thomas Freitag committed
130
    GooString *gpageName = new GooString (pathName);
131
    PDFDoc *pagedoc = new PDFDoc (new GooString (srcFileName), nullptr, nullptr, nullptr);
132
    int errCode = pagedoc->savePageAs(gpageName, pageNo);
Thomas Freitag's avatar
Thomas Freitag committed
133 134
    if ( errCode != errNone) {
      delete gpageName;
135
      delete doc;
136
      delete pagedoc;
Thomas Freitag's avatar
Thomas Freitag committed
137 138
      return false;
    }
139
    delete pagedoc;
Thomas Freitag's avatar
Thomas Freitag committed
140 141
    delete gpageName;
  }
142
  delete doc;
Thomas Freitag's avatar
Thomas Freitag committed
143 144 145 146 147 148 149 150 151 152 153 154
  return true;
}

int
main (int argc, char *argv[])
{
  GBool ok;
  int exitCode;

  exitCode = 99;

  // parse args
155
  Win32Console win32console(&argc, &argv);
Thomas Freitag's avatar
Thomas Freitag committed
156 157 158
  ok = parseArgs (argDesc, &argc, argv);
  if (!ok || argc != 3 || printVersion || printHelp)
    {
159
      fprintf (stderr, "pdfseparate version %s\n", PACKAGE_VERSION);
Thomas Freitag's avatar
Thomas Freitag committed
160 161 162 163
      fprintf (stderr, "%s\n", popplerCopyright);
      fprintf (stderr, "%s\n", xpdfCopyright);
      if (!printVersion)
	{
164
	  printUsage ("pdfseparate", "<PDF-sourcefile> <PDF-pattern-destfile>",
Thomas Freitag's avatar
Thomas Freitag committed
165 166 167 168 169 170
		      argDesc);
	}
      if (printVersion || printHelp)
	exitCode = 0;
      goto err0;
    }
171
  globalParams = new GlobalParams();
172 173 174 175
  ok = extractPages (argv[1], argv[2]);
  if (ok) {
    exitCode = 0;
  }
176
  delete globalParams;
Thomas Freitag's avatar
Thomas Freitag committed
177 178 179 180 181

err0:

  return exitCode;
}