1 /*
2  * << H a r u -- Free PDF Library >> -- PdfXref.cpp
3  *
4  * Copyright (c) 1999-2003 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp>
5  *
6  * Permission to use, copy, modify, distribute and sell this software
7  * and its documentation for any purpose is hereby granted without fee,
8  * provided that the above copyright notice appear in all copies and
9  * that both that copyright notice and this permission notice appear
10  * in supporting documentation.
11  * It is provided "as is" without express or implied warranty.
12  *
13  */
14 
15 #include <new>
16 #include "libharu.h"
17 
18 #define PDF_FREE_ENTRY          'f'
19 #define PDF_IN_USE_ENTRY        'n'
20 
21 #define PDF_MAX_GENERATION_NUM  65535
22 
23 /*----- PdfXrefEntry class ---------------------------------------------------*/
24 
~PdfXrefEntry()25 PdfXrefEntry::~PdfXrefEntry()
26 {
27     if (HasObject())
28         delete fObject;
29     PDF_DEBUG_PRINT(("++ [%x] PdfXrefEntry delete.\n", (int)this));
30 }
31 
PdfXrefEntry(PdfObject * object)32 PdfXrefEntry::PdfXrefEntry(PdfObject *object)
33 {
34     fEntryType = PDF_FREE_ENTRY;
35     fByteOffset = 0;
36     fObject = NULL;
37     SetObject(object);
38     PDF_DEBUG_PRINT(("++ [%x] PdfXrefEntry new.\n", (int)this));
39 }
40 
41 void
SetObject(PdfObject * object)42 PdfXrefEntry::SetObject(PdfObject *object)
43 {
44     fObject = object;
45     if (object != NULL) {
46         fGenerationNo = object->GetGenerationNo();
47         fEntryType = PDF_IN_USE_ENTRY;
48     }
49 }
50 
51 /*----------------------------------------------------------------------------*/
52 /*----- Xref class -----------------------------------------------------------*/
53 
PdfXref(PdfDoc * doc)54 PdfXref::PdfXref(PdfDoc* doc)
55 {
56     fDoc = doc;
57     fEntries = NULL;
58     PDF_DEBUG_PRINT(("++ [%x] PdfXref new.\n", (int)this));
59 }
60 
61 void
Init()62 PdfXref::Init()
63 {
64     fEntries = new PdfList();
65     PdfXrefEntry* newEntry = new PdfXrefEntry((PdfObject*)NULL);
66     newEntry->SetEntryType(PDF_FREE_ENTRY);
67     newEntry->SetGenerationNo(PDF_MAX_GENERATION_NUM);
68     if (fEntries->AddItem(newEntry) == false) {
69         delete newEntry;
70         throw PdfException(PDF_ERR_MALLOC, "PdfXref::Init()");
71     }
72 }
73 
~PdfXref()74 PdfXref::~PdfXref()
75 {
76     Clear();
77     delete fEntries;
78     PDF_DEBUG_PRINT(("++ [%x] PdfXref delete.\n", (int)this));
79 }
80 
81 void
Clear()82 PdfXref::Clear()
83 {
84     PDF_DEBUG_PRINT(("PdfXref::Clear: item count:[%d]\n", GetCount()));
85 
86     if (fEntries == NULL)
87         return;
88 
89     for (int i = 0; i < GetCount(); i++) {
90         PdfXrefEntry* entry = GetEntry(i);
91         if (entry != NULL)
92             delete entry;
93     }
94     fEntries->Clear();
95     fAddr = 0;
96 }
97 
98 PdfObject*
GetObject(PdfOID objectID)99 PdfXref::GetObject(PdfOID objectID)
100 {
101     if (fEntries == NULL)
102         return NULL;
103 
104     PdfXrefEntry* entry = GetEntry(objectID);
105     if (entry && entry->HasObject())
106         return entry->GetObject();
107     else
108         return NULL;
109 }
110 
111 PdfOID
AddObject(PdfObject * object)112 PdfXref::AddObject(PdfObject* object)
113 {
114     PDF_DEBUG_PRINT(("PdfXref::AddObject: [%X]\n", (int)object));
115 
116     PdfXrefEntry* newEntry = NULL;
117 
118     try {
119         if (fEntries == NULL)
120             Init();
121         newEntry = new PdfXrefEntry(object);
122     } catch (ALLOC_ERROR& e) {
123         delete object;
124         throw;
125     }
126 
127     if (fEntries->AddItem((void*)newEntry)) {
128         object->SetObjectID(fEntries->CountItems() - 1);
129     } else {
130         PDF_DEBUG_PRINT(("PdfXref::AddObject: failed to add object at:[%x]\n",
131             (int)object));
132         delete newEntry;
133         throw PdfException(PDF_ERR_MALLOC, "PdfXref::AddObject");
134     }
135     return object->GetObjectID();
136 }
137 
138 void
WriteToStream(PdfStreamBase * out,PdfEncryptor * e)139 PdfXref::WriteToStream(PdfStreamBase* out, PdfEncryptor* e)
140 {
141     char Buf[11];
142     PdfXrefEntry* entry;
143 
144     if (fEntries == NULL)
145         Init();
146 
147     for (int i = 1; i < GetCount(); i++) {
148         entry = GetEntry(i);
149         PDF_DEBUG_PRINT(("PdfXref::WriteToStream: objectId = %d\n",
150             entry->GetObject()->GetObjectID()));
151         entry->SetByteOffset(out->GetPos());
152 #ifdef USE_ENCRYPTION
153         if (e != NULL)
154             e->Init(entry->GetObject()->GetObjectID(),
155                 entry->GetGenerationNo());
156 #endif
157         entry->GetObject()->WriteValueToStream(out, e);
158     }
159 
160     fAddr = out->GetPos();
161     *out << "xref\015\0120 " << (unsigned int)GetCount() << "\015\012";
162     for (int j = 0; j < GetCount(); j++) {
163         entry = GetEntry(j);
164 
165 #ifdef __WIN32__
166         _snprintf(Buf, 11, "%010d", entry->GetByteOffset());
167 #else
168         snprintf(Buf, 11, "%010d", entry->GetByteOffset());
169 #endif
170         *out << Buf
171              << " ";
172 #ifdef __WIN32__
173         _snprintf(Buf, 6, "%05d", entry->GetGenerationNo());
174 #else
175         snprintf(Buf, 6, "%05d", entry->GetGenerationNo());
176 #endif
177         *out << Buf
178              << " "
179              << entry->GetEntryType()
180              << "\015\012";
181     }
182 }
183 
184 void
SetError(int err)185 PdfXref::SetError(int err)
186 {
187     fDoc->SetError(err);
188 }
189 
190 /*----------------------------------------------------------------------------*/
191 
192