Skip to content

Commit

Permalink
Fix #664, #666, #667, #669
Browse files Browse the repository at this point in the history
  • Loading branch information
hhrutter committed Aug 7, 2023
1 parent a9afcfe commit be32323
Show file tree
Hide file tree
Showing 28 changed files with 362 additions and 231 deletions.
8 changes: 2 additions & 6 deletions pkg/api/merge.go
Expand Up @@ -55,6 +55,7 @@ func MergeRaw(rsc []io.ReadSeeker, w io.Writer, conf *model.Configuration) error
conf = model.NewDefaultConfiguration()
}
conf.Cmd = model.MERGECREATE
conf.ValidationMode = model.ValidationRelaxed
conf.CreateBookmarks = false

ctxDest, _, _, err := readAndValidate(rsc[0], conf, time.Now())
Expand All @@ -74,12 +75,6 @@ func MergeRaw(rsc []io.ReadSeeker, w io.Writer, conf *model.Configuration) error
return err
}

if conf.ValidationMode != model.ValidationNone {
if err = ValidateContext(ctxDest); err != nil {
return err
}
}

return WriteContext(ctxDest, w)
}

Expand All @@ -93,6 +88,7 @@ func Merge(destFile string, inFiles []string, w io.Writer, conf *model.Configura
conf = model.NewDefaultConfiguration()
}
conf.Cmd = model.MERGECREATE
conf.ValidationMode = model.ValidationRelaxed

