Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4680 right-hear 1
#include "fitz.h"
2
#include "muxps.h"
3
 
4
/*
5
 * The FixedDocumentSequence and FixedDocument parts determine
6
 * which parts correspond to actual pages, and the page order.
7
 */
8
 
9
void
10
xps_debug_page_list(xps_context *ctx)
11
{
12
	xps_document *fixdoc = ctx->first_fixdoc;
13
	xps_page *page = ctx->first_page;
14
 
15
	if (ctx->start_part)
16
		printf("start part %s\n", ctx->start_part);
17
 
18
	while (fixdoc)
19
	{
20
		printf("fixdoc %s\n", fixdoc->name);
21
		fixdoc = fixdoc->next;
22
	}
23
 
24
	while (page)
25
	{
26
		printf("page %s w=%d h=%d\n", page->name, page->width, page->height);
27
		page = page->next;
28
	}
29
}
30
 
31
static void
32
xps_add_fixed_document(xps_context *ctx, char *name)
33
{
34
	xps_document *fixdoc;
35
 
36
	/* Check for duplicates first */
37
	for (fixdoc = ctx->first_fixdoc; fixdoc; fixdoc = fixdoc->next)
38
		if (!strcmp(fixdoc->name, name))
39
			return;
40
 
41
	fixdoc = fz_malloc(sizeof(xps_document));
42
	fixdoc->name = fz_strdup(name);
43
	fixdoc->next = NULL;
44
 
45
	if (!ctx->first_fixdoc)
46
	{
47
		ctx->first_fixdoc = fixdoc;
48
		ctx->last_fixdoc = fixdoc;
49
	}
50
	else
51
	{
52
		ctx->last_fixdoc->next = fixdoc;
53
		ctx->last_fixdoc = fixdoc;
54
	}
55
}
56
 
57
static void
58
xps_add_fixed_page(xps_context *ctx, char *name, int width, int height)
59
{
60
	xps_page *page;
61
 
62
	/* Check for duplicates first */
63
	for (page = ctx->first_page; page; page = page->next)
64
		if (!strcmp(page->name, name))
65
			return;
66
 
67
	page = fz_malloc(sizeof(xps_page));
68
	page->name = fz_strdup(name);
69
	page->width = width;
70
	page->height = height;
71
	page->root = NULL;
72
	page->next = NULL;
73
 
74
	if (!ctx->first_page)
75
	{
76
		ctx->first_page = page;
77
		ctx->last_page = page;
78
	}
79
	else
80
	{
81
		ctx->last_page->next = page;
82
		ctx->last_page = page;
83
	}
84
}
85
 
86
static void
87
xps_free_fixed_pages(xps_context *ctx)
88
{
89
	xps_page *page = ctx->first_page;
90
	while (page)
91
	{
92
		xps_page *next = page->next;
93
		xps_free_page(ctx, page);
94
		fz_free(page->name);
95
		fz_free(page);
96
		page = next;
97
	}
98
	ctx->first_page = NULL;
99
	ctx->last_page = NULL;
100
}
101
 
102
static void
103
xps_free_fixed_documents(xps_context *ctx)
104
{
105
	xps_document *doc = ctx->first_fixdoc;
106
	while (doc)
107
	{
108
		xps_document *next = doc->next;
109
		fz_free(doc->name);
110
		fz_free(doc);
111
		doc = next;
112
	}
113
	ctx->first_fixdoc = NULL;
114
	ctx->last_fixdoc = NULL;
115
}
116
 
117
void
118
xps_free_page_list(xps_context *ctx)
119
{
120
	xps_free_fixed_documents(ctx);
121
	xps_free_fixed_pages(ctx);
122
}
123
 
124
/*
125
 * Parse the fixed document sequence structure and _rels/.rels to find the start part.
126
 */
127
 
128
static void
129
xps_parse_metadata_imp(xps_context *ctx, xml_element *item)
130
{
131
	while (item)
132
	{
133
		xps_parse_metadata_imp(ctx, xml_down(item));
134
 
135
		if (!strcmp(xml_tag(item), "Relationship"))
136
		{
137
			char *target = xml_att(item, "Target");
138
			char *type = xml_att(item, "Type");
139
			if (target && type)
140
			{
141
				char tgtbuf[1024];
142
				xps_absolute_path(tgtbuf, ctx->base_uri, target, sizeof tgtbuf);
143
				if (!strcmp(type, REL_START_PART))
144
					ctx->start_part = fz_strdup(tgtbuf);
145
			}
146
		}
147
 
148
		if (!strcmp(xml_tag(item), "DocumentReference"))
149
		{
150
			char *source = xml_att(item, "Source");
151
			if (source)
152
			{
153
				char srcbuf[1024];
154
				xps_absolute_path(srcbuf, ctx->base_uri, source, sizeof srcbuf);
155
				xps_add_fixed_document(ctx, srcbuf);
156
			}
157
		}
158
 
159
		if (!strcmp(xml_tag(item), "PageContent"))
160
		{
161
			char *source = xml_att(item, "Source");
162
			char *width_att = xml_att(item, "Width");
163
			char *height_att = xml_att(item, "Height");
164
			int width = width_att ? atoi(width_att) : 0;
165
			int height = height_att ? atoi(height_att) : 0;
166
			if (source)
167
			{
168
				char srcbuf[1024];
169
				xps_absolute_path(srcbuf, ctx->base_uri, source, sizeof srcbuf);
170
				xps_add_fixed_page(ctx, srcbuf, width, height);
171
			}
172
		}
173
 
174
		item = xml_next(item);
175
	}
176
}
177
 
