// =========================================================================== //  ©2013-2026 WebSupergoo. All rights reserved. // //  This source code is for use exclusively with the ABCpdf product with //  which it is distributed, under the terms of the license for that //  product. Details can be found at // //    http://www.websupergoo.com/ // //  This copyright notice must not be deleted and must be reproduced alongside //  any sections of code extracted from this module. // =========================================================================== using System; using System.Collections.Generic; using System.Text; using WebSupergoo.ABCpdf14; using WebSupergoo.ABCpdf14.Objects; using WebSupergoo.ABCpdf14.Atoms; namespace ReferenceXObject {   public sealed class ObjectCopy {     public const int XObjectLocalEntryCount = 3;  // Metadata, OPI, OC     private Doc _doc;     private List<string> _xobjLocalEntryList;     public ObjectCopy(Doc doc) {       _doc = doc;       _xobjLocalEntryList = new List<string>();     }     public List<string> XObjectLocalEntryList {       get { return _xobjLocalEntryList; }     }     public static string GetXObjectLocalEntryPath(int index) {       // These are the entries in PixMap that are also valid in Form XObject       // They are not copied over       switch(index) {       case 0: return "/Metadata";       case 1: return "/OPI";       case 2: return "/OC";       }       throw new ArgumentOutOfRangeException("index");     }     private static IndirectObject NewStreamObject(Doc doc, DictAtom dict, int id) {       // Some IndirectObject derived classes assert the existence of data       dict["Length"] = new NumAtom(1);       string dictStr = dict.ToString();       IndirectObject obj = IndirectObject.FromString(dictStr + "stream\n0\nendstream\n");       if(id==0)         id = doc.ObjectSoup.Count;       doc.ObjectSoup[id] = obj;       return doc.ObjectSoup[id];     }     private static Atom CopyAtom(IndirectObject obj, Doc destDoc, bool allowStreams) {       if(!allowStreams && obj is StreamObject)         return null;       return CopyAtom(obj, obj.Atom, destDoc, allowStreams);     }     private static Atom CopyAtom(IndirectObject obj, Atom atom, Doc destDoc, bool allowStreams) {       if(atom is RefAtom) {         IndirectObject obj2 = obj.ResolveObj(atom);         StreamObject streamObj = obj2 as StreamObject;         if(streamObj==null) {           Atom atom2 = obj2==null? null: CopyAtom(obj2, destDoc, allowStreams);           if(atom2==null)             return null;           obj2 = IndirectObject.FromString(atom2.ToString());           int id = destDoc.ObjectSoup.Count;           destDoc.ObjectSoup[id] = obj2;           obj2 = destDoc.ObjectSoup[id];           return new RefAtom(obj2);         }         if(!allowStreams)           return null;         DictAtom dict = CopyAtom(streamObj, destDoc, allowStreams) as DictAtom;         if(dict==null)           return null;         byte[] data = streamObj.GetData();         streamObj = (StreamObject)NewStreamObject(destDoc, dict, 0);         streamObj.SetData(data);         return new RefAtom(streamObj);       }       if(atom is DictAtom) {         DictAtom dict = new DictAtom();         foreach(KeyValuePair<string, Atom> pair in (DictAtom)atom) {           Atom atom2 = CopyAtom(obj, pair.Value, destDoc, allowStreams);           if(atom2==null)             return null;           dict[pair.Key] = atom2;         }         return dict;       }       if(atom is ArrayAtom) {         ArrayAtom arr = new ArrayAtom();         foreach(Atom v in (ArrayAtom)atom) {           Atom atom2 = CopyAtom(obj, v, destDoc, allowStreams);           if(atom2==null)             return null;           arr.Add(atom2);         }         return arr;       }       return atom.Clone();     }     public PixMap CopyPixMap(PixMap pixmap, Doc destDoc, int id) {       _xobjLocalEntryList.Clear();       return CopyPixMap(pixmap, destDoc, id, 0);     }     private PixMap CopyPixMap(PixMap pixmap, Doc destDoc, int id, int iLocal) {       DictAtom dict = new DictAtom();       foreach(KeyValuePair<string, Atom> pair in (DictAtom)pixmap.Atom) {         switch(pair.Key) {         case "Metadata":           SetListItem(_xobjLocalEntryList, iLocal, pair.Value.ToString());           break;         case "OPI":           SetListItem(_xobjLocalEntryList, iLocal+1, pair.Value.ToString());           break;         case "OC":           SetListItem(_xobjLocalEntryList, iLocal+2, pair.Value.ToString());           break;         case "Mask":         case "SMask":           if(pair.Value is RefAtom) {             PixMap mask = pixmap.ResolveObj(pair.Value) as PixMap;             if(mask==null)               goto default;             PixMap destMask = CopyPixMap(mask,               destDoc, 0, iLocal+XObjectLocalEntryCount);             dict[pair.Key] = new RefAtom(destMask);             break;           }           goto default;         default: {             // Allow stream objects only for ColorSpace             Atom atom = CopyAtom(pixmap, pair.Value,               destDoc, pair.Key=="ColorSpace");             if(atom!=null)               dict[pair.Key] = atom;           }           break;         }       }       PixMap outPixMap = (PixMap)NewStreamObject(destDoc, dict, id);       byte[] data = pixmap.GetData();       outPixMap.SetData(data);       return outPixMap;     }     private static void SetListItem(List<string> list, int index, string value) {       if(list.Count>=index+1)         list[index] = value;       else {         while(list.Count<index)           list.Add(null);         list.Add(value);       }     }   } }