From 075feb93382cab65bff73db7ecd59f16f92f7ab5 Mon Sep 17 00:00:00 2001 From: Horst Rutter Date: Thu, 22 Apr 2021 21:15:24 +0200 Subject: [PATCH] Fix #322 --- pkg/cli/test/cli_test.go | 2 +- pkg/pdfcpu/createAnnotations.go | 2 +- pkg/pdfcpu/crypto.go | 29 +++++++++++---------------- pkg/pdfcpu/dict.go | 6 +++++- pkg/pdfcpu/read.go | 35 ++++----------------------------- pkg/pdfcpu/utf16.go | 12 +++++------ pkg/pdfcpu/validate/action.go | 8 ++++---- pkg/pdfcpu/validate/objects.go | 8 ++++---- pkg/pdfcpu/write.go | 5 +---- pkg/pdfcpu/writeImage.go | 18 +++++------------ pkg/pdfcpu/xreftable.go | 15 +++++++------- 11 files changed, 50 insertions(+), 90 deletions(-) diff --git a/pkg/cli/test/cli_test.go b/pkg/cli/test/cli_test.go index 53e67d058..53c16c5a1 100644 --- a/pkg/cli/test/cli_test.go +++ b/pkg/cli/test/cli_test.go @@ -108,7 +108,7 @@ func TestValidate(t *testing.T) { for _, f := range allPDFs(t, inDir) { inFile := filepath.Join(inDir, f) if err := validateFile(t, inFile, nil); err != nil { - t.Fatalf("%s: %v\n", msg, err) + t.Fatalf("%s: %s: %v\n", msg, inFile, err) } } } diff --git a/pkg/pdfcpu/createAnnotations.go b/pkg/pdfcpu/createAnnotations.go index 4e14b6685..685031717 100644 --- a/pkg/pdfcpu/createAnnotations.go +++ b/pkg/pdfcpu/createAnnotations.go @@ -941,7 +941,7 @@ func createRemoteGoToAction(xRefTable *XRefTable) (*IndirectRef, error) { map[string]Object{ "Type": Name("Action"), "S": Name("GoToR"), - "F": StringLiteral(".\\/go.pdf"), + "F": StringLiteral("./go.pdf"), "D": Array{Integer(0), Name("Fit")}, "NewWindow": Boolean(true), }, diff --git a/pkg/pdfcpu/crypto.go b/pkg/pdfcpu/crypto.go index 4004fee8c..3ab13cff8 100644 --- a/pkg/pdfcpu/crypto.go +++ b/pkg/pdfcpu/crypto.go @@ -862,7 +862,7 @@ func validateOAndU(d Dict) (o, u []byte, err error) { break } if o == nil || len(o) != 32 && len(o) != 48 { - err = errors.New("pdfcpu: unsupported encryption: required entry \"O\" missing or invalid") + err = errors.New("pdfcpu: unsupported encryption: missing or invalid required entry \"O\"") break } @@ -872,7 +872,7 @@ func validateOAndU(d Dict) (o, u []byte, err error) { break } if u == nil || len(u) != 32 && len(u) != 48 { - err = errors.Errorf("pdfcpu: unsupported encryption: required entry \"U\" missing or invalid %d", len(u)) + err = errors.New("pdfcpu: unsupported encryption: missing or invalid required entry \"U\"") } break @@ -1034,20 +1034,14 @@ func decryptBytes(b []byte, objNr, genNr int, encKey []byte, needAES bool, r int } // decryptString decrypts s using RC4 or AES. -func decryptString(s string, objNr, genNr int, key []byte, needAES bool, r int) (*string, error) { +func decryptString(s string, objNr, genNr int, key []byte, needAES bool, r int) ([]byte, error) { - b, err := Unescape(s) + bb, err := Unescape(s) if err != nil { return nil, err } - b, err = decryptBytes(b, objNr, genNr, key, needAES, r) - if err != nil { - return nil, err - } - - s1 := string(b) - return &s1, nil + return decryptBytes(bb, objNr, genNr, key, needAES, r) } func applyRC4CipherBytes(b []byte, objNr, genNr int, key []byte, needAES bool) ([]byte, error) { @@ -1145,8 +1139,7 @@ func encryptDeepObject(objIn Object, objNr, genNr int, key []byte, needAES bool, return nil, nil } -// DecryptDeepObject recurses over non trivial PDF objects and decrypts all strings encountered. -func decryptDeepObject(objIn Object, objNr, genNr int, key []byte, needAES bool, r int) (*StringLiteral, error) { +func decryptDeepObject(objIn Object, objNr, genNr int, key []byte, needAES bool, r int) (*HexLiteral, error) { _, ok := objIn.(IndirectRef) if ok { @@ -1178,20 +1171,20 @@ func decryptDeepObject(objIn Object, objNr, genNr int, key []byte, needAES bool, } case StringLiteral: - s, err := decryptString(obj.Value(), objNr, genNr, key, needAES, r) + bb, err := decryptString(obj.Value(), objNr, genNr, key, needAES, r) if err != nil { return nil, err } - sl := StringLiteral(*s) - return &sl, nil + hl := NewHexLiteral(bb) + return &hl, nil case HexLiteral: bb, err := decryptHexLiteral(obj, objNr, genNr, key, needAES, r) if err != nil { return nil, err } - sl := StringLiteral(string(bb)) - return &sl, nil + hl := NewHexLiteral(bb) + return &hl, nil default: diff --git a/pkg/pdfcpu/dict.go b/pkg/pdfcpu/dict.go index ad45688fa..91bda186b 100644 --- a/pkg/pdfcpu/dict.go +++ b/pkg/pdfcpu/dict.go @@ -512,7 +512,11 @@ func (d Dict) StringEntryBytes(key string) ([]byte, error) { s := d.StringLiteralEntry(key) if s != nil { - return Unescape(s.Value()) + bb, err := Unescape(s.Value()) + if err != nil { + return nil, err + } + return bb, nil } h := d.HexLiteralEntry(key) diff --git a/pkg/pdfcpu/read.go b/pkg/pdfcpu/read.go index a94fead2e..23a4e45ba 100644 --- a/pkg/pdfcpu/read.go +++ b/pkg/pdfcpu/read.go @@ -1704,11 +1704,11 @@ func ParseObject(ctx *Context, offset int64, objNr, genNr int) (Object, error) { case StringLiteral: if ctx.EncKey != nil { - s1, err := decryptString(o.Value(), objNr, genNr, ctx.EncKey, ctx.AES4Strings, ctx.E.R) + bb, err := decryptString(o.Value(), objNr, genNr, ctx.EncKey, ctx.AES4Strings, ctx.E.R) if err != nil { return nil, err } - return StringLiteral(*s1), nil + return NewHexLiteral(bb), nil } return o, nil @@ -1718,7 +1718,7 @@ func ParseObject(ctx *Context, offset int64, objNr, genNr int) (Object, error) { if err != nil { return nil, err } - return StringLiteral(string(bb)), nil + return NewHexLiteral(bb), nil } return o, nil @@ -2477,32 +2477,6 @@ func handleUnencryptedFile(ctx *Context) error { return nil } -func idBytes(ctx *Context) (id []byte, err error) { - - if ctx.ID == nil { - return nil, errors.New("pdfcpu: missing ID entry") - } - - hl, ok := ctx.ID[0].(HexLiteral) - if ok { - id, err = hl.Bytes() - if err != nil { - return nil, err - } - } else { - sl, ok := ctx.ID[0].(StringLiteral) - if !ok { - return nil, errors.New("pdfcpu: ID must contain hex literals or string literals") - } - id, err = Unescape(sl.Value()) - if err != nil { - return nil, err - } - } - - return id, nil -} - func needsOwnerAndUserPassword(cmd CommandMode) bool { return cmd == CHANGEOPW || cmd == CHANGEUPW || cmd == SETPERMISSIONS @@ -2535,8 +2509,7 @@ func setupEncryptionKey(ctx *Context, d Dict) (err error) { return err } - ctx.E.ID, err = idBytes(ctx) - if err != nil { + if ctx.E.ID, err = ctx.IDFirstElement(); err != nil { return err } diff --git a/pkg/pdfcpu/utf16.go b/pkg/pdfcpu/utf16.go index 0eb8852b0..e03ebd393 100644 --- a/pkg/pdfcpu/utf16.go +++ b/pkg/pdfcpu/utf16.go @@ -50,7 +50,7 @@ func IsUTF16BE(b []byte) bool { func decodeUTF16String(b []byte) (string, error) { // We only accept big endian byte order. if !IsUTF16BE(b) { - log.Debug.Printf("decodeUTF16String: not UTF16BE: %v\n", b) + log.Debug.Printf("decodeUTF16String: not UTF16BE: %s\n", hex.Dump(b)) return "", ErrInvalidUTF16BE } @@ -119,13 +119,13 @@ func encodeUTF16String(s string) string { } // StringLiteralToString returns the best possible string rep for a string literal. -func StringLiteralToString(s string) (string, error) { - b, err := Unescape(s) +func StringLiteralToString(sl StringLiteral) (string, error) { + bb, err := Unescape(sl.Value()) if err != nil { return "", err } - s1 := string(b) + s1 := string(bb) // Check for Big Endian UTF-16. if IsStringUTF16BE(s1) { @@ -140,9 +140,9 @@ func StringLiteralToString(s string) (string, error) { } // HexLiteralToString returns a possibly UTF16 encoded string for a hex string. -func HexLiteralToString(hexString string) (string, error) { +func HexLiteralToString(hl HexLiteral) (string, error) { // Get corresponding byte slice. - b, err := hex.DecodeString(hexString) + b, err := hex.DecodeString(hl.Value()) if err != nil { return "", err } diff --git a/pkg/pdfcpu/validate/action.go b/pkg/pdfcpu/validate/action.go index c3d303ca7..c91d6a755 100644 --- a/pkg/pdfcpu/validate/action.go +++ b/pkg/pdfcpu/validate/action.go @@ -477,7 +477,7 @@ func validateHideActionDictEntryT(xRefTable *pdf.XRefTable, o pdf.Object) error case pdf.StringLiteral: // Ensure UTF16 correctness. - _, err := pdf.StringLiteralToString(o.Value()) + _, err := pdf.StringLiteralToString(o) if err != nil { return err } @@ -506,7 +506,7 @@ func validateHideActionDictEntryT(xRefTable *pdf.XRefTable, o pdf.Object) error case pdf.StringLiteral: // Ensure UTF16 correctness. - _, err = pdf.StringLiteralToString(o.Value()) + _, err = pdf.StringLiteralToString(o) if err != nil { return err } @@ -664,11 +664,11 @@ func validateJavaScript(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryNam case pdf.StringLiteral: // Ensure UTF16 correctness. - _, err = pdf.StringLiteralToString(o.Value()) + _, err = pdf.StringLiteralToString(o) case pdf.HexLiteral: // Ensure UTF16 correctness. - _, err = pdf.HexLiteralToString(o.Value()) + _, err = pdf.HexLiteralToString(o) case pdf.StreamDict: // no further processing diff --git a/pkg/pdfcpu/validate/objects.go b/pkg/pdfcpu/validate/objects.go index 57e145314..648c270a9 100644 --- a/pkg/pdfcpu/validate/objects.go +++ b/pkg/pdfcpu/validate/objects.go @@ -1015,10 +1015,10 @@ func validateString(xRefTable *pdf.XRefTable, o pdf.Object, validate func(string switch o := o.(type) { case pdf.StringLiteral: - s, err = pdf.StringLiteralToString(o.Value()) + s, err = pdf.StringLiteralToString(o) case pdf.HexLiteral: - s, err = pdf.HexLiteralToString(o.Value()) + s, err = pdf.HexLiteralToString(o) default: err = errors.New("pdfcpu: validateString: invalid type") @@ -1070,10 +1070,10 @@ func validateStringEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryNa switch o := o.(type) { case pdf.StringLiteral: - s, err = pdf.StringLiteralToString(o.Value()) + s, err = pdf.StringLiteralToString(o) case pdf.HexLiteral: - s, err = pdf.HexLiteralToString(o.Value()) + s, err = pdf.HexLiteralToString(o) default: err = errors.Errorf("pdfcpu: validateStringEntry: dict=%s entry=%s invalid type", dictName, entryName) diff --git a/pkg/pdfcpu/write.go b/pkg/pdfcpu/write.go index 18bd860e6..daf41fbff 100644 --- a/pkg/pdfcpu/write.go +++ b/pkg/pdfcpu/write.go @@ -833,13 +833,10 @@ func setupEncryption(ctx *Context) error { return errors.New("pdfcpu: encrypt: missing ID") } - var id []byte - if id, err = ctx.IDFirstElement(); err != nil { + if ctx.E.ID, err = ctx.IDFirstElement(); err != nil { return err } - ctx.E.ID = id - if err = calcOAndU(ctx, d); err != nil { return err } diff --git a/pkg/pdfcpu/writeImage.go b/pkg/pdfcpu/writeImage.go index d049a7c06..2c97f9562 100644 --- a/pkg/pdfcpu/writeImage.go +++ b/pkg/pdfcpu/writeImage.go @@ -116,30 +116,22 @@ func pdfImage(xRefTable *XRefTable, sd *StreamDict, objNr int) (*PDFImage, error // Identify the color lookup table for an Indexed color space. func colorLookupTable(xRefTable *XRefTable, o Object) ([]byte, error) { - var lookup []byte - var err error - o, _ = xRefTable.Dereference(o) switch o := o.(type) { case StringLiteral: - return Unescape(string(o)) + return []byte(o), nil case HexLiteral: - lookup, err = o.Bytes() - if err != nil { - return nil, err - } + return o.Bytes() case StreamDict: - lookup, err = streamBytes(&o) - if err != nil || lookup == nil { - return nil, err - } + return streamBytes(&o) + } - return lookup, nil + return nil, nil } func decodePixelColorValue(p uint8, bpc, c int, decode []colValRange) uint8 { diff --git a/pkg/pdfcpu/xreftable.go b/pkg/pdfcpu/xreftable.go index 9d9f5c23d..e57a6b0da 100644 --- a/pkg/pdfcpu/xreftable.go +++ b/pkg/pdfcpu/xreftable.go @@ -932,7 +932,7 @@ func (xRefTable *XRefTable) DereferenceStringLiteral(o Object, sinceVersion Vers } // Ensure UTF16 correctness. - s1, err := StringLiteralToString(s.Value()) + s1, err := StringLiteralToString(s) if err != nil { return s, err } @@ -962,18 +962,18 @@ func (xRefTable *XRefTable) DereferenceStringOrHexLiteral(obj Object, sinceVersi case StringLiteral: // Ensure UTF16 correctness. - if s, err = StringLiteralToString(str.Value()); err != nil { + if s, err = StringLiteralToString(str); err != nil { return "", err } case HexLiteral: // Ensure UTF16 correctness. - if s, err = HexLiteralToString(str.Value()); err != nil { + if s, err = HexLiteralToString(str); err != nil { return "", err } default: - return "", errors.Errorf("pdfcpu: dereferenceStringOrHexLiteral: wrong type <%v>", obj) + return "", errors.Errorf("pdfcpu: dereferenceStringOrHexLiteral: wrong type %T", obj) } @@ -994,9 +994,9 @@ func (xRefTable *XRefTable) DereferenceStringOrHexLiteral(obj Object, sinceVersi func Text(o Object) (string, error) { switch obj := o.(type) { case StringLiteral: - return StringLiteralToString(obj.Value()) + return StringLiteralToString(obj) case HexLiteral: - return HexLiteralToString(obj.Value()) + return HexLiteralToString(obj) default: return "", errors.Errorf("pdfcpu: text: corrupt - %v\n", obj) } @@ -1640,7 +1640,8 @@ func (xRefTable *XRefTable) IDFirstElement() (id []byte, err error) { return nil, errors.New("pdfcpu: ID must contain hex literals or string literals") } - return Unescape(sl.Value()) + //return Unescape(sl.Value()) + return []byte(sl), nil } // InheritedPageAttrs represents all inherited page attributes.