178
static int
179
xps_parse_metadata(xps_context *ctx, xps_part *part)
180
{
181
	xml_element *root;
182
	char buf[1024];
183
	char *s;
184
 
185
	/* Save directory name part */
186
	fz_strlcpy(buf, part->name, sizeof buf);
187
	s = strrchr(buf, '/');
188
	if (s)
189
		s[0] = 0;
190
 
191
	/* _rels parts are voodoo: their URI references are from
192
	 * the part they are associated with, not the actual _rels
193
	 * part being parsed.
194
	 */
195
	s = strstr(buf, "/_rels");
196
	if (s)
197
		*s = 0;
198
 
199
	ctx->base_uri = buf;
200
	ctx->part_uri = part->name;
201
 
202
	root = xml_parse_document(part->data, part->size);
203
	if (!root)
204
		return fz_rethrow(-1, "cannot parse metadata part '%s'", part->name);
205
 
206
	xps_parse_metadata_imp(ctx, root);
207
 
208
	xml_free_element(root);
209
 
210
	ctx->base_uri = NULL;
211
	ctx->part_uri = NULL;
212
 
213
	return fz_okay;
214
}
215
 
216
static int
217
xps_read_and_process_metadata_part(xps_context *ctx, char *name)
218
{
219
	xps_part *part;
220
	int code;
221
 
222
	part = xps_read_part(ctx, name);
223
	if (!part)
224
		return fz_rethrow(-1, "cannot read zip part '%s'", name);
225
 
226
	code = xps_parse_metadata(ctx, part);
227
	if (code)
228
		return fz_rethrow(code, "cannot process metadata part '%s'", name);
229
 
230
	xps_free_part(ctx, part);
231
 
232
	return fz_okay;
233
}
234
 
235
int
236
xps_read_page_list(xps_context *ctx)
237
{
238
	xps_document *doc;
239
	int code;
240
 
241
	code = xps_read_and_process_metadata_part(ctx, "/_rels/.rels");
242
	if (code)
243
		return fz_rethrow(code, "cannot process root relationship part");
244
 
245
	if (!ctx->start_part)
246
		return fz_throw("cannot find fixed document sequence start part");
247
 
248
	code = xps_read_and_process_metadata_part(ctx, ctx->start_part);
249
	if (code)
250
		return fz_rethrow(code, "cannot process FixedDocumentSequence part");
251
 
252
	for (doc = ctx->first_fixdoc; doc; doc = doc->next)
253
	{
254
		code = xps_read_and_process_metadata_part(ctx, doc->name);
255
		if (code)
256
			return fz_rethrow(code, "cannot process FixedDocument part");
257
	}
258
 
259
	return fz_okay;
260
}
261
 
262
int
263
xps_count_pages(xps_context *ctx)
264
{
265
	xps_page *page;
266
	int n = 0;
267
	for (page = ctx->first_page; page; page = page->next)
268
		n ++;
269
	return n;
270
}
271
 
272
static int
273
xps_load_fixed_page(xps_context *ctx, xps_page *page)
274
{
275
	xps_part *part;
276
	xml_element *root;
277
	char *width_att;
278
	char *height_att;
279
 
280
	part = xps_read_part(ctx, page->name);
281
	if (!part)
282
		return fz_rethrow(-1, "cannot read zip part '%s'", page->name);
283
 
284
	root = xml_parse_document(part->data, part->size);
285
	if (!root)
286
		return fz_rethrow(-1, "cannot parse xml part '%s'", page->name);
287
 
288
	xps_free_part(ctx, part);
289
 
290
	if (strcmp(xml_tag(root), "FixedPage"))
291
		return fz_throw("expected FixedPage element (found %s)", xml_tag(root));
292
 
293
	width_att = xml_att(root, "Width");
294
	if (!width_att)
295
		return fz_throw("FixedPage missing required attribute: Width");
296
 
297
	height_att = xml_att(root, "Height");
298
	if (!height_att)
299
		return fz_throw("FixedPage missing required attribute: Height");
300
 
301
	page->width = atoi(width_att);
302
	page->height = atoi(height_att);
303
	page->root = root;
304
 
305
	return 0;
306
}
307
 
308
int
309
xps_load_page(xps_page **pagep, xps_context *ctx, int number)
310
{
311
	xps_page *page;
312
	int code;
313
	int n = 0;
314
 
315
	for (page = ctx->first_page; page; page = page->next)
316
	{
317
		if (n == number)
318
		{
319
			if (!page->root)
320
			{
321
				code = xps_load_fixed_page(ctx, page);
322
				if (code)
323
					return fz_rethrow(code, "cannot load page %d", number + 1);
324
			}
325
			*pagep = page;
326
			return fz_okay;
327
		}
328
		n ++;
329
	}
330
 
331
	return fz_throw("cannot find page %d", number + 1);
332
}
333
 
334
void
335
xps_free_page(xps_context *ctx, xps_page *page)
336
{
337
	/* only free the XML contents */
338
	if (page->root)
339
		xml_free_element(page->root);
340
	page->root = NULL;
341
}