Merge pull request #67 from digitorus/revert-66-revert-65-fix-catalog-entries-discarded
fix: Existing catalog entries are being discarded; this ensures that all catalog entries are copied to the new updated catalog.
This commit is contained in:
@@ -2,7 +2,11 @@ package sign
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/digitorus/pdf"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (context *SignContext) createCatalog() ([]byte, error) {
|
func (context *SignContext) createCatalog() ([]byte, error) {
|
||||||
@@ -28,32 +32,18 @@ func (context *SignContext) createCatalog() ([]byte, error) {
|
|||||||
// catalog_buffer.WriteString(" /Version /2.0")
|
// catalog_buffer.WriteString(" /Version /2.0")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Retrieve the root and check for necessary keys in one loop
|
// Retrieve the root, its pointer and set the root string
|
||||||
root := context.PDFReader.Trailer().Key("Root")
|
root := context.PDFReader.Trailer().Key("Root")
|
||||||
rootPtr := root.GetPtr()
|
rootPtr := root.GetPtr()
|
||||||
context.CatalogData.RootString = strconv.Itoa(int(rootPtr.GetID())) + " " + strconv.Itoa(int(rootPtr.GetGen())) + " R"
|
context.CatalogData.RootString = strconv.Itoa(int(rootPtr.GetID())) + " " + strconv.Itoa(int(rootPtr.GetGen())) + " R"
|
||||||
|
|
||||||
foundPages, foundNames := false, false
|
// Copy over existing catalog entries except for type and AcroForum
|
||||||
for _, key := range root.Keys() {
|
for _, key := range root.Keys() {
|
||||||
switch key {
|
if key != "Type" && key != "AcroForm" {
|
||||||
case "Pages":
|
_, _ = fmt.Fprintf(&catalog_buffer, " /%s ", key)
|
||||||
foundPages = true
|
context.serializeCatalogEntry(&catalog_buffer, rootPtr.GetID(), root.Key(key))
|
||||||
case "Names":
|
catalog_buffer.WriteString("\n")
|
||||||
foundNames = true
|
|
||||||
}
|
}
|
||||||
if foundPages && foundNames {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Pages and Names references if they exist
|
|
||||||
if foundPages {
|
|
||||||
pages := root.Key("Pages").GetPtr()
|
|
||||||
catalog_buffer.WriteString(" /Pages " + strconv.Itoa(int(pages.GetID())) + " " + strconv.Itoa(int(pages.GetGen())) + " R\n")
|
|
||||||
}
|
|
||||||
if foundNames {
|
|
||||||
names := root.Key("Names").GetPtr()
|
|
||||||
catalog_buffer.WriteString(" /Names " + strconv.Itoa(int(names.GetID())) + " " + strconv.Itoa(int(names.GetGen())) + " R\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the AcroForm dictionary with /NeedAppearances
|
// Start the AcroForm dictionary with /NeedAppearances
|
||||||
@@ -123,3 +113,53 @@ func (context *SignContext) createCatalog() ([]byte, error) {
|
|||||||
|
|
||||||
return catalog_buffer.Bytes(), nil
|
return catalog_buffer.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// serializeCatalogEntry takes a pdf.Value and serializes it to the given writer.
|
||||||
|
func (context *SignContext) serializeCatalogEntry(w io.Writer, rootObjId uint32, value pdf.Value) {
|
||||||
|
if ptr := value.GetPtr(); ptr.GetID() != rootObjId {
|
||||||
|
// Indirect object
|
||||||
|
_, _ = fmt.Fprintf(w, "%d %d R", ptr.GetID(), ptr.GetGen())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct object
|
||||||
|
switch value.Kind() {
|
||||||
|
case pdf.String:
|
||||||
|
_, _ = fmt.Fprintf(w, "(%s)", value.RawString())
|
||||||
|
case pdf.Null:
|
||||||
|
_, _ = fmt.Fprint(w, "null")
|
||||||
|
case pdf.Bool:
|
||||||
|
if value.Bool() {
|
||||||
|
_, _ = fmt.Fprint(w, "true")
|
||||||
|
} else {
|
||||||
|
_, _ = fmt.Fprint(w, "false")
|
||||||
|
}
|
||||||
|
case pdf.Integer:
|
||||||
|
_, _ = fmt.Fprintf(w, "%d", value.Int64())
|
||||||
|
case pdf.Real:
|
||||||
|
_, _ = fmt.Fprintf(w, "%f", value.Float64())
|
||||||
|
case pdf.Name:
|
||||||
|
_, _ = fmt.Fprintf(w, "/%s", value.Name())
|
||||||
|
case pdf.Dict:
|
||||||
|
_, _ = fmt.Fprint(w, "<<")
|
||||||
|
for idx, key := range value.Keys() {
|
||||||
|
if idx > 0 {
|
||||||
|
_, _ = fmt.Fprint(w, " ") // Space between items
|
||||||
|
}
|
||||||
|
_, _ = fmt.Fprintf(w, "/%s ", key)
|
||||||
|
context.serializeCatalogEntry(w, rootObjId, value.Key(key))
|
||||||
|
}
|
||||||
|
_, _ = fmt.Fprint(w, ">>")
|
||||||
|
case pdf.Array:
|
||||||
|
_, _ = fmt.Fprint(w, "[")
|
||||||
|
for idx := range value.Len() {
|
||||||
|
if idx > 0 {
|
||||||
|
_, _ = fmt.Fprint(w, " ") // Space between items
|
||||||
|
}
|
||||||
|
context.serializeCatalogEntry(w, rootObjId, value.Index(idx))
|
||||||
|
}
|
||||||
|
_, _ = fmt.Fprint(w, "]")
|
||||||
|
case pdf.Stream:
|
||||||
|
panic("stream cannot be a direct object")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -15,17 +15,17 @@ var testFiles = []struct {
|
|||||||
{
|
{
|
||||||
file: "../testfiles/testfile20.pdf",
|
file: "../testfiles/testfile20.pdf",
|
||||||
expectedCatalogs: map[CertType]string{
|
expectedCatalogs: map[CertType]string{
|
||||||
CertificationSignature: "<<\n /Type /Catalog\n /Pages 3 0 R\n /AcroForm <<\n /Fields [10 0 R]\n /SigFlags 3\n >>\n>>\n",
|
CertificationSignature: "<<\n /Type /Catalog\n /Metadata 2 0 R\n /Pages 3 0 R\n /AcroForm <<\n /Fields [10 0 R]\n /SigFlags 3\n >>\n>>\n",
|
||||||
UsageRightsSignature: "<<\n /Type /Catalog\n /Pages 3 0 R\n /AcroForm <<\n /Fields [10 0 R]\n /SigFlags 1\n >>\n>>\n",
|
UsageRightsSignature: "<<\n /Type /Catalog\n /Metadata 2 0 R\n /Pages 3 0 R\n /AcroForm <<\n /Fields [10 0 R]\n /SigFlags 1\n >>\n>>\n",
|
||||||
ApprovalSignature: "<<\n /Type /Catalog\n /Pages 3 0 R\n /AcroForm <<\n /Fields [10 0 R]\n /SigFlags 3\n >>\n>>\n",
|
ApprovalSignature: "<<\n /Type /Catalog\n /Metadata 2 0 R\n /Pages 3 0 R\n /AcroForm <<\n /Fields [10 0 R]\n /SigFlags 3\n >>\n>>\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
file: "../testfiles/testfile21.pdf",
|
file: "../testfiles/testfile21.pdf",
|
||||||
expectedCatalogs: map[CertType]string{
|
expectedCatalogs: map[CertType]string{
|
||||||
CertificationSignature: "<<\n /Type /Catalog\n /Pages 9 0 R\n /Names 6 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 3\n >>\n>>\n",
|
CertificationSignature: "<<\n /Type /Catalog\n /Metadata 8 0 R\n /Names 6 0 R\n /Pages 9 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 3\n >>\n>>\n",
|
||||||
UsageRightsSignature: "<<\n /Type /Catalog\n /Pages 9 0 R\n /Names 6 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 1\n >>\n>>\n",
|
UsageRightsSignature: "<<\n /Type /Catalog\n /Metadata 8 0 R\n /Names 6 0 R\n /Pages 9 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 1\n >>\n>>\n",
|
||||||
ApprovalSignature: "<<\n /Type /Catalog\n /Pages 9 0 R\n /Names 6 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 3\n >>\n>>\n",
|
ApprovalSignature: "<<\n /Type /Catalog\n /Metadata 8 0 R\n /Names 6 0 R\n /Pages 9 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 3\n >>\n>>\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user