if destFile != "" {
conf.Cmd = model.MERGEAPPEND
Expand Down
26 changes: 26 additions & 0 deletions pkg/api/test/bookmark_test.go
Expand Up @@ -28,6 +28,26 @@ import (
// Acrobat Reader "Bookmarks" = Mac Preview "Table of Contents".
// Mac Preview limitations: does not render color, style, outline tree collapsed by default.

func InactiveTestAddDuplicateBookmarks(t *testing.T) {
msg := "TestAddDuplicateBookmarks"
inFile := filepath.Join(inDir, "CenterOfWhy.pdf")
outFile := filepath.Join("..", "..", "samples", "bookmarks", "bookmarkDuplicates.pdf")

bms := []pdfcpu.Bookmark{
{PageFrom: 2, Title: "Duplicate Name"},
{PageFrom: 3, Title: "Duplicate Name"},
{PageFrom: 5, Title: "Duplicate Name"},
}

replace := true // Replace existing bookmarks.
if err := api.AddBookmarksFile(inFile, outFile, bms, replace, nil); err != nil {
t.Fatalf("%s addBookmarks: %v\n", msg, err)
}
if err := api.ValidateFile(outFile, nil); err != nil {
t.Fatalf("%s: %v\n", msg, err)
}
}

func TestAddSimpleBookmarks(t *testing.T) {
msg := "TestAddSimpleBookmarks"
inFile := filepath.Join(inDir, "CenterOfWhy.pdf")
Expand All @@ -52,6 +72,9 @@ func TestAddSimpleBookmarks(t *testing.T) {
if err := api.AddBookmarksFile(inFile, outFile, bms, replace, nil); err != nil {
t.Fatalf("%s addBookmarks: %v\n", msg, err)
}
if err := api.ValidateFile(outFile, nil); err != nil {
t.Fatalf("%s: %v\n", msg, err)
}
}

func TestAddBookmarkTree2Levels(t *testing.T) {
Expand Down Expand Up @@ -79,4 +102,7 @@ func TestAddBookmarkTree2Levels(t *testing.T) {
if err := api.AddBookmarksFile(inFile, outFile, bms, false, nil); err != nil {
t.Fatalf("%s addBookmarks: %v\n", msg, err)
}
if err := api.ValidateFile(outFile, nil); err != nil {
t.Fatalf("%s: %v\n", msg, err)
}
}
26 changes: 22 additions & 4 deletions pkg/api/test/merge_test.go
Expand Up @@ -24,7 +24,6 @@ import (
"testing"

"github.com/pdfcpu/pdfcpu/pkg/api"
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
)

func TestMergeCreateNew(t *testing.T) {
Expand All @@ -39,10 +38,12 @@ func TestMergeCreateNew(t *testing.T) {
// outFile will be overwritten.

// Bookmarks for the merged document will be created/preserved per default (see config.yaml)
conf := model.NewDefaultConfiguration()
//conf.CreateBookmarks = false

if err := api.MergeCreateFile(inFiles, outFile, conf); err != nil {
if err := api.MergeCreateFile(inFiles, outFile, nil); err != nil {
t.Fatalf("%s: %v\n", msg, err)
}

if err := api.ValidateFile(outFile, conf); err != nil {
t.Fatalf("%s: %v\n", msg, err)
}
}
Expand All @@ -60,15 +61,24 @@ func TestMergeAppendNew(t *testing.T) {

// Merge inFiles by concatenation in the order specified and write the result to outFile.
// If outFile already exists its content will be preserved and serves as the beginning of the merge result.

// Bookmarks for the merged document will be created/preserved per default (see config.yaml)

if err := api.MergeAppendFile(inFiles, outFile, nil); err != nil {
t.Fatalf("%s: %v\n", msg, err)
}
if err := api.ValidateFile(outFile, conf); err != nil {
t.Fatalf("%s: %v\n", msg, err)
}

anotherFile := filepath.Join(inDir, "testRot.pdf")
err := api.MergeAppendFile([]string{anotherFile}, outFile, nil)
if err != nil {
t.Fatalf("%s: %v\n", msg, err)
}
if err := api.ValidateFile(outFile, conf); err != nil {
t.Fatalf("%s: %v\n", msg, err)
}
}

func TestMergeToBufNew(t *testing.T) {
Expand All @@ -90,6 +100,10 @@ func TestMergeToBufNew(t *testing.T) {
if err := os.WriteFile(outFile, buf.Bytes(), 0644); err != nil {
t.Fatalf("%s: write: %v\n", msg, err)
}

if err := api.ValidateFile(outFile, conf); err != nil {
t.Fatalf("%s: %v\n", msg, err)
}
}

func TestMergeRaw(t *testing.T) {
Expand Down Expand Up @@ -124,4 +138,8 @@ func TestMergeRaw(t *testing.T) {
if err := os.WriteFile(outFile, buf.Bytes(), 0644); err != nil {
t.Fatalf("%s: write: %v\n", msg, err)
}

if err := api.ValidateFile(outFile, conf); err != nil {
t.Fatalf("%s: %v\n", msg, err)
}
}
11 changes: 7 additions & 4 deletions pkg/pdfcpu/bookmark.go
Expand Up @@ -232,19 +232,23 @@ func bmDict(ctx *model.Context, bm Bookmark, parent types.IndirectRef) (types.Di
}

var o types.Object = *ir
ctx.Names["Dests"].Add(ctx.XRefTable, bm.Title, o)

s, err := types.EscapeUTF16String(bm.Title)
if err != nil {
return nil, err
}

d := types.Dict(map[string]types.Object{
"Dest": types.StringLiteral(bm.Title),
"Dest": types.NewHexLiteral([]byte(bm.Title)),
"Title": types.StringLiteral(*s),
"Parent": parent},
)

m := model.NameMap{bm.Title: []types.Dict{d}}
if err := ctx.Names["Dests"].Add(ctx.XRefTable, bm.Title, o, m, []string{"D", "Dest"}); err != nil {
return nil, err
}

if bm.Color != nil {
d["C"] = types.Array{types.Float(bm.Color.R), types.Float(bm.Color.G), types.Float(bm.Color.B)}
}
Expand Down Expand Up @@ -291,7 +295,7 @@ func createOutlineItemDict(ctx *model.Context, bms []Bookmark, parent *types.Ind
first = ir
}

if bm.Children != nil {
if len(bm.Children) > 0 {

first, last, c, visc, err := createOutlineItemDict(ctx, bm.Children, ir, &bm.PageFrom)
if err != nil {
Expand Down Expand Up @@ -339,7 +343,6 @@ func AddBookmarks(ctx *model.Context, bms []Bookmark, replace bool) error {
return err
}

// TODO Merge with existing outlines.
if !replace {
if _, ok := rootDict.Find("Outlines"); ok {
return errExistingBookmarks
Expand Down
16 changes: 14 additions & 2 deletions pkg/pdfcpu/createAnnotations.go
Expand Up @@ -536,7 +536,13 @@ func createFileAttachmentAnnotation(xRefTable *model.XRefTable, pageIndRef types
}

fn := filepath.Base(fileName)
fileSpecDict, err := xRefTable.NewFileSpecDict(fn, types.EncodeUTF16String(fn), "attached by pdfcpu", *ir)

s, err := types.EscapeUTF16String(fn)
if err != nil {
return nil, err
}

fileSpecDict, err := xRefTable.NewFileSpecDict(fn, *s, "attached by pdfcpu", *ir)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -576,7 +582,13 @@ func createFileSpecDict(xRefTable *model.XRefTable, fileName string) (types.Dict
return nil, err
}
fn := filepath.Base(fileName)
return xRefTable.NewFileSpecDict(fn, types.EncodeUTF16String(fn), "attached by pdfcpu", *ir)

s, err := types.EscapeUTF16String(fn)
if err != nil {
return nil, err
}

return xRefTable.NewFileSpecDict(fn, *s, "attached by pdfcpu", *ir)
}

func createSoundObject(xRefTable *model.XRefTable) (*types.IndirectRef, error) {
Expand Down
12 changes: 6 additions & 6 deletions pkg/pdfcpu/createRenditions.go
Expand Up @@ -31,7 +31,7 @@ func createMHBEDict() *types.Dict {
"U": types.StringLiteral("vnd.adobe.swname:ADBE_Acrobat"),
"L": types.NewIntegerArray(0),
"H": types.NewIntegerArray(),
"OS": types.NewStringArray(),
"OS": types.NewStringLiteralArray(),
},
)

Expand Down Expand Up @@ -59,7 +59,7 @@ func createMHBEDict() *types.Dict {
},
),
"P": types.NewNameArray("1.3"),
"L": types.NewStringArray("en-US"),
"L": types.NewStringLiteralArray("en-US"),
},
)

Expand All @@ -77,7 +77,7 @@ func createMediaPlayersDict() *types.Dict {
"U": types.StringLiteral("vnd.adobe.swname:ADBE_Acrobat"),
"L": types.NewIntegerArray(0),
"H": types.NewIntegerArray(),
"OS": types.NewStringArray(),
"OS": types.NewStringLiteralArray(),
},
)

Expand Down Expand Up @@ -163,7 +163,7 @@ func createMediaClipDataDict(xRefTable *model.XRefTable) (*types.IndirectRef, er
//"CT": StringLiteral("audio/mp4"),
//"CT": StringLiteral("video/mp4"),
"P": mediaPermissionsDict,
"Alt": types.NewStringArray("en-US", "My vacation", "de", "Mein Urlaub", "", "My vacation"),
"Alt": types.NewStringLiteralArray("en-US", "My vacation", "de", "Mein Urlaub", "", "My vacation"),
"PL": *mediaPlayersDict,
"MH": mhbe,
"BE": mhbe,
Expand Down Expand Up @@ -234,7 +234,7 @@ func createFloatingWindowsParamsDict() *types.Dict {
"T": types.Boolean(true),
"UC": types.Boolean(true),
"R": types.Integer(0),
"TT": types.NewStringArray("en-US", "Special title", "de", "Spezieller Titel", "default title"),
"TT": types.NewStringLiteralArray("en-US", "Special title", "de", "Spezieller Titel", "default title"),
},
)

Expand Down Expand Up @@ -299,7 +299,7 @@ func createSectionMediaRendition(mediaClipDataDict *types.IndirectRef) *types.Di
"S": types.Name("MCS"), // media clip section
"N": types.StringLiteral("Sample movie"),
"D": *mediaClipDataDict,
"Alt": types.NewStringArray("en-US", "My vacation", "de", "Mein Urlaub", "", "default vacation"),
"Alt": types.NewStringLiteralArray("en-US", "My vacation", "de", "Mein Urlaub", "", "default vacation"),
"MH": *mhbe,
"BE": *mhbe,
},
Expand Down
4 changes: 2 additions & 2 deletions pkg/pdfcpu/createTestPDF.go
Expand Up @@ -1724,7 +1724,7 @@ func createResetButton(xRefTable *model.XRefTable, pageAnnots *types.Array) (*ty
map[string]types.Object{
"Type": types.Name("Action"),
"S": types.Name("ResetForm"),
"Fields": types.NewStringArray("inputField"),
"Fields": types.NewStringLiteralArray("inputField"),
"Flags": types.Integer(0),
},
)
Expand Down Expand Up @@ -1774,7 +1774,7 @@ func createSubmitButton(xRefTable *model.XRefTable, pageAnnots *types.Array) (*t
"Type": types.Name("Action"),
"S": types.Name("SubmitForm"),
"F": urlSpec,
"Fields": types.NewStringArray("inputField"),
"Fields": types.NewStringLiteralArray("inputField"),
"Flags": types.Integer(0),
},
)
Expand Down
18 changes: 15 additions & 3 deletions pkg/pdfcpu/form/form.go
Expand Up @@ -127,7 +127,11 @@ func fullyQualifiedFieldName(xRefTable *model.XRefTable, indRef types.IndirectRe

thisID := indRef.ObjectNumber.String()
thisName := ""
if s := d.StringOrHexLiteralEntry("T"); s != nil {
s, err := d.StringOrHexLiteralEntry("T")
if err != nil {
return false, err
}
if s != nil {
thisName = *s
}

Expand Down Expand Up @@ -933,7 +937,11 @@ func annotIndRefSameLevel(xRefTable *model.XRefTable, fields types.Array, fieldI
if indRef.ObjectNumber.String() == fieldIDOrName {
return &indRef, nil
}
if id := d.StringOrHexLiteralEntry("T"); id != nil && *id == fieldIDOrName {
id, err := d.StringOrHexLiteralEntry("T")
if err != nil {
return nil, err
}
if id != nil && *id == fieldIDOrName {
return &indRef, nil
}
}
Expand Down Expand Up @@ -968,7 +976,11 @@ func annotIndRefForField(xRefTable *model.XRefTable, fields types.Array, fieldID
if indRef.ObjectNumber.String() == partialName {
return annotIndRefForField(xRefTable, kids, fieldIDOrName[len(partialName)+1:])
}
if id := d.StringOrHexLiteralEntry("T"); id != nil {
id, err := d.StringOrHexLiteralEntry("T")
if err != nil {
return nil, err
}
if id != nil {
if *id == partialName {
return annotIndRefForField(xRefTable, kids, fieldIDOrName[len(partialName)+1:])
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/pdfcpu/merge.go
Expand Up @@ -435,8 +435,8 @@ func mergeNames(ctxSrc, ctxDest *model.Context) error {

for id, namesSrc := range ctxSrc.Names {
if namesDest, ok := ctxDest.Names[id]; ok {
// Merge src tree into dest tree
if err := namesDest.AddTree(ctxDest.XRefTable, namesSrc); err != nil {
// Merge src tree into dest tree including collision detection.
if err := namesDest.AddTree(ctxDest.XRefTable, namesSrc, ctxSrc.NameRefs[id], []string{"D", "Dest"}); err != nil {
return err
}
continue
Expand Down

0 comments on commit be32323

Please sign in to comment.