Skip to content

Commit b1b9f99

Browse files
committed
Fix #868, add config parms offline, timeout
1 parent 23311b7 commit b1b9f99

File tree

13 files changed

+190
-85
lines changed

13 files changed

+190
-85
lines changed

cmd/pdfcpu/cmd.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ func (m commandMap) process(cmdPrefix string, command string) (string, error) {
139139
conf.OwnerPW = opw
140140
conf.UserPW = upw
141141

142+
if !conf.Offline {
143+
conf.Offline = offline
144+
}
145+
142146
if m[cmdStr].handler != nil {
143147
m[cmdStr].handler(conf)
144148
return command, nil

cmd/pdfcpu/init.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ func initFlags() {
338338
flag.StringVar(&mode, "mode", "", modeUsage)
339339
flag.StringVar(&mode, "m", "", modeUsage)
340340

341+
flag.BoolVar(&offline, "offline", false, "")
342+
flag.BoolVar(&offline, "off", false, "")
343+
flag.BoolVar(&offline, "o", false, "")
344+
341345
selectedPagesUsage := "a comma separated list of pages or page ranges, see pdfcpu selectedpages"
342346
flag.StringVar(&selectedPages, "pages", "", selectedPagesUsage)
343347
flag.StringVar(&selectedPages, "p", "", selectedPagesUsage)

cmd/pdfcpu/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ var (
2626
fileStats, mode, selectedPages string
2727
upw, opw, key, perm, unit, conf string
2828
verbose, veryVerbose bool
29-
links, quiet, sorted, bookmarks bool
29+
links, quiet, offline, sorted, bookmarks bool
3030
all, dividerPage, json, replaceBookmarks bool
3131
needStackTrace = true
3232
cmdMap commandMap

cmd/pdfcpu/process.go

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ import (
3939
"github.com/pkg/errors"
4040
)
4141

42+
func abs(i int) int {
43+
if i < 0 {
44+
return -i
45+
}
46+
return i
47+
}
48+
4249
func hasPDFExtension(filename string) bool {
4350
return strings.HasSuffix(strings.ToLower(filename), ".pdf")
4451
}
@@ -165,6 +172,58 @@ func process(cmd *cli.Command) {
165172
//os.Exit(0)
166173
}
167174

175+
func getBaseDir(path string) string {
176+
i := strings.Index(path, "**")
177+
basePath := path[:i]
178+
basePath = filepath.Clean(basePath)
179+
if basePath == "" {
180+
return "."
181+
}
182+
return basePath
183+
}
184+
185+
func expandWildcardsRec(s string, inFiles *[]string, conf *model.Configuration) error {
186+
s = filepath.Clean(s)
187+
wantsPdf := strings.HasSuffix(s, ".pdf")
188+
return filepath.WalkDir(getBaseDir(s), func(path string, d os.DirEntry, err error) error {
189+
if err != nil {
190+
return err
191+
}
192+
if d.IsDir() {
193+
return nil
194+
}
195+
196+
//filename := d.Name()
197+
198+
if ok := hasPDFExtension(path); ok {
199+
*inFiles = append(*inFiles, path)
200+
return nil
201+
}
202+
203+
if !wantsPdf && conf.CheckFileNameExt {
204+
//sensurePDFExtension(path)
205+
fmt.Fprintf(os.Stderr, "%s needs extension \".pdf\".\n", path)
206+
os.Exit(1)
207+
}
208+
209+
return nil
210+
})
211+
}
212+
213+
func expandWildcards(s string, inFiles *[]string, conf *model.Configuration) error {
214+
paths, err := filepath.Glob(s)
215+
if err != nil {
216+
return err
217+
}
218+
for _, path := range paths {
219+
if conf.CheckFileNameExt {
220+
ensurePDFExtension(path)
221+
}
222+
*inFiles = append(*inFiles, path)
223+
}
224+
return nil
225+
}
226+
168227
func processValidateCommand(conf *model.Configuration) {
169228
if len(flag.Args()) == 0 || selectedPages != "" {
170229
fmt.Fprintf(os.Stderr, "%s\n\n", usageValidate)
@@ -173,18 +232,29 @@ func processValidateCommand(conf *model.Configuration) {
173232

174233
inFiles := []string{}
175234
for _, arg := range flag.Args() {
235+
236+
if strings.Contains(arg, "**") {
237+
// **/ fails on first file w/o extension "pdf"
238+
// **/*.pdf
239+
if err := expandWildcardsRec(arg, &inFiles, conf); err != nil {
240+
fmt.Fprintf(os.Stderr, "%s", err)
241+
}
242+
continue
243+
}
244+
176245
if strings.Contains(arg, "*") {
177-
matches, err := filepath.Glob(arg)
178-
if err != nil {
246+
// * fails on first file w/o extension "pdf"
247+
// *.pdf
248+
if err := expandWildcards(arg, &inFiles, conf); err != nil {
179249
fmt.Fprintf(os.Stderr, "%s", err)
180-
os.Exit(1)
181250
}
182-
inFiles = append(inFiles, matches...)
183251
continue
184252
}
253+
185254
if conf.CheckFileNameExt {
186255
ensurePDFExtension(arg)
187256
}
257+
188258
inFiles = append(inFiles, arg)
189259
}
190260

@@ -964,10 +1034,8 @@ func updateWatermarks(conf *model.Configuration, onTop bool) {
9641034
switch mode {
9651035
case "text":
9661036
wm, err = pdfcpu.ParseTextWatermarkDetails(flag.Arg(0), flag.Arg(1), onTop, conf.Unit)
967-
9681037
case "image":
9691038
wm, err = pdfcpu.ParseImageWatermarkDetails(flag.Arg(0), flag.Arg(1), onTop, conf.Unit)
970-
9711039
case "pdf":
9721040
wm, err = pdfcpu.ParsePDFWatermarkDetails(flag.Arg(0), flag.Arg(1), onTop, conf.Unit)
9731041
default:
@@ -1197,13 +1265,6 @@ func processRemovePagesCommand(conf *model.Configuration) {
11971265
process(cli.RemovePagesCommand(inFile, outFile, pages, conf))
11981266
}
11991267

1200-
func abs(i int) int {
1201-
if i < 0 {
1202-
return -i
1203-
}
1204-
return i
1205-
}
1206-
12071268
func processRotateCommand(conf *model.Configuration) {
12081269
if len(flag.Args()) < 2 || len(flag.Args()) > 3 {
12091270
fmt.Fprintf(os.Stderr, "%s\n\n", usageRotate)

pkg/api/api.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func ReadContextFile(inFile string) (*model.Context, error) {
9191
logDisclaimerPDF20()
9292
}
9393

94-
if err = validate.XRefTable(ctx.XRefTable); err != nil {
94+
if err = validate.XRefTable(ctx); err != nil {
9595
return nil, err
9696
}
9797

@@ -103,7 +103,7 @@ func ValidateContext(ctx *model.Context) error {
103103
if ctx.Version() == model.V20 {
104104
logDisclaimerPDF20()
105105
}
106-
return validate.XRefTable(ctx.XRefTable)
106+
return validate.XRefTable(ctx)
107107
}
108108

109109
// OptimizeContext optimizes ctx.

pkg/pdfcpu/form/fill.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ func addImages(ctx *model.Context, pages map[string]*Page) ([]*model.Page, error
7070
RadioBtnAPs: map[float64]*primitives.AP{},
7171
OldFieldIDs: types.StringSet{},
7272
Debug: false,
73+
Offline: ctx.Offline,
74+
Timeout: ctx.Timeout,
7375
}
7476

7577
if err := cacheResIDs(ctx, pdf); err != nil {

pkg/pdfcpu/model/configuration.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,17 @@ type Configuration struct {
237237
// Optimize duplicate content streams across pages.
238238
OptimizeDuplicateContentStreams bool
239239

240-
// Merge creates bookmarks
240+
// Merge creates bookmarks.
241241
CreateBookmarks bool
242242

243243
// PDF Viewer is expected to supply appearance streams for form fields.
244244
NeedAppearances bool
245+
246+
// Internet availability.
247+
Offline bool
248+
249+
// HTTP timeout in seconds.
250+
Timeout int
245251
}
246252

247253
// ConfigPath defines the location of pdfcpu's configuration directory.
@@ -341,6 +347,8 @@ func newDefaultConfiguration() *Configuration {
341347
OptimizeDuplicateContentStreams: false,
342348
CreateBookmarks: true,
343349
NeedAppearances: false,
350+
Offline: false,
351+
Timeout: 5,
344352
}
345353
}
346354

@@ -412,7 +420,9 @@ func (c Configuration) String() string {
412420
"OptimizeResourceDicts %t\n"+
413421
"OptimizeDuplicateContentStreams %t\n"+
414422
"CreateBookmarks %t\n"+
415-
"NeedAppearances %t\n",
423+
"NeedAppearances %t\n"+
424+
"Offline %t\n"+
425+
"Timeout %d\n",
416426
path,
417427
c.CheckFileNameExt,
418428
c.Reader15,
@@ -434,6 +444,8 @@ func (c Configuration) String() string {
434444
c.OptimizeDuplicateContentStreams,
435445
c.CreateBookmarks,
436446
c.NeedAppearances,
447+
c.Offline,
448+
c.Timeout,
437449
)
438450
}
439451

pkg/pdfcpu/model/parseConfig.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ type configuration struct {
4949
OptimizeDuplicateContentStreams bool `yaml:"optimizeDuplicateContentStreams"`
5050
CreateBookmarks bool `yaml:"createBookmarks"`
5151
NeedAppearances bool `yaml:"needAppearances"`
52+
Offline bool `yaml:"offline"`
53+
Timeout int `yaml:"timeout"`
5254
}
5355

5456
func loadedConfig(c configuration, configPath string) *Configuration {
@@ -100,6 +102,8 @@ func loadedConfig(c configuration, configPath string) *Configuration {
100102
conf.OptimizeDuplicateContentStreams = c.OptimizeDuplicateContentStreams
101103
conf.CreateBookmarks = c.CreateBookmarks
102104
conf.NeedAppearances = c.NeedAppearances
105+
conf.Offline = c.Offline
106+
conf.Timeout = c.Timeout
103107

104108
return &conf
105109
}

pkg/pdfcpu/model/parseConfig_js.go

Lines changed: 31 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,15 @@ func handleConfEncryptKeyLength(v string, c *Configuration) error {
131131
return nil
132132
}
133133

134+
func handleTimeout(v string, c *Configuration) error {
135+
i, err := strconv.Atoi(v)
136+
if err != nil {
137+
return errors.Errorf("timeout is numeric > 0, got: %s", v)
138+
}
139+
c.Timeout = i
140+
return nil
141+
}
142+
134143
func handleConfPermissions(v string, c *Configuration) error {
135144
i, err := strconv.Atoi(v)
136145
if err != nil {
@@ -167,49 +176,12 @@ func handleDateFormat(v string, c *Configuration) error {
167176
return nil
168177
}
169178

170-
func handleOptimize(k, v string, c *Configuration) error {
171-
v = strings.ToLower(v)
172-
if v != "true" && v != "false" {
173-
return errors.Errorf("config key %s is boolean", k)
174-
}
175-
c.Optimize = v == "true"
176-
return nil
177-
}
178-
179-
func handleOptimizeResourceDicts(k, v string, c *Configuration) error {
179+
func boolean(k, v string) (bool, error) {
180180
v = strings.ToLower(v)
181181
if v != "true" && v != "false" {
182-
return errors.Errorf("config key %s is boolean", k)
182+
return false, errors.Errorf("config key %s is boolean", k)
183183
}
184-
c.OptimizeResourceDicts = v == "true"
185-
return nil
186-
}
187-
188-
func handleOptimizeDuplicateContentStreams(k, v string, c *Configuration) error {
189-
v = strings.ToLower(v)
190-
if v != "true" && v != "false" {
191-
return errors.Errorf("config key %s is boolean", k)
192-
}
193-
c.OptimizeDuplicateContentStreams = v == "true"
194-
return nil
195-
}
196-
197-
func handleCreateBookmarks(k, v string, c *Configuration) error {
198-
v = strings.ToLower(v)
199-
if v != "true" && v != "false" {
200-
return errors.Errorf("config key %s is boolean", k)
201-
}
202-
c.CreateBookmarks = v == "true"
203-
return nil
204-
}
205-
206-
func handleNeedAppearances(k, v string, c *Configuration) error {
207-
v = strings.ToLower(v)
208-
if v != "true" && v != "false" {
209-
return errors.Errorf("config key %s is boolean", k)
210-
}
211-
c.NeedAppearances = v == "true"
212-
return nil
184+
return v == "true", nil
213185
}
214186

215187
func parseKeysPart1(k, v string, c *Configuration) (bool, error) {
@@ -243,44 +215,50 @@ func parseKeysPart1(k, v string, c *Configuration) (bool, error) {
243215
return false, nil
244216
}
245217

246-
func parseKeysPart2(k, v string, c *Configuration) error {
218+
func parseKeysPart2(k, v string, c *Configuration) (err error) {
247219
switch k {
248220

249221
case "encryptUsingAES":
250-
return handleConfEncryptUsingAES(k, v, c)
222+
err = handleConfEncryptUsingAES(k, v, c)
251223

252224
case "encryptKeyLength":
253-
return handleConfEncryptKeyLength(v, c)
225+
err = handleConfEncryptKeyLength(v, c)
254226

255227
case "permissions":
256-
return handleConfPermissions(v, c)
228+
err = handleConfPermissions(v, c)
257229

258230
case "unit", "units":
259-
return handleConfUnit(v, c)
231+
err = handleConfUnit(v, c)
260232

261233
case "timestampFormat":
262-
return handleTimestampFormat(v, c)
234+
err = handleTimestampFormat(v, c)
263235

264236
case "dateFormat":
265-
return handleDateFormat(v, c)
237+
err = handleDateFormat(v, c)
266238

267239
case "optimize":
268-
return handleOptimize(k, v, c)
240+
c.Optimize, err = boolean(k, v)
269241

270242
case "optimizeResourceDicts":
271-
return handleOptimizeResourceDicts(k, v, c)
243+
c.OptimizeResourceDicts, err = boolean(k, v)
272244

273245
case "optimizeDuplicateContentStreams":
274-
return handleOptimizeDuplicateContentStreams(k, v, c)
246+
c.OptimizeDuplicateContentStreams, err = boolean(k, v)
275247

276248
case "createBookmarks":
277-
return handleCreateBookmarks(k, v, c)
249+
c.CreateBookmarks, err = boolean(k, v)
278250

279251
case "needAppearances":
280-
return handleNeedAppearances(k, v, c)
252+
c.NeedAppearances, err = boolean(k, v)
253+
254+
case "offline":
255+
c.Offline, err = boolean(k, v)
256+
257+
case "timeout":
258+
handleTimeout(v, c)
281259
}
282260

283-
return nil
261+
return err
284262
}
285263

286264
func parseKeyValue(k, v string, c *Configuration) error {

0 commit comments

Comments
 (0)