github.com/pdfcpu/pdfcpu@v0.11.1/pkg/pdfcpu/merge.go (about)

     1  /*
     2  Copyright 2018 The pdfcpu Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package pdfcpu
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/pdfcpu/pdfcpu/pkg/log"
    23  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
    24  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
    25  	"github.com/pkg/errors"
    26  )
    27  
    28  func EnsureOutlines(ctx *model.Context, fName string, append bool) error {
    29  
    30  	rootDict, err := ctx.Catalog()
    31  	if err != nil {
    32  		return err
    33  	}
    34  
    35  	if err := ctx.LocateNameTree("Dests", true); err != nil {
    36  		return err
    37  	}
    38  
    39  	outlinesDict := types.Dict(map[string]types.Object{"Type": types.Name("Outlines")})
    40  	indRef, err := ctx.IndRefForNewObject(outlinesDict)
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	first, last, total, visible, err := createOutlineItemDict(ctx, []Bookmark{{PageFrom: 1, Title: fName}}, indRef, nil)
    46  	if err != nil {
    47  		return err
    48  	}
    49  
    50  	outlinesDict["First"] = *first
    51  	outlinesDict["Last"] = *last
    52  	outlinesDict["Count"] = types.Integer(total + visible)
    53  
    54  	if obj, ok := rootDict.Find("Outlines"); ok {
    55  		if append {
    56  			return nil
    57  		}
    58  		d, err := ctx.DereferenceDict(obj)
    59  		if err != nil {
    60  			return err
    61  		}
    62  		count := d.IntEntry("Count")
    63  		c := 0
    64  		f, l := d.IndirectRefEntry("First"), d.IndirectRefEntry("Last")
    65  		for ir := f; ir != nil; ir = d.IndirectRefEntry("Next") {
    66  			d, err = ctx.DereferenceDict(*ir)
    67  			if err != nil {
    68  				return err
    69  			}
    70  			d["Parent"] = *first
    71  			c++
    72  		}
    73  		d, err = ctx.DereferenceDict(*first)
    74  		if err != nil {
    75  			return err
    76  		}
    77  
    78  		d["First"] = *f
    79  		d["Last"] = *l
    80  		if count != nil && *count != 0 {
    81  			c = *count
    82  		}
    83  		d["Count"] = types.Integer(-c)
    84  	}
    85  
    86  	rootDict["Outlines"] = *indRef
    87  
    88  	return nil
    89  }
    90  
    91  func mergeOutlines(fName string, p int, ctxSrc, ctxDest *model.Context) error {
    92  	rootDictDest, _ := ctxDest.Catalog()
    93  	indRef := rootDictDest.IndirectRefEntry("Outlines")
    94  	outlinesDict, err := ctxDest.DereferenceDict(*indRef)
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	first, last, _, _, err := createOutlineItemDict(ctxDest, []Bookmark{{PageFrom: p, Title: fName}}, indRef, nil)
   100  	if err != nil {
   101  		return err
   102  	}
   103  
   104  	l := outlinesDict.IndirectRefEntry("Last")
   105  	outlinesDict["Last"] = *last
   106  
   107  	topCount := 0
   108  
   109  	count := outlinesDict.IntEntry("Count")
   110  	if count != nil {
   111  		topCount = *count
   112  	}
   113  
   114  	topCount++
   115  
   116  	d1, err := ctxDest.DereferenceDict(*l)
   117  	if err != nil {
   118  		return err
   119  	}
   120  	d1["Next"] = *last
   121  
   122  	d2, err := ctxDest.DereferenceDict(*last)
   123  	if err != nil {
   124  		return err
   125  	}
   126  	d2["Previous"] = *l
   127  
   128  	rootDictSource, err := ctxSrc.Catalog()
   129  	if err != nil {
   130  		return err
   131  	}
   132  
   133  	if obj, ok := rootDictSource.Find("Outlines"); ok {
   134  
   135  		// Integrate existing outlines from ctxSource.
   136  
   137  		d, err := ctxDest.DereferenceDict(obj)
   138  		if err != nil {
   139  			return err
   140  		}
   141  
   142  		f, l := d.IndirectRefEntry("First"), d.IndirectRefEntry("Last")
   143  		if f == nil && l == nil {
   144  			outlinesDict["Count"] = types.Integer(topCount)
   145  			return nil
   146  		}
   147  
   148  		d2["First"] = *f
   149  		d2["Last"] = *l
   150  
   151  		c := 0
   152  
   153  		// Update parents.
   154  		// TODO Collapse outline dicts.
   155  		for ir := f; ir != nil; ir = d.IndirectRefEntry("Next") {
   156  			d, err = ctxDest.DereferenceDict(*ir)
   157  			if err != nil {
   158  				return err
   159  			}
   160  			d["Parent"] = *first
   161  
   162  			i := d.IntEntry("Count")
   163  			if i != nil && *i > 0 {
   164  				c += *i
   165  			}
   166  
   167  			c++
   168  		}
   169  
   170  		d2["Count"] = types.Integer(c)
   171  		topCount += c
   172  	}
   173  
   174  	outlinesDict["Count"] = types.Integer(topCount)
   175  	return nil
   176  }
   177  
   178  func handleNeedAppearances(ctxSrc *model.Context, dSrc, dDest types.Dict) error {
   179  	o, found := dSrc.Find("NeedAppearances")
   180  	if !found || o == nil {
   181  		return nil
   182  	}
   183  	b, err := ctxSrc.DereferenceBoolean(o, model.V10)
   184  	if err != nil {
   185  		return err
   186  	}
   187  	if b != nil && *b {
   188  		dDest["NeedAppearances"] = types.Boolean(true)
   189  	}
   190  	return nil
   191  }
   192  
   193  func handleCO(ctxSrc, ctxDest *model.Context, dSrc, dDest types.Dict) error {
   194  	o, found := dSrc.Find("CO")
   195  	if !found {
   196  		return nil
   197  	}
   198  	arrSrc, err := ctxSrc.DereferenceArray(o)
   199  	if err != nil {
   200  		return err
   201  	}
   202  	o, found = dDest.Find("CO")
   203  	if !found {
   204  		dDest["CO"] = arrSrc
   205  		return nil
   206  	}
   207  	arrDest, err := ctxDest.DereferenceArray(o)
   208  	if err != nil {
   209  		return err
   210  	}
   211  	if len(arrDest) == 0 {
   212  		dDest["CO"] = arrSrc
   213  	} else {
   214  		arrDest = append(arrDest, arrSrc...)
   215  		dDest["CO"] = arrDest
   216  	}
   217  	return nil
   218  }
   219  
   220  func handleDR(ctxSrc *model.Context, dSrc, dDest types.Dict) error {
   221  	o, found := dSrc.Find("DR")
   222  	if !found {
   223  		return nil
   224  	}
   225  	dSrc, err := ctxSrc.DereferenceDict(o)
   226  	if err != nil {
   227  		return err
   228  	}
   229  	if len(dSrc) == 0 {
   230  		return nil
   231  	}
   232  	_, found = dDest.Find("DR")
   233  	if !found {
   234  		dDest["DR"] = dSrc
   235  	}
   236  	return nil
   237  }
   238  
   239  func handleDA(ctxSrc *model.Context, dSrc, dDest types.Dict, arrFieldsSrc types.Array) error {
   240  	// (for each with field type  /FT /Tx w/o DA, set DA to default DA)
   241  	// TODO Walk field tree and inspect terminal fields.
   242  
   243  	sSrc := dSrc.StringEntry("DA")
   244  	if sSrc == nil || len(*sSrc) == 0 {
   245  		return nil
   246  	}
   247  	sDest := dDest.StringEntry("DA")
   248  	if sDest == nil {
   249  		dDest["DA"] = types.StringLiteral(*sSrc)
   250  		return nil
   251  	}
   252  	// Push sSrc down to all top level fields of dSource
   253  	for _, o := range arrFieldsSrc {
   254  		d, err := ctxSrc.DereferenceDict(o)
   255  		if err != nil {
   256  			return err
   257  		}
   258  		n := d.NameEntry("FT")
   259  		if n != nil && *n == "Tx" {
   260  			_, found := d.Find("DA")
   261  			if !found {
   262  				d["DA"] = types.StringLiteral(*sSrc)
   263  			}
   264  		}
   265  	}
   266  	return nil
   267  }
   268  
   269  func handleQ(ctxSrc *model.Context, dSrc, dDest types.Dict, arrFieldsSrc types.Array) error {
   270  	// (for each with field type /FT /Tx w/o Q, set Q to default Q)
   271  	// TODO Walk field tree and inspect terminal fields.
   272  
   273  	iSrc := dSrc.IntEntry("Q")
   274  	if iSrc == nil {
   275  		return nil
   276  	}
   277  	iDest := dDest.IntEntry("Q")
   278  	if iDest == nil {
   279  		dDest["Q"] = types.Integer(*iSrc)
   280  		return nil
   281  	}
   282  	// Push iSrc down to all top level fields of dSource
   283  	for _, o := range arrFieldsSrc {
   284  		d, err := ctxSrc.DereferenceDict(o)
   285  		if err != nil {
   286  			return err
   287  		}
   288  		n := d.NameEntry("FT")
   289  		if n != nil && *n == "Tx" {
   290  			_, found := d.Find("Q")
   291  			if !found {
   292  				d["Q"] = types.Integer(*iSrc)
   293  			}
   294  		}
   295  	}
   296  	return nil
   297  }
   298  
   299  func handleFormAttributes(ctxSrc, ctxDest *model.Context, dSrc, dDest types.Dict, arrFieldsSrc types.Array) error {
   300  	// NeedAppearances: try: set to true only
   301  	if err := handleNeedAppearances(ctxSrc, dSrc, dDest); err != nil {
   302  		return err
   303  	}
   304  
   305  	// SigFlags: set bit 1 to true only (SignaturesExist)
   306  	//           set bit 2 to true only (AppendOnly)
   307  	dDest.Delete("SigFields")
   308  
   309  	// CO: add all indrefs
   310  	if err := handleCO(ctxSrc, ctxDest, dSrc, dDest); err != nil {
   311  		return err
   312  	}
   313  
   314  	// DR: default resource dict
   315  	if err := handleDR(ctxSrc, dSrc, dDest); err != nil {
   316  		return err
   317  	}
   318  
   319  	// DA: default appearance streams for variable text fields
   320  	if err := handleDA(ctxSrc, dSrc, dDest, arrFieldsSrc); err != nil {
   321  		return err
   322  	}
   323  
   324  	// Q: left, center, right for variable text fields
   325  	if err := handleQ(ctxSrc, dSrc, dDest, arrFieldsSrc); err != nil {
   326  		return err
   327  	}
   328  
   329  	// XFA: ignore
   330  	delete(dDest, "XFA")
   331  
   332  	return nil
   333  }
   334  
   335  func rootDicts(ctxSrc, ctxDest *model.Context) (types.Dict, types.Dict, error) {
   336  	rootDictSource, err := ctxSrc.Catalog()
   337  	if err != nil {
   338  		return nil, nil, err
   339  	}
   340  
   341  	rootDictDest, err := ctxDest.Catalog()
   342  	if err != nil {
   343  		return nil, nil, err
   344  	}
   345  
   346  	return rootDictSource, rootDictDest, nil
   347  }
   348  
   349  func mergeInFields(ctxDest *model.Context, arrFieldsSrc, arrFieldsDest types.Array, dDest types.Dict) error {
   350  	parentDict :=
   351  		types.Dict(map[string]types.Object{
   352  			"Kids": arrFieldsSrc,
   353  			"T":    types.StringLiteral(fmt.Sprintf("%d", len(arrFieldsDest))),
   354  		})
   355  
   356  	ir, err := ctxDest.IndRefForNewObject(parentDict)
   357  	if err != nil {
   358  		return err
   359  	}
   360  
   361  	for _, ir1 := range arrFieldsSrc {
   362  		d, err := ctxDest.DereferenceDict(ir1)
   363  		if err != nil {
   364  			return err
   365  		}
   366  		if len(d) == 0 {
   367  			continue
   368  		}
   369  		d["Parent"] = *ir
   370  	}
   371  
   372  	dDest["Fields"] = append(arrFieldsDest, *ir)
   373  
   374  	return nil
   375  }
   376  
   377  func mergeDests(ctxSource, ctxDest *model.Context) error {
   378  	rootDictSource, rootDictDest, err := rootDicts(ctxSource, ctxDest)
   379  	if err != nil {
   380  		return err
   381  	}
   382  
   383  	o1, found := rootDictSource.Find("Dests")
   384  	if !found {
   385  		return nil
   386  	}
   387  
   388  	o2, found := rootDictDest.Find("Dests")
   389  	if !found {
   390  		rootDictDest["Dests"] = o1
   391  		return nil
   392  	}
   393  
   394  	destsSrc, err := ctxSource.DereferenceDict(o1)
   395  	if err != nil {
   396  		return err
   397  	}
   398  
   399  	destsDest, err := ctxDest.DereferenceDict(o2)
   400  	if err != nil {
   401  		return err
   402  	}
   403  
   404  	// Note: We ignore duplicate keys
   405  	for k, v := range destsSrc {
   406  		destsDest[k] = v
   407  	}
   408  
   409  	return nil
   410  }
   411  
   412  func mergeNames(ctxSrc, ctxDest *model.Context) error {
   413  
   414  	rootDictSrc, rootDictDest, err := rootDicts(ctxSrc, ctxDest)
   415  	if err != nil {
   416  		return err
   417  	}
   418  
   419  	_, found := rootDictSrc.Find("Names")
   420  	if !found {
   421  		// Nothing to merge in.
   422  		return nil
   423  	}
   424  
   425  	if _, found := rootDictDest.Find("Names"); !found {
   426  		ctxDest.Names = ctxSrc.Names
   427  		return nil
   428  	}
   429  
   430  	// We need to merge src Names into dest Names.
   431  
   432  	for id, namesSrc := range ctxSrc.Names {
   433  		if namesDest, ok := ctxDest.Names[id]; ok {
   434  			// Merge src tree into dest tree including collision detection.
   435  			if err := namesDest.AddTree(ctxDest.XRefTable, namesSrc, ctxSrc.NameRefs[id], []string{"D", "Dest"}); err != nil {
   436  				return err
   437  			}
   438  			continue
   439  		}
   440  
   441  		// Name tree missing in dest ctx => copy over names from src ctx
   442  		ctxDest.Names[id] = namesSrc
   443  	}
   444  
   445  	return nil
   446  }
   447  
   448  func mergeForms(ctxSrc, ctxDest *model.Context) error {
   449  
   450  	rootDictSource, rootDictDest, err := rootDicts(ctxSrc, ctxDest)
   451  	if err != nil {
   452  		return err
   453  	}
   454  
   455  	o, found := rootDictSource.Find("AcroForm")
   456  	if !found {
   457  		return nil
   458  	}
   459  
   460  	dSrc, err := ctxSrc.DereferenceDict(o)
   461  	if err != nil || len(dSrc) == 0 {
   462  		return err
   463  	}
   464  
   465  	// Retrieve ctxSrc Form Fields
   466  	o, found = dSrc.Find("Fields")
   467  	if !found {
   468  		return nil
   469  	}
   470  	arrFieldsSrc, err := ctxSrc.DereferenceArray(o)
   471  	if err != nil {
   472  		return err
   473  	}
   474  	if len(arrFieldsSrc) == 0 {
   475  		return nil
   476  	}
   477  
   478  	// We have a ctxSrc.Form with fields.
   479  
   480  	o, found = rootDictDest.Find("AcroForm")
   481  	if !found {
   482  		rootDictDest["AcroForm"] = dSrc
   483  		return nil
   484  	}
   485  
   486  	dDest, err := ctxDest.DereferenceDict(o)
   487  	if err != nil {
   488  		return err
   489  	}
   490  
   491  	if len(dDest) == 0 {
   492  		rootDictDest["AcroForm"] = dSrc
   493  		return nil
   494  	}
   495  
   496  	// Retrieve ctxDest AcroForm Fields
   497  	o, found = dDest.Find("Fields")
   498  	if !found {
   499  		rootDictDest["AcroForm"] = dSrc
   500  		return nil
   501  	}
   502  	arrFieldsDest, err := ctxDest.DereferenceArray(o)
   503  	if err != nil {
   504  		return err
   505  	}
   506  	if len(arrFieldsDest) == 0 {
   507  		rootDictDest["AcroForm"] = dSrc
   508  		return nil
   509  	}
   510  
   511  	if err := mergeInFields(ctxDest, arrFieldsSrc, arrFieldsDest, dDest); err != nil {
   512  		return err
   513  	}
   514  
   515  	return handleFormAttributes(ctxSrc, ctxDest, dSrc, dDest, arrFieldsSrc)
   516  }
   517  
   518  func patchIndRef(ir *types.IndirectRef, lookup map[int]int) {
   519  	i := ir.ObjectNumber.Value()
   520  	ir.ObjectNumber = types.Integer(lookup[i])
   521  }
   522  
   523  func patchObject(o types.Object, lookup map[int]int) types.Object {
   524  	if log.TraceEnabled() {
   525  		log.Trace.Printf("patchObject before: %v\n", o)
   526  	}
   527  
   528  	var ob types.Object
   529  
   530  	switch obj := o.(type) {
   531  
   532  	case types.IndirectRef:
   533  		patchIndRef(&obj, lookup)
   534  		ob = obj
   535  
   536  	case types.Dict:
   537  		patchDict(obj, lookup)
   538  		ob = obj
   539  
   540  	case types.StreamDict:
   541  		patchDict(obj.Dict, lookup)
   542  		ob = obj
   543  
   544  	case types.ObjectStreamDict:
   545  		patchDict(obj.Dict, lookup)
   546  		ob = obj
   547  
   548  	case types.XRefStreamDict:
   549  		patchDict(obj.Dict, lookup)
   550  		ob = obj
   551  
   552  	case types.Array:
   553  		patchArray(&obj, lookup)
   554  		ob = obj
   555  
   556  	}
   557  
   558  	if log.TraceEnabled() {
   559  		log.Trace.Printf("patchObject end: %v\n", ob)
   560  	}
   561  
   562  	return ob
   563  }
   564  
   565  func patchDict(d types.Dict, lookup map[int]int) {
   566  	if log.TraceEnabled() {
   567  		log.Trace.Printf("patchDict before: %v\n", d)
   568  	}
   569  
   570  	for k, obj := range d {
   571  		o := patchObject(obj, lookup)
   572  		if o != nil {
   573  			d[k] = o
   574  		}
   575  	}
   576  
   577  	if log.TraceEnabled() {
   578  		log.Trace.Printf("patchDict after: %v\n", d)
   579  	}
   580  }
   581  
   582  func patchArray(a *types.Array, lookup map[int]int) {
   583  	if log.TraceEnabled() {
   584  		log.Trace.Printf("patchArray begin: %v\n", *a)
   585  	}
   586  
   587  	for i, obj := range *a {
   588  		o := patchObject(obj, lookup)
   589  		if o != nil {
   590  			(*a)[i] = o
   591  		}
   592  	}
   593  
   594  	if log.TraceEnabled() {
   595  		log.Trace.Printf("patchArray end: %v\n", a)
   596  	}
   597  }
   598  
   599  func objNrsIntSet(ctx *model.Context) types.IntSet {
   600  	objNrs := types.IntSet{}
   601  
   602  	for k := range ctx.Table {
   603  		if k == 0 {
   604  			// obj#0 is always the head of the freelist.
   605  			continue
   606  		}
   607  		objNrs[k] = true
   608  	}
   609  
   610  	return objNrs
   611  }
   612  
   613  func lookupTable(keys types.IntSet, i int) map[int]int {
   614  	m := map[int]int{}
   615  
   616  	for k := range keys {
   617  		m[k] = i
   618  		i++
   619  	}
   620  
   621  	return m
   622  }
   623  
   624  // Patch an IntSet of objNrs using lookup.
   625  func patchObjects(s types.IntSet, lookup map[int]int) types.IntSet {
   626  	t := types.IntSet{}
   627  
   628  	for k, v := range s {
   629  		if v {
   630  			t[lookup[k]] = v
   631  		}
   632  	}
   633  
   634  	return t
   635  }
   636  
   637  func patchNameTree(n *model.Node, lookup map[int]int) error {
   638  
   639  	patchValues := func(xRefTable *model.XRefTable, k string, v *types.Object) error {
   640  		*v = patchObject(*v, lookup)
   641  		return nil
   642  	}
   643  
   644  	return n.Process(nil, patchValues)
   645  }
   646  
   647  func patchSourceObjectNumbers(ctxSrc, ctxDest *model.Context) {
   648  	if log.DebugEnabled() {
   649  		log.Debug.Printf("patchSourceObjectNumbers:  ctxSrc: xRefTableSize:%d trailer.Size:%d - %s\n", len(ctxSrc.Table), *ctxSrc.Size, ctxSrc.Read.FileName)
   650  		log.Debug.Printf("patchSourceObjectNumbers: ctxDest: xRefTableSize:%d trailer.Size:%d - %s\n", len(ctxDest.Table), *ctxDest.Size, ctxDest.Read.FileName)
   651  	}
   652  
   653  	// Patch source xref tables obj numbers which are essentially the keys.
   654  	//logInfoMerge.Printf("Source XRefTable before:\n%s\n", ctxSource)
   655  
   656  	objNrs := objNrsIntSet(ctxSrc)
   657  
   658  	// Create lookup table for object numbers.
   659  	// The first number is the successor of the last number in ctxDest.
   660  	lookup := lookupTable(objNrs, *ctxDest.Size)
   661  
   662  	// Patch pointer to root object
   663  	patchIndRef(ctxSrc.Root, lookup)
   664  
   665  	// Patch pointer to info object
   666  	if ctxSrc.Info != nil {
   667  		patchIndRef(ctxSrc.Info, lookup)
   668  	}
   669  
   670  	// Patch free object zero
   671  	entry := ctxSrc.Table[0]
   672  	off := int(*entry.Offset)
   673  	if off != 0 {
   674  		i := int64(lookup[off])
   675  		entry.Offset = &i
   676  	}
   677  
   678  	// Patch all indRefs for xref table entries.
   679  	for k := range objNrs {
   680  
   681  		//logDebugMerge.Printf("patching obj #%d\n", k)
   682  
   683  		entry := ctxSrc.Table[k]
   684  
   685  		if entry.Free {
   686  			if log.DebugEnabled() {
   687  				log.Debug.Printf("patch free entry: old offset:%d\n", *entry.Offset)
   688  			}
   689  			off := int(*entry.Offset)
   690  			if off == 0 {
   691  				continue
   692  			}
   693  			i := int64(lookup[off])
   694  			entry.Offset = &i
   695  			if log.DebugEnabled() {
   696  				log.Debug.Printf("patch free entry: new offset:%d\n", *entry.Offset)
   697  			}
   698  			continue
   699  		}
   700  
   701  		patchObject(entry.Object, lookup)
   702  	}
   703  
   704  	// Patch xref entry object numbers.
   705  	m := make(map[int]*model.XRefTableEntry, *ctxSrc.Size)
   706  	for k, v := range lookup {
   707  		m[v] = ctxSrc.Table[k]
   708  	}
   709  	m[0] = ctxSrc.Table[0]
   710  	ctxSrc.Table = m
   711  
   712  	// Patch DuplicateInfo object numbers.
   713  	ctxSrc.Optimize.DuplicateInfoObjects = patchObjects(ctxSrc.Optimize.DuplicateInfoObjects, lookup)
   714  
   715  	// Patch Linearization object numbers.
   716  	ctxSrc.LinearizationObjs = patchObjects(ctxSrc.LinearizationObjs, lookup)
   717  
   718  	// Patch XRefStream objects numbers.
   719  	ctxSrc.Read.XRefStreams = patchObjects(ctxSrc.Read.XRefStreams, lookup)
   720  
   721  	// Patch object stream object numbers.
   722  	ctxSrc.Read.ObjectStreams = patchObjects(ctxSrc.Read.ObjectStreams, lookup)
   723  
   724  	// Patch cached name trees.
   725  	for _, v := range ctxSrc.Names {
   726  		patchNameTree(v, lookup)
   727  	}
   728  
   729  	if log.DebugEnabled() {
   730  		log.Debug.Printf("patchSourceObjectNumbers end")
   731  	}
   732  }
   733  
   734  func createDividerPagesDict(ctx *model.Context, parentIndRef types.IndirectRef) (*types.IndirectRef, error) {
   735  	d := types.Dict(
   736  		map[string]types.Object{
   737  			"Type":   types.Name("Pages"),
   738  			"Parent": parentIndRef,
   739  			"Count":  types.Integer(1),
   740  		},
   741  	)
   742  
   743  	indRef, err := ctx.IndRefForNewObject(d)
   744  	if err != nil {
   745  		return nil, err
   746  	}
   747  
   748  	dims, err := ctx.XRefTable.PageDims()
   749  	if err != nil {
   750  		return nil, err
   751  	}
   752  
   753  	last := len(dims) - 1
   754  	mediaBox := types.NewRectangle(0, 0, dims[last].Width, dims[last].Height)
   755  
   756  	indRefPageDict, err := ctx.EmptyPage(indRef, mediaBox, 0)
   757  	if err != nil {
   758  		return nil, err
   759  	}
   760  	ctx.SetValid(*indRefPageDict)
   761  
   762  	d.Insert("Kids", types.Array{*indRefPageDict})
   763  
   764  	return indRef, nil
   765  }
   766  
   767  func appendSourcePageTreeToDestPageTree(ctxSrc, ctxDest *model.Context, dividerPage bool) error {
   768  	if log.DebugEnabled() {
   769  		log.Debug.Println("appendSourcePageTreeToDestPageTree begin")
   770  	}
   771  
   772  	indRefPageTreeRootDictDest, err := ctxDest.Pages()
   773  	if err != nil {
   774  		return err
   775  	}
   776  
   777  	pageTreeRootDictDest, err := ctxDest.XRefTable.DereferenceDict(*indRefPageTreeRootDictDest)
   778  	if err != nil {
   779  		return err
   780  	}
   781  
   782  	pageCountDest := pageTreeRootDictDest.IntEntry("Count")
   783  	if pageCountDest == nil || *pageCountDest != ctxDest.PageCount {
   784  		return errors.Errorf("pdfcpu: corrupt page node at obj #%d\n", indRefPageTreeRootDictDest.ObjectNumber)
   785  	}
   786  
   787  	c := ctxDest.PageCount
   788  
   789  	d := types.NewDict()
   790  	d.InsertName("Type", "Pages")
   791  	kids := types.Array{*indRefPageTreeRootDictDest}
   792  
   793  	indRef, err := ctxDest.IndRefForNewObject(d)
   794  	if err != nil {
   795  		return err
   796  	}
   797  
   798  	if dividerPage {
   799  		dividerPagesNodeIndRef, err := createDividerPagesDict(ctxDest, *indRef)
   800  		if err != nil {
   801  			return err
   802  		}
   803  		kids = append(kids, *dividerPagesNodeIndRef)
   804  		c++
   805  	}
   806  
   807  	pageTreeRootDictDest["Parent"] = *indRef
   808  
   809  	indRefPageTreeRootDictSource, err := ctxSrc.Pages()
   810  	if err != nil {
   811  		return err
   812  	}
   813  
   814  	d.Insert("Kids", append(kids, *indRefPageTreeRootDictSource))
   815  
   816  	pageTreeRootDictSource, err := ctxSrc.XRefTable.DereferenceDict(*indRefPageTreeRootDictSource)
   817  	if err != nil {
   818  		return err
   819  	}
   820  
   821  	pageTreeRootDictSource["Parent"] = *indRef
   822  
   823  	pageCountSource := pageTreeRootDictSource.IntEntry("Count")
   824  	if pageCountSource == nil || *pageCountSource != ctxSrc.PageCount {
   825  		return errors.Errorf("pdfcpu: corrupt page node at obj #%d\n", indRefPageTreeRootDictSource.ObjectNumber)
   826  	}
   827  
   828  	c += ctxSrc.PageCount
   829  	d.InsertInt("Count", c)
   830  	ctxDest.PageCount = c
   831  
   832  	rootDict, err := ctxDest.Catalog()
   833  	if err != nil {
   834  		return err
   835  	}
   836  
   837  	rootDict["Pages"] = *indRef
   838  
   839  	if log.DebugEnabled() {
   840  		log.Debug.Println("appendSourcePageTreeToDestPageTree end")
   841  	}
   842  
   843  	return nil
   844  }
   845  
   846  func zipSourcePageTreeIntoDestPageTree(ctxSrc, ctxDest *model.Context) error {
   847  	if log.DebugEnabled() {
   848  		log.Debug.Println("zipSourcePageTreeIntoDestPageTree begin")
   849  	}
   850  
   851  	appendFromPageNr := 0
   852  	if ctxSrc.PageCount > ctxDest.PageCount {
   853  		appendFromPageNr = ctxDest.PageCount + 1
   854  	}
   855  
   856  	rootPageIndRef, err := ctxDest.Pages()
   857  	if err != nil {
   858  		return err
   859  	}
   860  
   861  	// Process dest page tree recursively and weave in src pages
   862  	p := 0
   863  	if ctxDest.PageCount, err = ctxDest.InsertPages(rootPageIndRef, &p, ctxSrc); err != nil {
   864  		return err
   865  	}
   866  
   867  	if appendFromPageNr > 0 {
   868  		// append remaining src pages
   869  		if ctxDest.PageCount, err = ctxDest.AppendPages(rootPageIndRef, appendFromPageNr, ctxSrc); err != nil {
   870  			return err
   871  		}
   872  	}
   873  
   874  	if log.DebugEnabled() {
   875  		log.Debug.Println("zipSourcePageTreeIntoDestPageTree end")
   876  	}
   877  
   878  	return nil
   879  }
   880  
   881  func appendSourceObjectsToDest(ctxSrc, ctxDest *model.Context) {
   882  	if log.DebugEnabled() {
   883  		log.Debug.Println("appendSourceObjectsToDest begin")
   884  	}
   885  
   886  	for objNr, entry := range ctxSrc.Table {
   887  
   888  		// Do not copy free list head.
   889  		if objNr == 0 {
   890  			continue
   891  		}
   892  
   893  		if log.DebugEnabled() {
   894  			log.Debug.Printf("adding obj %d from src to dest\n", objNr)
   895  		}
   896  
   897  		ctxDest.Table[objNr] = entry
   898  
   899  		*ctxDest.Size++
   900  
   901  	}
   902  
   903  	if log.DebugEnabled() {
   904  		log.Debug.Println("appendSourceObjectsToDest end")
   905  	}
   906  }
   907  
   908  // merge two disjunct IntSets
   909  func mergeIntSets(src, dest types.IntSet) {
   910  	for k := range src {
   911  		dest[k] = true
   912  	}
   913  }
   914  
   915  func mergeDuplicateObjNumberIntSets(ctxSrc, ctxDest *model.Context) {
   916  	if log.DebugEnabled() {
   917  		log.Debug.Println("mergeDuplicateObjNumberIntSets begin")
   918  	}
   919  
   920  	mergeIntSets(ctxSrc.Optimize.DuplicateInfoObjects, ctxDest.Optimize.DuplicateInfoObjects)
   921  	mergeIntSets(ctxSrc.LinearizationObjs, ctxDest.LinearizationObjs)
   922  	mergeIntSets(ctxSrc.Read.XRefStreams, ctxDest.Read.XRefStreams)
   923  	mergeIntSets(ctxSrc.Read.ObjectStreams, ctxDest.Read.ObjectStreams)
   924  
   925  	if log.DebugEnabled() {
   926  		log.Debug.Println("mergeDuplicateObjNumberIntSets end")
   927  	}
   928  }
   929  
   930  // MergeXRefTables merges Context ctxSrc into ctxDest by appending its page tree.
   931  // zip         ... zip 2 files together (eg. 1A,1B,2A,2B,3A,3B...)
   932  // dividerPage ... insert blank page between merged files (not applicable for zipping)
   933  func MergeXRefTables(fName string, ctxSrc, ctxDest *model.Context, zip, dividerPage bool) (err error) {
   934  
   935  	patchSourceObjectNumbers(ctxSrc, ctxDest)
   936  
   937  	appendSourceObjectsToDest(ctxSrc, ctxDest)
   938  
   939  	origDestPageCount := ctxDest.PageCount
   940  	if dividerPage {
   941  		origDestPageCount++
   942  	}
   943  
   944  	if zip {
   945  		err = zipSourcePageTreeIntoDestPageTree(ctxSrc, ctxDest)
   946  	} else {
   947  		err = appendSourcePageTreeToDestPageTree(ctxSrc, ctxDest, dividerPage)
   948  	}
   949  
   950  	if err != nil {
   951  		return nil
   952  	}
   953  
   954  	if err = mergeForms(ctxSrc, ctxDest); err != nil {
   955  		return err
   956  	}
   957  
   958  	if err = mergeDests(ctxSrc, ctxDest); err != nil {
   959  		return err
   960  	}
   961  
   962  	if err = mergeNames(ctxSrc, ctxDest); err != nil {
   963  		return err
   964  	}
   965  
   966  	if !zip && ctxDest.Configuration.CreateBookmarks {
   967  		if err = mergeOutlines(fName, origDestPageCount+1, ctxSrc, ctxDest); err != nil {
   968  			return err
   969  		}
   970  	}
   971  
   972  	// Mark src's root object as free.
   973  	if err = ctxDest.FreeObject(int(ctxSrc.Root.ObjectNumber)); err != nil {
   974  		return
   975  	}
   976  
   977  	// Mark source's info object as free.
   978  	// Note: Any indRefs this info object depends on are missed.
   979  	if ctxSrc.Info != nil {
   980  		if err = ctxDest.FreeObject(int(ctxSrc.Info.ObjectNumber)); err != nil {
   981  			return
   982  		}
   983  	}
   984  
   985  	// Merge all IntSets containing redundant object numbers.
   986  	mergeDuplicateObjNumberIntSets(ctxSrc, ctxDest)
   987  
   988  	if log.InfoEnabled() {
   989  		log.Info.Printf("Dest XRefTable after merge:\n%s\n", ctxDest)
   990  	}
   991  
   992  	return nil
   993  }