Skip to content

Commit

Permalink
name tree fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
hhrutter committed Nov 27, 2018
1 parent f2d6820 commit 515e9db
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 66 deletions.
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -99,7 +99,6 @@ Required build version: go1.9 and up

## Contributing

* By participating in any form or contributing to `pdfcpu` you are are expected to uphold our [Code of Conduct](CODE_OF_CONDUCT.md).
* Please open an issue if you find a bug or want to propose a change.
* Feature requests - always welcome.
* Bug fixes - always welcome.
Expand All @@ -114,6 +113,9 @@ Thanks goes to these wonderful people:
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
<!-- ALL-CONTRIBUTORS-LIST:END - Do not remove or modify this section -->

## Code of Conduct

Please note that this project is released with a Contributor [Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.

## Disclaimer

Expand Down
2 changes: 1 addition & 1 deletion lzw/README.md
Expand Up @@ -2,7 +2,7 @@

* This is a consolidated version of `compress/lzw` that supports GIF, TIFF and PDF.
* Please refer to this [golang proposal](https://github.com/golang/go/issues/25409) for details.
* `pdfcpu` also hosts an improved version of Go's TIFF package at [github.com/hhrutter/pdfcpu/tiff](https://github.com/hhrutter/pdfcpu/tiff) leveraging the improved `compress/lzw`.
* `pdfcpu` also hosts an improved version of Go's TIFF package at [github.com/hhrutter/pdfcpu/tiff](https://github.com/hhrutter/pdfcpu/tree/master/tiff) leveraging the improved `compress/lzw`.

## Background

Expand Down
5 changes: 5 additions & 0 deletions pkg/api/process_test.go
Expand Up @@ -343,6 +343,11 @@ func TestOptimizeCommandWithLF(t *testing.T) {
t.Fatalf("TestOptimizeCommandWithLF: %v\n", err)
}

_, err = Process(ValidateCommand(outFile, config))
if err != nil {
t.Fatalf("TestOptimizeCommandWithLF validation: %v\n", err)
}

}
}

