1 /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
2 
3     Copyright (C) 2002-2014 by Jin-Hwan Cho and Shunsaku Hirata,
4     the dvipdfmx project team.
5 
6     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 */
22 
23 /*
24  * Currently, this is nearly useless.
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 #include "system.h"
32 #include "mem.h"
33 #include "error.h"
34 
35 #include "dpxutil.h"
36 
37 #include "pdfobj.h"
38 
39 #include "pdfresource.h"
40 
41 #define PDF_RESOURCE_DEBUG_STR "PDF"
42 #define PDF_RESOURCE_DEBUG     3
43 
44 #define PDF_RESOURCE_FONT       0
45 #define PDF_RESOURCE_CIDFONT    1
46 #define PDF_RESOURCE_ENCODING   2
47 #define PDF_RESOURCE_CMAP       3
48 #define PDF_RESOURCE_XOBJECT    4
49 #define PDF_RESOURCE_COLORSPACE 5
50 #define PDF_RESOURCE_SHADING    6
51 #define PDF_RESOURCE_PATTERN    7
52 #define PDF_RESOURCE_GSTATE     8
53 
54 typedef struct pdf_res
55 {
56   char    *ident;
57 
58   int      flags;
59 
60   int      category;
61   void    *cdata;
62 
63   pdf_obj *object;
64   pdf_obj *reference;
65 } pdf_res;
66 
67 static struct {
68   const char *name;
69   int         cat_id;
70 } pdf_resource_categories[] = {
71   {"Font",       PDF_RESOURCE_FONT},
72   {"CIDFont",    PDF_RESOURCE_CIDFONT},
73   {"Encoding",   PDF_RESOURCE_ENCODING},
74   {"CMap",       PDF_RESOURCE_CMAP},
75   {"XObject",    PDF_RESOURCE_XOBJECT},
76   {"ColorSpace", PDF_RESOURCE_COLORSPACE},
77   {"Shading",    PDF_RESOURCE_SHADING},
78   {"Pattern",    PDF_RESOURCE_PATTERN},
79   {"ExtGState",  PDF_RESOURCE_GSTATE},
80 };
81 
82 #define PDF_NUM_RESOURCE_CATEGORIES (sizeof(pdf_resource_categories)/sizeof(pdf_resource_categories[0]))
83 
84 #define CACHE_ALLOC_SIZE 16u
85 struct res_cache
86 {
87   int      count;
88   int      capacity;
89   pdf_res *resources;
90 };
91 
92 static struct res_cache resources[PDF_NUM_RESOURCE_CATEGORIES];
93 
94 static void
pdf_init_resource(pdf_res * res)95 pdf_init_resource (pdf_res *res)
96 {
97   ASSERT(res);
98 
99   res->ident     = NULL;
100   res->category  = -1;
101   res->flags     = 0;
102   res->cdata     = NULL;
103   res->object    = NULL;
104   res->reference = NULL;
105 
106   return;
107 }
108 
109 static void
pdf_flush_resource(pdf_res * res)110 pdf_flush_resource (pdf_res *res)
111 {
112   if (res) {
113     if (res->reference)
114       pdf_release_obj(res->reference);
115     if (res->object)
116       pdf_release_obj(res->object);
117 
118     res->reference = NULL;
119     res->object    = NULL;
120   }
121 }
122 
123 static void
pdf_clean_resource(pdf_res * res)124 pdf_clean_resource (pdf_res *res)
125 {
126   if (res) {
127     if (res->reference || res->object)
128       WARN("Trying to release un-flushed object.");
129     if (res->reference)
130       pdf_release_obj(res->reference);
131     if (res->object)
132       pdf_release_obj(res->object);
133     if (res->ident)
134       RELEASE(res->ident);
135     res->ident    = NULL;
136     res->category = -1;
137     res->flags    = 0;
138   }
139 }
140 
141 void
pdf_init_resources(void)142 pdf_init_resources (void)
143 {
144   int  i;
145 
146   for (i = 0;
147        i < PDF_NUM_RESOURCE_CATEGORIES; i++) {
148     resources[i].count     = 0;
149     resources[i].capacity  = 0;
150     resources[i].resources = NULL;
151   }
152 }
153 
154 void
pdf_close_resources(void)155 pdf_close_resources (void)
156 {
157   int  i;
158 
159   for (i = 0;
160        i < PDF_NUM_RESOURCE_CATEGORIES; i++) {
161     struct res_cache *rc;
162     int    j;
163 
164     rc = &resources[i];
165     for (j = 0; j < rc->count; j++) {
166       pdf_flush_resource(&rc->resources[j]);
167       pdf_clean_resource(&rc->resources[j]);
168     }
169     RELEASE(rc->resources);
170 
171     rc->count     = 0;
172     rc->capacity  = 0;
173     rc->resources = NULL;
174   }
175 }
176 
177 static int
get_category(const char * category)178 get_category (const char *category)
179 {
180   int  i;
181 
182   for (i = 0;
183        i < PDF_NUM_RESOURCE_CATEGORIES; i++) {
184     if (!strcmp(category, pdf_resource_categories[i].name)) {
185       return pdf_resource_categories[i].cat_id;
186     }
187   }
188 
189   return -1;
190 }
191 
192 long
pdf_defineresource(const char * category,const char * resname,pdf_obj * object,int flags)193 pdf_defineresource (const char *category,
194 		    const char *resname, pdf_obj *object, int flags)
195 {
196   int      res_id;
197   struct res_cache *rc;
198   int      cat_id;
199   pdf_res *res = NULL;
200 
201   ASSERT(category && object);
202 
203   cat_id = get_category(category);
204   if (cat_id < 0) {
205     ERROR("Unknown resource category: %s", category);
206     return -1;
207   }
208 
209   rc = &resources[cat_id];
210   if (resname) {
211     for (res_id = 0; res_id < rc->count; res_id++) {
212       res = &rc->resources[res_id];
213       if (!strcmp(resname, res->ident)) {
214 	WARN("Resource %s (category: %s) already defined...",
215 	     resname, category);
216 	pdf_flush_resource(res);
217 	res->flags    = flags;
218 	if (flags & PDF_RES_FLUSH_IMMEDIATE) {
219 	  res->reference = pdf_ref_obj(object);
220 	  pdf_release_obj(object);
221 	} else {
222 	  res->object = object;
223 	}
224 	return (long) ((cat_id << 16)|(res_id));
225       }
226     }
227   } else {
228     res_id = rc->count;
229   }
230 
231   if (res_id == rc->count) {
232     if (rc->count >= rc->capacity) {
233       rc->capacity += CACHE_ALLOC_SIZE;
234       rc->resources = RENEW(rc->resources, rc->capacity, pdf_res);
235     }
236     res = &rc->resources[res_id];
237 
238     pdf_init_resource(res);
239     if (resname && resname[0] != '\0') {
240       res->ident = NEW(strlen(resname) + 1, char);
241       strcpy(res->ident, resname);
242     }
243     res->category = cat_id;
244     res->flags    = flags;
245     if (flags & PDF_RES_FLUSH_IMMEDIATE) {
246       res->reference = pdf_ref_obj(object);
247       pdf_release_obj(object);
248     } else {
249       res->object = object;
250     }
251     rc->count++;
252   }
253 
254   return (long) ((cat_id << 16)|(res_id));
255 }
256 
257 #if 0
258 int
259 pdf_resource_exist (const char *category, const char *resname)
260 {
261   int    res_id;
262   struct res_cache *rc;
263   int    cat_id;
264 
265   ASSERT(resname && category);
266 
267   cat_id = get_category(category);
268   if (cat_id < 0)
269     ERROR("Unknown resource category: %s", category);
270 
271   rc = &resources[cat_id];
272   for (res_id = 0; res_id < rc->count; res_id++) {
273     pdf_res *res;
274 
275     res = &rc->resources[res_id];
276     if (!strcmp(resname, res->ident)) {
277       return 1;
278     }
279   }
280 
281   return 0;
282 }
283 #endif
284 
285 long
pdf_findresource(const char * category,const char * resname)286 pdf_findresource (const char *category, const char *resname)
287 {
288   pdf_res *res;
289   int      res_id, cat_id;
290   struct res_cache *rc;
291 
292   ASSERT(resname && category);
293 
294   cat_id = get_category(category);
295   if (cat_id < 0) {
296     ERROR("Unknown resource category: %s", category);
297     return -1;
298   }
299 
300   rc = &resources[cat_id];
301   for (res_id = 0; res_id < rc->count; res_id++) {
302     res = &rc->resources[res_id];
303     if (!strcmp(resname, res->ident)) {
304       return (long) (cat_id << 16|res_id);
305     }
306   }
307 
308   return -1;
309 }
310 
311 pdf_obj *
pdf_get_resource_reference(long rc_id)312 pdf_get_resource_reference (long rc_id)
313 {
314   int  cat_id, res_id;
315   struct res_cache *rc;
316   pdf_res *res;
317 
318   cat_id = (rc_id >> 16) & 0xffff;
319   res_id = rc_id & 0xffff;
320 
321   if (cat_id < 0 ||
322       cat_id >= PDF_NUM_RESOURCE_CATEGORIES) {
323     ERROR("Invalid category ID: %d", cat_id);
324     return NULL;
325   }
326   rc  = &resources[cat_id];
327   if (res_id < 0 || res_id >= rc->count) {
328     ERROR("Invalid resource ID: %d", res_id);
329     return NULL;
330   }
331 
332   res = &rc->resources[res_id];
333   if (!res->reference) {
334     if (!res->object) {
335       ERROR("Undefined object...");
336       return NULL;
337     } else {
338       res->reference = pdf_ref_obj(res->object);
339     }
340   }
341 
342   return pdf_link_obj(res->reference);
343 }
344 
345 #if 0
346 pdf_obj *
347 pdf_get_resource (long rc_id)
348 {
349   int  cat_id, res_id;
350   struct res_cache *rc;
351   pdf_res *res;
352 
353   cat_id = (rc_id >> 16) & 0xffff;
354   res_id = rc_id & 0xffff;
355 
356   if (cat_id < 0 ||
357       cat_id >= PDF_NUM_RESOURCE_CATEGORIES) {
358     ERROR("Invalid category ID: %d", cat_id);
359     return NULL;
360   }
361   rc  = &resources[cat_id];
362   if (res_id < 0 || res_id >= rc->count) {
363     ERROR("Invalid resource ID: %d", res_id);
364     return NULL;
365   }
366 
367   res = &rc->resources[res_id];
368   if (!res->object) {
369     ERROR("Object already flushed???");
370     return NULL;
371   }
372 
373   return res->object;
374 }
375 #endif
376