git-svn-id: https://pdfsharp.svn.codeplex.com/svn@39620 56d0cb2f-6006-4f69-a5a2-94740...
[pdfsharp:pdfsharp.git] / PDFsharp / code / PdfSharp / PdfSharp.Pdf.Advanced / PdfReference.cs
1 #region PDFsharp - A .NET library for processing PDF\r
2 //\r
3 // Authors:\r
4 //   Stefan Lange (mailto:Stefan.Lange@pdfsharp.com)\r
5 //\r
6 // Copyright (c) 2005-2009 empira Software GmbH, Cologne (Germany)\r
7 //\r
8 // http://www.pdfsharp.com\r
9 // http://sourceforge.net/projects/pdfsharp\r
10 //\r
11 // Permission is hereby granted, free of charge, to any person obtaining a\r
12 // copy of this software and associated documentation files (the "Software"),\r
13 // to deal in the Software without restriction, including without limitation\r
14 // the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
15 // and/or sell copies of the Software, and to permit persons to whom the\r
16 // Software is furnished to do so, subject to the following conditions:\r
17 //\r
18 // The above copyright notice and this permission notice shall be included\r
19 // in all copies or substantial portions of the Software.\r
20 //\r
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
24 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
26 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \r
27 // DEALINGS IN THE SOFTWARE.\r
28 #endregion\r
29 \r
30 // With this define each iref object gets a unique number (uid) to make them distinguishable in the debugger\r
31 #define UNIQUE_IREF\r
32 \r
33 using System;\r
34 using System.Collections.Generic;\r
35 using System.Diagnostics;\r
36 using System.Collections;\r
37 using System.Text;\r
38 using System.IO;\r
39 using PdfSharp.Internal;\r
40 using PdfSharp.Pdf.IO;\r
41 \r
42 namespace PdfSharp.Pdf.Advanced\r
43 {\r
44   /// <summary>\r
45   /// Represents an indirect reference to a PdfObject.\r
46   /// </summary>\r
47   [DebuggerDisplay("iref({ObjectNumber}, {GenerationNumber})")]\r
48   public sealed class PdfReference : PdfItem\r
49   {\r
50     // About PdfReference \r
51     // \r
52     // * A PdfReference holds the either ObjectID or the PdfObject or both.\r
53     // \r
54     // * Each PdfObject has a PdfReference if and only if it is an indirect object. Direct objects have\r
55     //   no PdfReference, because they are embedded in a parent objects.\r
56     //\r
57     // * PdfReference objects are used to reference PdfObject instances. A value in a PDF dictionary\r
58     //   or array that is a PdfReference represents an indirect reference. A value in a PDF dictionary or\r
59     //   or array that is a PdfObject represents a direct (or embeddded) object.\r
60     //\r
61     // * When a PDF file is imported, the PdfXRefTable is filled with PdfReference objects keeping the\r
62     //   ObjectsIDs and file positions (offsets) of all indirect objects.\r
63     //\r
64     // * Indirect objects can easily be renumbered because they do not rely on their ObjectsIDs.\r
65     //\r
66     // * During modification of a document the ObjectID of an indirect object has no meaning,\r
67     //   except that they must be different in pairs.\r
68 \r
69     /// <summary>\r
70     /// Initializes a new PdfReference instance for the specified indirect object.\r
71     /// </summary>\r
72     public PdfReference(PdfObject pdfObject)\r
73     {\r
74       Debug.Assert(pdfObject.Reference == null, "Must not create iref for an object that already has one.");\r
75       this.value = pdfObject;\r
76 #if UNIQUE_IREF && DEBUG\r
77       this.uid = ++PdfReference.counter;\r
78 #endif\r
79     }\r
80 \r
81     /// <summary>\r
82     /// Initializes a new PdfReference instance from the specified object identifier and file position.\r
83     /// </summary>\r
84     public PdfReference(PdfObjectID objectID, int position)\r
85     {\r
86       this.objectID = objectID;\r
87       this.position = position;\r
88 #if UNIQUE_IREF && DEBUG\r
89       this.uid = ++PdfReference.counter;\r
90 #endif\r
91     }\r
92 \r
93     /// <summary>\r
94     /// Writes the object in PDF iref table format.\r
95     /// </summary>\r
96     internal void WriteXRefEnty(PdfWriter writer)\r
97     {\r
98       // PDFsharp does not yet support PDF 1.5 object streams.\r
99 \r
100       // Each line must be exactly 20 bytes long, otherwise Acrobat repairs the file.\r
101       string text = String.Format("{0:0000000000} {1:00000} n\n",\r
102         this.position, this.objectID.GenerationNumber); // this.InUse ? 'n' : 'f');\r
103       writer.WriteRaw(text);\r
104     }\r
105 \r
106     /// <summary>\r
107     /// Writes an indirect reference.\r
108     /// </summary>\r
109     internal override void WriteObject(PdfWriter writer)\r
110     {\r
111       writer.Write(this);\r
112     }\r
113 \r
114     /// <summary>\r
115     /// Gets or sets the object identifier.\r
116     /// </summary>\r
117     public PdfObjectID ObjectID\r
118     {\r
119       get { return this.objectID; }\r
120       set\r
121       {\r
122         if (this.objectID != value)\r
123         {\r
124           this.objectID = value;\r
125           if (this.Document != null)\r
126           {\r
127             //PdfXRefTable table = this.Document.xrefTable;\r
128             //table.Remove(this);\r
129             //this.objectID = value;\r
130             //table.Add(this);\r
131           }\r
132         }\r
133       }\r
134     }\r
135     PdfObjectID objectID;\r
136 \r
137     /// <summary>\r
138     /// Gets the object number of the object identifier.\r
139     /// </summary>\r
140     public int ObjectNumber\r
141     {\r
142       get { return this.objectID.ObjectNumber; }\r
143     }\r
144 \r
145     /// <summary>\r
146     /// Gets the generation number of the object identifier.\r
147     /// </summary>\r
148     public int GenerationNumber\r
149     {\r
150       get { return this.objectID.GenerationNumber; }\r
151     }\r
152 \r
153     /// <summary>\r
154     /// Gets or sets the file position of the related PdfObject.\r
155     /// </summary>\r
156     public int Position\r
157     {\r
158       get { return this.position; }\r
159       set { this.position = value; }\r
160     }\r
161     int position;  // I know it should be long, but I have never seen a 2GB PDF file.\r
162 \r
163     //public bool InUse\r
164     //{\r
165     //  get {return this.inUse;}\r
166     //  set {this.inUse = value;}\r
167     //}\r
168     //bool inUse;\r
169 \r
170     /// <summary>\r
171     /// Gets or sets the referenced PdfObject.\r
172     /// </summary>\r
173     public PdfObject Value\r
174     {\r
175       get { return this.value; }\r
176       set\r
177       {\r
178         Debug.Assert(value != null, "The value of a PdfReference must never be null.");\r
179         Debug.Assert(value.Reference == null || Object.ReferenceEquals(value.Reference, this), "The reference of the value must be null or this.");\r
180         this.value = value;\r
181         // value must never be null\r
182         value.Reference = this;\r
183       }\r
184     }\r
185     PdfObject value;\r
186 \r
187     /// <summary>\r
188     /// Hack for dead objects.\r
189     /// </summary>\r
190     internal void SetObject(PdfObject value)\r
191     {\r
192       this.value = value;\r
193     }\r
194 \r
195     /// <summary>\r
196     /// Gets or sets the document this object belongs to.\r
197     /// </summary>\r
198     public PdfDocument Document\r
199     {\r
200       get { return this.document; }\r
201       set { this.document = value; }\r
202     }\r
203     PdfDocument document;\r
204 \r
205     /// <summary>\r
206     /// Gets a string representing the object identifier.\r
207     /// </summary>\r
208     public override string ToString()\r
209     {\r
210       return this.objectID.ToString() + " R";\r
211     }\r
212 \r
213     internal static PdfReferenceComparer Comparer\r
214     {\r
215       get { return new PdfReferenceComparer(); }\r
216     }\r
217 \r
218     /// <summary>\r
219     /// Implements a comparer that compares PdfReference objects by their PdfObjectID.\r
220     /// </summary>\r
221     internal class PdfReferenceComparer : IComparer<PdfReference>\r
222     {\r
223       public int Compare(PdfReference x, PdfReference y)\r
224       {\r
225         PdfReference l = x; // as PdfReference;\r
226         PdfReference r = y; // as PdfReference;\r
227         if (l != null)\r
228         {\r
229           if (r != null)\r
230             return l.objectID.CompareTo(r.objectID);\r
231           else\r
232             return -1;\r
233         }\r
234         else if (r != null)\r
235           return 1;\r
236         else\r
237           return 0;\r
238       }\r
239     }\r
240 \r
241 #if UNIQUE_IREF && DEBUG\r
242     static int counter = 0;\r
243     int uid;\r
244 #endif\r
245   }\r
246 }\r