Expand Down
14 changes: 6 additions & 8 deletions pkg/pdfcpu/attach.go
Expand Up @@ -253,7 +253,7 @@ func AttachList(xRefTable *XRefTable) (list []string, err error) {

log.Debug.Println("List begin")

if !xRefTable.Valid && xRefTable.Names["EmbeddedFiles"] == nil {
if !xRefTable.Valid {
err = xRefTable.LocateNameTree("EmbeddedFiles", false)
if err != nil {
return nil, err
Expand All @@ -280,7 +280,7 @@ func AttachExtract(ctx *Context, files StringSet) (err error) {

log.Debug.Println("Extract begin")

if !ctx.Valid && ctx.Names["EmbeddedFiles"] == nil {
if !ctx.Valid {
err = ctx.LocateNameTree("EmbeddedFiles", false)
if err != nil {
return err
Expand Down Expand Up @@ -308,11 +308,9 @@ func AttachAdd(xRefTable *XRefTable, files StringSet) (ok bool, err error) {

log.Debug.Println("Add begin")

if xRefTable.Names["EmbeddedFiles"] == nil {
err := xRefTable.LocateNameTree("EmbeddedFiles", true)
if err != nil {
return false, err
}
err = xRefTable.LocateNameTree("EmbeddedFiles", true)
if err != nil {
return false, err
}

ok, err = addAttachedFiles(xRefTable, files)
Expand All @@ -328,7 +326,7 @@ func AttachRemove(xRefTable *XRefTable, files StringSet) (ok bool, err error) {

log.Debug.Println("Remove begin")

if !xRefTable.Valid && xRefTable.Names["EmbeddedFiles"] == nil {
if !xRefTable.Valid {
err = xRefTable.LocateNameTree("EmbeddedFiles", false)
if err != nil {
return false, err
Expand Down
18 changes: 11 additions & 7 deletions pkg/pdfcpu/nameTree.go
Expand Up @@ -32,10 +32,10 @@ const maxEntries = 3
// Once maxEntries has been reached a leaf node turns into an intermediary node with two kids,
// which are leaf nodes each of them holding half of the sorted entries of the original leaf node.
type Node struct {
Kids []*Node // Mirror of the name tree's Kids array.
Names []entry // Mirror of the name tree's Names array.
Kmin, Kmax string // Mirror of the name tree's Limit array[Kmin,Kmax].
IndRef *IndirectRef // Pointer to the PDF object representing this name tree node.
Kids []*Node // Mirror of the name tree's Kids array, an array of indirect references.
Names []entry // Mirror of the name tree's Names array.
Kmin, Kmax string // Mirror of the name tree's Limit array[Kmin,Kmax].
D *Dict // Pointer to the PDF dict representing this name tree node.
}

// entry is a key value pair.
Expand Down Expand Up @@ -111,6 +111,11 @@ func (n *Node) AddToLeaf(k string, v Object) {
// Add adds an entry to a name tree.
func (n *Node) Add(xRefTable *XRefTable, k string, v Object) error {

// The values associated with the keys may be objects of any type.
// Stream objects shall be specified by indirect object references.
// Dictionary, array, and string objects should be specified by indirect object references.
// Other PDF objects (nulls, numbers, booleans, and names) should be specified as direct objects.

if n.Names == nil {
n.Names = make([]entry, 0, maxEntries)
}
Expand Down Expand Up @@ -324,7 +329,7 @@ func (n *Node) removeFromKids(xRefTable *XRefTable, k string) (ok bool, err erro
// This kid is now empty and needs to be removed.

if xRefTable != nil {
err := xRefTable.DeleteObjectGraph(*n.Kids[i].IndRef)
err = xRefTable.deleteObject(*kid.D)
if err != nil {
return false, err
}
Expand All @@ -351,7 +356,7 @@ func (n *Node) removeFromKids(xRefTable *XRefTable, k string) (ok bool, err erro
log.Debug.Println("removeFromKids: only 1 kid")

if xRefTable != nil {
err = xRefTable.DeleteObject(n.IndRef.ObjectNumber.Value())
err = xRefTable.deleteObject(*n.D)
if err != nil {
return false, err
}
Expand All @@ -360,7 +365,6 @@ func (n *Node) removeFromKids(xRefTable *XRefTable, k string) (ok bool, err erro
*n = *n.Kids[0]

log.Debug.Printf("removeFromKids: new n = %s\n", n)
log.Debug.Printf("removeFromKids: n.IndRef = %v\n", n.IndRef)

return true, nil
}
Expand Down
23 changes: 15 additions & 8 deletions pkg/pdfcpu/validate/nameTree.go
Expand Up @@ -548,6 +548,12 @@ func validateIDTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pd

func validateNameTreeValue(name string, xRefTable *pdf.XRefTable, o pdf.Object) (err error) {

// TODO
// The values associated with the keys may be objects of any type.
// Stream objects shall be specified by indirect object references.
// Dictionary, array, and string objects should be specified by indirect object references.
// Other PDF objects (nulls, numbers, booleans, and names) should be specified as direct objects.

for k, v := range map[string]struct {
validate func(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error
sinceVersion pdf.Version
Expand Down Expand Up @@ -673,19 +679,15 @@ func validateNameTreeDictLimitsEntry(xRefTable *pdf.XRefTable, d pdf.Dict, first
return nil
}

func validateNameTree(xRefTable *pdf.XRefTable, name string, ir pdf.IndirectRef, root bool) (string, string, *pdf.Node, error) {
func validateNameTree(xRefTable *pdf.XRefTable, name string, d pdf.Dict, root bool) (string, string, *pdf.Node, error) {

// see 7.7.4

// A node has "Kids" or "Names" entry.

node := &pdf.Node{IndRef: &ir}
node := &pdf.Node{D: &d}
var kmin, kmax string

d, err := xRefTable.DereferenceDict(ir)
if err != nil || d == nil {
return "", "", nil, err
}
var err error

// Kids: array of indirect references to the immediate children of this node.
// if Kids present then recurse
Expand All @@ -709,9 +711,14 @@ func validateNameTree(xRefTable *pdf.XRefTable, name string, ir pdf.IndirectRef,
return "", "", nil, errors.New("validateNameTree: corrupt kid, should be indirect reference")
}

d, err := xRefTable.DereferenceDict(kid)
if err != nil {
return "", "", nil, err
}

var kminKid string
var kidNode *pdf.Node
kminKid, kmax, kidNode, err = validateNameTree(xRefTable, name, kid, false)
kminKid, kmax, kidNode, err = validateNameTree(xRefTable, name, d, false)
if err != nil {
return "", "", nil, err
}
Expand Down
6 changes: 5 additions & 1 deletion pkg/pdfcpu/validate/structTree.go
Expand Up @@ -626,7 +626,11 @@ func validateStructTreeRootDict(xRefTable *pdf.XRefTable, d pdf.Dict) error {
// A name tree that maps element identifiers to the structure elements they denote.
ir := d.IndirectRefEntry("IDTree")
if ir != nil {
_, _, _, err := validateNameTree(xRefTable, "IDTree", *ir, true)
d, err := xRefTable.DereferenceDict(*ir)
if err != nil {
return err
}
_, _, _, err = validateNameTree(xRefTable, "IDTree", d, true)
if err != nil {
return err
}
Expand Down
20 changes: 7 additions & 13 deletions pkg/pdfcpu/validate/xReftable.go
Expand Up @@ -104,15 +104,6 @@ func validateNames(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, s

// => 7.7.4 Name Dictionary

/*
<Kids, [(86 0 R)]>
86:
<Limits, [(F1) (P.9)]>
<Names, [(F1) (87 0 R) (F2) ...
*/

d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Names", required, sinceVersion, nil)
if err != nil || d == nil {
return err
Expand All @@ -129,16 +120,19 @@ func validateNames(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, s
return errors.Errorf("validateNames: unknown name tree name: %s\n", treeName)
}

ir, ok := value.(pdf.IndirectRef)
if !ok {
return errors.New("validateNames: name tree must be indirect ref")
d, err := xRefTable.DereferenceDict(value)
if err != nil {
return err
}

_, _, tree, err := validateNameTree(xRefTable, treeName, ir, true)
_, _, tree, err := validateNameTree(xRefTable, treeName, d, true)
if err != nil {
return err
}

// Internalize this name tree.
// If no validation takes place, name trees have to be internalized via xRefTable.LocateNameTree
// TODO Move this out of validation into Read.
if tree != nil {
xRefTable.Names[treeName] = tree
}
Expand Down
50 changes: 24 additions & 26 deletions pkg/pdfcpu/xreftable.go
Expand Up @@ -1167,14 +1167,9 @@ func (xRefTable *XRefTable) bindNameTreeNode(name string, n *Node, root bool) er

var dict Dict

if n.IndRef == nil {
d := NewDict()
indRef, err := xRefTable.IndRefForNewObject(d)
if err != nil {
return err
}
n.IndRef = indRef
dict = d
if n.D == nil {
dict = NewDict()
n.D = &dict
} else {
if root {
// Update root object after possible tree modification after removal of empty kid.
Expand All @@ -1185,17 +1180,10 @@ func (xRefTable *XRefTable) bindNameTreeNode(name string, n *Node, root bool) er
if namesDict == nil {
return errors.New("Root entry \"Names\" corrupt")
}
namesDict.Update(name, *n.IndRef)
}
log.Debug.Printf("bind IndRef = %v\n", n.IndRef)
d, err := xRefTable.DereferenceDict(*n.IndRef)
if err != nil {
return err
}
if d == nil {
return errors.Errorf("name tree node dict is nil for node: %v\n", n)
namesDict.Update(name, *n.D)
}
dict = d
log.Debug.Printf("bind dict = %v\n", *n.D)
dict = *n.D
}

if !root {
Expand All @@ -1221,7 +1209,11 @@ func (xRefTable *XRefTable) bindNameTreeNode(name string, n *Node, root bool) er
if err != nil {
return err
}
kids = append(kids, *k.IndRef)
indRef, err := xRefTable.IndRefForNewObject(*k.D)
if err != nil {
return err
}
kids = append(kids, *indRef)
}

dict.Update("Kids", kids)
Expand All @@ -1237,6 +1229,7 @@ func (xRefTable *XRefTable) BindNameTrees() error {

log.Write.Println("BindNameTrees..")

// Iterate over internal name tree rep.
for k, v := range xRefTable.Names {
log.Write.Printf("bindNameTree: %s\n", k)
err := xRefTable.bindNameTreeNode(k, v, true)
Expand All @@ -1251,6 +1244,10 @@ func (xRefTable *XRefTable) BindNameTrees() error {
// LocateNameTree locates/ensures a specific name tree.
func (xRefTable *XRefTable) LocateNameTree(nameTreeName string, ensure bool) error {

if xRefTable.Names[nameTreeName] != nil {
return nil
}

d, err := xRefTable.Catalog()
if err != nil {
return err
Expand Down Expand Up @@ -1292,17 +1289,17 @@ func (xRefTable *XRefTable) LocateNameTree(nameTreeName string, ensure bool) err

d.Insert(nameTreeName, *ir)

xRefTable.Names[nameTreeName] = &Node{IndRef: ir}
xRefTable.Names[nameTreeName] = &Node{D: &dict}

return nil
}

ir, ok := o.(IndirectRef)
if !ok {
return errors.New("LocateNameTree: name tree must be indirect ref")
d1, err := xRefTable.DereferenceDict(o)
if err != nil {
return err
}

xRefTable.Names[nameTreeName] = &Node{IndRef: &ir}
xRefTable.Names[nameTreeName] = &Node{D: &d1}

return nil
}
Expand Down Expand Up @@ -1339,8 +1336,9 @@ func (xRefTable *XRefTable) RemoveNameTree(nameTreeName string) error {
// We have an existing name dict.

// Delete the name tree.
if ir := namesDict.IndirectRefEntry(nameTreeName); ir != nil {
err = xRefTable.DeleteObjectGraph(*ir)
o, found := namesDict.Find(nameTreeName)
if found {
err = xRefTable.deleteObject(o)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion tiff/README.md
@@ -1,6 +1,6 @@
# Note

This package is an improved version of golang.org/x/image/tiff. It uses a consolidated version of `compress/lzw` (hosted at: [github.com/hhrutter/pdfcpu/lzw](https://github.com/hhrutter/pdfcpu/lzw)) for compression and also adds support for CMYK.
This package is an improved version of golang.org/x/image/tiff. It uses a consolidated version of `compress/lzw` (hosted at: [github.com/hhrutter/pdfcpu/lzw](https://github.com/hhrutter/pdfcpu/tree/master/lzw)) for compression and also adds support for CMYK.

## Background

Expand Down

0 comments on commit 515e9db

Please sign in to comment.