forked from pdfcpu/pdfcpu
/
configuration.go
388 lines (336 loc) · 9.24 KB
/
configuration.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
/*
Copyright 2018 The pdfcpu Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pdfcpu
import (
_ "embed"
"fmt"
"os"
"path/filepath"
"time"
"github.com/Equilaw/pdfcpu/pkg/font"
)
const (
// ValidationStrict ensures 100% compliance with the spec (PDF 32000-1:2008).
ValidationStrict int = iota
// ValidationRelaxed ensures PDF compliance based on frequently encountered validation errors.
ValidationRelaxed
// ValidationNone bypasses validation.
ValidationNone
)
const (
// StatsFileNameDefault is the standard stats filename.
StatsFileNameDefault = "stats.csv"
// PermissionsAll enables all user access permission bits.
PermissionsAll int16 = -1 // 0xFFFF
// PermissionsPrint disables all user access permissions bits except for printing.
PermissionsPrint int16 = -1849 // 0xF8C7
// PermissionsNone disables all user access permissions bits.
PermissionsNone int16 = -3901 // 0xF0C3
)
// CommandMode specifies the operation being executed.
type CommandMode int
// The available commands.
const (
VALIDATE CommandMode = iota
OPTIMIZE
SPLIT
MERGECREATE
MERGEAPPEND
EXTRACTIMAGES
EXTRACTFONTS
EXTRACTPAGES
EXTRACTCONTENT
EXTRACTMETADATA
TRIM
ADDATTACHMENTS
ADDATTACHMENTSPORTFOLIO
REMOVEATTACHMENTS
EXTRACTATTACHMENTS
LISTATTACHMENTS
SETPERMISSIONS
LISTPERMISSIONS
ENCRYPT
DECRYPT
CHANGEUPW
CHANGEOPW
ADDWATERMARKS
REMOVEWATERMARKS
IMPORTIMAGES
INSERTPAGESBEFORE
INSERTPAGESAFTER
REMOVEPAGES
ROTATE
NUP
BOOKLET
INFO
CHEATSHEETSFONTS
INSTALLFONTS
LISTFONTS
LISTKEYWORDS
ADDKEYWORDS
REMOVEKEYWORDS
LISTPROPERTIES
ADDPROPERTIES
REMOVEPROPERTIES
COLLECT
CROP
LISTBOXES
ADDBOXES
REMOVEBOXES
LISTANNOTATIONS
ADDANNOTATIONS
REMOVEANNOTATIONS
ADDBOOKMARKS
LISTIMAGES
CREATE
)
// Configuration of a Context.
type Configuration struct {
// Location of corresponding config.yml
Path string
// Check filename extensions.
CheckFileNameExt bool
// Enables PDF V1.5 compatible processing of object streams, xref streams, hybrid PDF files.
Reader15 bool
// Enables decoding of all streams (fontfiles, images..) for logging purposes.
DecodeAllStreams bool
// Validate against ISO-32000: strict or relaxed.
ValidationMode int
// Check for broken links in LinkedAnnotations/URIActions.
ValidateLinks bool
// End of line char sequence for writing.
Eol string
// Turns on object stream generation.
// A signal for compressing any new non-stream-object into an object stream.
// true enforces WriteXRefStream to true.
// false does not prevent xRefStream generation.
WriteObjectStream bool
// Switches between xRefSection (<=V1.4) and objectStream/xRefStream (>=V1.5) writing.
WriteXRefStream bool
// Turns on stats collection.
// TODO Decision - unused.
CollectStats bool
// A CSV-filename holding the statistics.
StatsFileName string
// Supplied user password.
UserPW string
UserPWNew *string
// Supplied owner password.
OwnerPW string
OwnerPWNew *string
// EncryptUsingAES ensures AES encryption.
// true: AES encryption
// false: RC4 encryption.
EncryptUsingAES bool
// AES:40,128,256 RC4:40,128
EncryptKeyLength int
// Supplied user access permissions, see Table 22.
Permissions int16
// Command being executed.
Cmd CommandMode
// Display unit in effect.
Unit DisplayUnit
// Timestamp format.
TimestampFormat string
// Buffersize for locating PDF header <= 100
HeaderBufSize int
// Optimize duplicate content streams across pages.
OptimizeDuplicateContentStreams bool
}
// ConfigPath defines the location of pdfcpu's configuration directory.
// If set to a file path, pdfcpu will ensure the config dir at this location.
// Other possible values:
// default: Ensure config dir at default location
// disable: Disable config dir usage
var ConfigPath string = "default"
var loadedDefaultConfig *Configuration
//go:embed config.yml
var configFileBytes []byte
func ensureConfigFileAt(path string) error {
f, err := os.Open(path)
if err != nil {
f.Close()
s := fmt.Sprintf("#############################\n# pdfcpu %s #\n# Created: %s #\n", VersionStr, time.Now().Format("2006-01-02 15:04"))
bb := append([]byte(s), configFileBytes...)
if err := os.WriteFile(path, bb, os.ModePerm); err != nil {
return err
}
f, err = os.Open(path)
if err != nil {
return err
}
}
defer f.Close()
// Load configuration into loadedDefaultConfig.
return parseConfigFile(f, path)
}
// EnsureDefaultConfigAt tries to load the default configuration from path.
// If path/pdfcpu/config.yaml is not found, it will be created.
func EnsureDefaultConfigAt(path string) error {
configDir := filepath.Join(path, "pdfcpu")
font.UserFontDir = filepath.Join(configDir, "fonts")
if err := os.MkdirAll(font.UserFontDir, os.ModePerm); err != nil {
return err
}
if err := ensureConfigFileAt(filepath.Join(configDir, "config.yml")); err != nil {
return err
}
//fmt.Println(loadedDefaultConfig)
return font.LoadUserFonts()
}
func newDefaultConfiguration() *Configuration {
// NOTE: Needs to stay in sync with config.yml
//
// Takes effect whenever the installed config.yml is disabled:
// cli: supply -conf disable
// api: call api.DisableConfigDir()
return &Configuration{
CheckFileNameExt: true,
Reader15: true,
DecodeAllStreams: false,
ValidationMode: ValidationRelaxed,
ValidateLinks: false,
Eol: EolLF,
WriteObjectStream: true,
WriteXRefStream: true,
EncryptUsingAES: true,
EncryptKeyLength: 256,
Permissions: PermissionsNone,
TimestampFormat: "2006-01-02 15:04",
HeaderBufSize: 100,
OptimizeDuplicateContentStreams: false,
}
}
// NewDefaultConfiguration returns the default pdfcpu configuration.
func NewDefaultConfiguration() *Configuration {
if loadedDefaultConfig != nil {
c := *loadedDefaultConfig
return &c
}
if ConfigPath != "disable" {
path, err := os.UserConfigDir()
if err != nil {
path = os.TempDir()
}
if err = EnsureDefaultConfigAt(path); err == nil {
c := *loadedDefaultConfig
return &c
}
fmt.Fprintf(os.Stderr, "pdfcpu: config dir problem: %v\n", err)
os.Exit(1)
}
// Bypass config.yml
return newDefaultConfiguration()
}
// NewAESConfiguration returns a default configuration for AES encryption.
func NewAESConfiguration(userPW, ownerPW string, keyLength int) *Configuration {
c := NewDefaultConfiguration()
c.UserPW = userPW
c.OwnerPW = ownerPW
c.EncryptUsingAES = true
c.EncryptKeyLength = keyLength
return c
}
// NewRC4Configuration returns a default configuration for RC4 encryption.
func NewRC4Configuration(userPW, ownerPW string, keyLength int) *Configuration {
c := NewDefaultConfiguration()
c.UserPW = userPW
c.OwnerPW = ownerPW
c.EncryptUsingAES = false
c.EncryptKeyLength = keyLength
return c
}
func (c Configuration) String() string {
path := "default"
if len(c.Path) > 0 {
path = c.Path
}
return fmt.Sprintf("pdfcpu configuration:\n"+
"Path: %s\n"+
"CheckFileNameExt: %t\n"+
"Reader15: %t\n"+
"DecodeAllStreams: %t\n"+
"ValidationMode: %s\n"+
"Eol: %s\n"+
"WriteObjectStream: %t\n"+
"WriteXrefStream: %t\n"+
"EncryptUsingAES: %t\n"+
"EncryptKeyLength: %d\n"+
"Permissions: %d\n"+
"Unit : %s\n"+
"TimestampFormat: %s\n"+
"HeaderBufSize: %d\n"+
"OptimizeDuplicateContentStreams %t\n",
path,
c.CheckFileNameExt,
c.Reader15,
c.DecodeAllStreams,
c.ValidationModeString(),
c.EolString(),
c.WriteObjectStream,
c.WriteXRefStream,
c.EncryptUsingAES,
c.EncryptKeyLength,
c.Permissions,
c.UnitString(),
c.TimestampFormat,
c.HeaderBufSize,
c.OptimizeDuplicateContentStreams,
)
}
// EolString returns a string rep for the eol in effect.
func (c *Configuration) EolString() string {
var s string
switch c.Eol {
case EolLF:
s = "EolLF"
case EolCR:
s = "EolCR"
case EolCRLF:
s = "EolCRLF"
}
return s
}
// ValidationModeString returns a string rep for the validation mode in effect.
func (c *Configuration) ValidationModeString() string {
if c.ValidationMode == ValidationStrict {
return "strict"
}
if c.ValidationMode == ValidationRelaxed {
return "relaxed"
}
return "none"
}
// UnitString returns a string rep for the display unit in effect.
func (c *Configuration) UnitString() string {
var s string
switch c.Unit {
case POINTS:
s = "points"
case INCHES:
s = "inches"
case CENTIMETRES:
s = "cm"
case MILLIMETRES:
s = "mm"
}
return s
}
// ApplyReducedFeatureSet returns true if complex entries like annotations shall not be written.
func (c *Configuration) ApplyReducedFeatureSet() bool {
switch c.Cmd {
case SPLIT, TRIM, EXTRACTPAGES, MERGECREATE, MERGEAPPEND, IMPORTIMAGES:
return true
}
return false
}