1 /* SPDX-License-Identifier: Zlib */
2
3 #include <stdlib.h>
4 #include <ctype.h>
5 #include <girara/datastructures.h>
6 #include <string.h>
7 #include <libdjvu/miniexp.h>
8 #include <glib.h>
9
10 #include "djvu.h"
11 #include "page-text.h"
12 #include "internal.h"
13
14 /* forward declarations */
15 static const char* get_extension(const char* path);
16 static void build_index(djvu_document_t *djvu_document, miniexp_t expression, girara_tree_node_t* root);
17 static bool exp_to_str(miniexp_t expression, const char** string);
18 static bool exp_to_int(miniexp_t expression, int* integer);
19 static bool exp_to_rect(miniexp_t expression, zathura_rectangle_t* rect);
20
21 ZATHURA_PLUGIN_REGISTER_WITH_FUNCTIONS(
22 "djvu",
23 VERSION_MAJOR, VERSION_MINOR, VERSION_REV,
24 ZATHURA_PLUGIN_FUNCTIONS({
25 .document_open = djvu_document_open,
26 .document_free = djvu_document_free,
27 .document_index_generate = djvu_document_index_generate,
28 .document_save_as = djvu_document_save_as,
29 .page_init = djvu_page_init,
30 .page_clear = djvu_page_clear,
31 .page_search_text = djvu_page_search_text,
32 .page_get_text = djvu_page_get_text,
33 .page_links_get = djvu_page_links_get,
34 .page_render = djvu_page_render,
35 .page_render_cairo = djvu_page_render_cairo
36 }),
37 ZATHURA_PLUGIN_MIMETYPES({
38 "image/vnd.djvu",
39 "image/vnd.djvu+multipage"
40 })
41 )
42
43 zathura_error_t
djvu_document_open(zathura_document_t * document)44 djvu_document_open(zathura_document_t* document)
45 {
46 zathura_error_t error = ZATHURA_ERROR_OK;
47
48 if (document == NULL) {
49 error = ZATHURA_ERROR_INVALID_ARGUMENTS;
50 goto error_out;
51 }
52
53 djvu_document_t* djvu_document = calloc(1, sizeof(djvu_document_t));
54 if (djvu_document == NULL) {
55 error = ZATHURA_ERROR_OUT_OF_MEMORY;
56 goto error_out;
57 }
58
59 /* setup format */
60 static unsigned int masks[4] = {0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000};
61 djvu_document->format = ddjvu_format_create(DDJVU_FORMAT_RGBMASK32, 4, masks);
62
63 if (djvu_document->format == NULL) {
64 error = ZATHURA_ERROR_UNKNOWN;
65 goto error_free;
66 }
67
68 ddjvu_format_set_row_order(djvu_document->format, TRUE);
69
70 /* setup context */
71 djvu_document->context = ddjvu_context_create("zathura");
72
73 if (djvu_document->context == NULL) {
74 error = ZATHURA_ERROR_UNKNOWN;
75 goto error_free;
76 }
77
78 /* setup document */
79 djvu_document->document =
80 ddjvu_document_create_by_filename(
81 djvu_document->context,
82 zathura_document_get_path(document),
83 FALSE
84 );
85
86 if (djvu_document->document == NULL) {
87 error = ZATHURA_ERROR_UNKNOWN;
88 goto error_free;
89 }
90
91 /* load document info */
92 ddjvu_message_t* msg;
93 ddjvu_message_wait(djvu_document->context);
94
95 while ((msg = ddjvu_message_peek(djvu_document->context)) &&
96 (msg->m_any.tag != DDJVU_DOCINFO)) {
97 if (msg->m_any.tag == DDJVU_ERROR) {
98 error = ZATHURA_ERROR_UNKNOWN;
99 goto error_free;
100 }
101
102 ddjvu_message_pop(djvu_document->context);
103 }
104
105 /* decoding error */
106 if (ddjvu_document_decoding_error(djvu_document->document)) {
107 handle_messages(djvu_document, true);
108 error = ZATHURA_ERROR_UNKNOWN;
109 goto error_free;
110 }
111
112 zathura_document_set_data(document, djvu_document);
113 zathura_document_set_number_of_pages(document,
114 ddjvu_document_get_pagenum(djvu_document->document));
115
116 return error;
117
118 error_free:
119
120 if (djvu_document->format != NULL) {
121 ddjvu_format_release(djvu_document->format);
122 }
123
124 if (djvu_document->context != NULL) {
125 ddjvu_context_release(djvu_document->context);
126 }
127
128 free(djvu_document);
129
130 error_out:
131
132 return error;
133 }
134
135 zathura_error_t
djvu_document_free(zathura_document_t * document,void * data)136 djvu_document_free(zathura_document_t* document, void* data)
137 {
138 djvu_document_t* djvu_document = data;
139 if (document == NULL) {
140 return ZATHURA_ERROR_INVALID_ARGUMENTS;
141 }
142
143 if (djvu_document != NULL) {
144 ddjvu_context_release(djvu_document->context);
145 ddjvu_document_release(djvu_document->document);
146 ddjvu_format_release(djvu_document->format);
147 free(djvu_document);
148 }
149
150 return ZATHURA_ERROR_OK;
151 }
152
153 girara_tree_node_t*
djvu_document_index_generate(zathura_document_t * document,void * data,zathura_error_t * error)154 djvu_document_index_generate(zathura_document_t* document, void* data, zathura_error_t* error)
155 {
156 djvu_document_t* djvu_document = data;
157 if (document == NULL || djvu_document == NULL) {
158 if (error != NULL) {
159 *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
160 }
161 return NULL;
162 }
163
164 miniexp_t outline = miniexp_dummy;
165 while ((outline = ddjvu_document_get_outline(djvu_document->document)) ==
166 miniexp_dummy) {
167 handle_messages(djvu_document, true);
168 }
169
170 if (outline == miniexp_dummy) {
171 return NULL;
172 }
173
174 if (miniexp_consp(outline) == 0 || miniexp_car(outline) != miniexp_symbol("bookmarks")) {
175 ddjvu_miniexp_release(djvu_document->document, outline);
176 return NULL;
177 }
178
179 girara_tree_node_t* root = girara_node_new(zathura_index_element_new("ROOT"));
180 build_index(djvu_document, miniexp_cdr(outline), root);
181
182 ddjvu_miniexp_release(djvu_document->document, outline);
183
184 return root;
185 }
186
187 zathura_error_t
djvu_document_save_as(zathura_document_t * document,void * data,const char * path)188 djvu_document_save_as(zathura_document_t* document, void* data, const char* path)
189 {
190 djvu_document_t* djvu_document = data;
191 if (document == NULL || djvu_document == NULL || path == NULL) {
192 return ZATHURA_ERROR_INVALID_ARGUMENTS;
193 }
194
195 FILE* fp = fopen(path, "w");
196 if (fp == NULL) {
197 return ZATHURA_ERROR_UNKNOWN;
198 }
199
200 const char* extension = get_extension(path);
201
202 ddjvu_job_t* job = NULL;
203 if (extension != NULL && g_strcmp0(extension, "ps") == 0) {
204 job = ddjvu_document_print(djvu_document->document, fp, 0, NULL);
205 } else {
206 job = ddjvu_document_save(djvu_document->document, fp, 0, NULL);
207 }
208 while (ddjvu_job_done(job) != true) {
209 handle_messages(djvu_document, true);
210 }
211
212 fclose(fp);
213
214 return ZATHURA_ERROR_OK;
215 }
216
217 zathura_error_t
djvu_page_init(zathura_page_t * page)218 djvu_page_init(zathura_page_t* page)
219 {
220 if (page == NULL) {
221 return ZATHURA_ERROR_INVALID_ARGUMENTS;
222 }
223
224 zathura_document_t* document = zathura_page_get_document(page);
225 djvu_document_t* djvu_document = zathura_document_get_data(document);
226
227 ddjvu_status_t status;
228 ddjvu_pageinfo_t page_info;
229
230 unsigned int index = zathura_page_get_index(page);
231 while ((status = ddjvu_document_get_pageinfo(djvu_document->document, index,
232 &page_info)) < DDJVU_JOB_OK) {
233 handle_messages(djvu_document, true);
234 }
235
236 if (status >= DDJVU_JOB_FAILED) {
237 handle_messages(djvu_document, true);
238 return ZATHURA_ERROR_UNKNOWN;
239 }
240
241 zathura_page_set_width(page, ZATHURA_DJVU_SCALE * page_info.width);
242 zathura_page_set_height(page, ZATHURA_DJVU_SCALE * page_info.height);
243
244 return ZATHURA_ERROR_OK;
245 }
246
247 zathura_error_t
djvu_page_clear(zathura_page_t * page,void * UNUSED (data))248 djvu_page_clear(zathura_page_t* page, void* UNUSED(data))
249 {
250 if (page == NULL) {
251 return ZATHURA_ERROR_INVALID_ARGUMENTS;
252 }
253
254 return ZATHURA_ERROR_OK;
255 }
256
257 girara_list_t*
djvu_page_search_text(zathura_page_t * page,void * UNUSED (data),const char * text,zathura_error_t * error)258 djvu_page_search_text(zathura_page_t* page, void* UNUSED(data), const char* text, zathura_error_t* error)
259 {
260 if (page == NULL || text == NULL || strlen(text) == 0) {
261 if (error != NULL) {
262 *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
263 }
264 goto error_ret;
265 }
266
267 zathura_document_t* document = zathura_page_get_document(page);
268 if (document == NULL) {
269 goto error_ret;
270 }
271
272 djvu_document_t* djvu_document = zathura_document_get_data(document);
273
274 djvu_page_text_t* page_text = djvu_page_text_new(djvu_document, page);
275 if (page_text == NULL) {
276 goto error_ret;
277 }
278
279 girara_list_t* results = djvu_page_text_search(page_text, text);
280 if (results == NULL) {
281 goto error_free;
282 }
283
284 djvu_page_text_free(page_text);
285
286 return results;
287
288 error_free:
289
290 if (page_text != NULL) {
291 djvu_page_text_free(page_text);
292 }
293
294 error_ret:
295
296 if (error != NULL && *error == ZATHURA_ERROR_OK) {
297 *error = ZATHURA_ERROR_UNKNOWN;
298 }
299
300 return NULL;
301 }
302
303 char*
djvu_page_get_text(zathura_page_t * page,void * UNUSED (data),zathura_rectangle_t rectangle,zathura_error_t * error)304 djvu_page_get_text(zathura_page_t* page, void* UNUSED(data), zathura_rectangle_t
305 rectangle, zathura_error_t* error)
306 {
307 if (page == NULL) {
308 if (error != NULL) {
309 *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
310 }
311 goto error_ret;
312 }
313
314 zathura_document_t* document = zathura_page_get_document(page);
315 if (document == NULL) {
316 goto error_ret;
317 }
318
319 djvu_document_t* djvu_document = zathura_document_get_data(document);
320
321 djvu_page_text_t* page_text = djvu_page_text_new(djvu_document, page);
322 if (page_text == NULL) {
323 goto error_ret;
324 }
325
326 double tmp = 0;
327 double page_height = zathura_page_get_height(page);
328 double page_width = zathura_page_get_width(page);
329
330 switch (zathura_document_get_rotation(document)) {
331 case 90:
332 tmp = rectangle.x1;
333 rectangle.x1 = rectangle.y1;
334 rectangle.y1 = tmp;
335 tmp = rectangle.x2;
336 rectangle.x2 = rectangle.y2;
337 rectangle.y2 = tmp;
338 break;
339 case 180:
340 tmp = rectangle.x1;
341 rectangle.x1 = (page_width - rectangle.x2);
342 rectangle.x2 = (page_width - tmp);
343 break;
344 case 270:
345 tmp = rectangle.y2;
346 rectangle.y2 = (page_height - rectangle.x1);
347 rectangle.x1 = (page_width - tmp);
348 tmp = rectangle.y1;
349 rectangle.y1 = (page_height - rectangle.x2);
350 rectangle.x2 = (page_width - tmp);
351 break;
352 default:
353 tmp = rectangle.y1;
354 rectangle.y1 = (page_height - rectangle.y2);
355 rectangle.y2 = (page_height - tmp);
356 break;
357 }
358
359 /* adjust to scale */
360 rectangle.x1 /= ZATHURA_DJVU_SCALE;
361 rectangle.x2 /= ZATHURA_DJVU_SCALE;
362 rectangle.y1 /= ZATHURA_DJVU_SCALE;
363 rectangle.y2 /= ZATHURA_DJVU_SCALE;
364
365 char* text = djvu_page_text_select(page_text, rectangle);
366
367 djvu_page_text_free(page_text);
368
369 return text;
370
371 error_ret:
372
373 if (error != NULL && *error == ZATHURA_ERROR_OK) {
374 *error = ZATHURA_ERROR_UNKNOWN;
375 }
376
377 return NULL;
378 }
379
380 girara_list_t*
djvu_page_links_get(zathura_page_t * page,void * UNUSED (data),zathura_error_t * error)381 djvu_page_links_get(zathura_page_t* page, void* UNUSED(data), zathura_error_t* error)
382 {
383 if (page == NULL) {
384 if (error != NULL) {
385 *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
386 }
387 goto error_ret;
388 }
389
390 zathura_document_t* document = zathura_page_get_document(page);
391 if (document == NULL) {
392 goto error_ret;
393 }
394
395 girara_list_t* list = girara_list_new2((girara_free_function_t) zathura_link_free);
396 if (list == NULL) {
397 if (error != NULL) {
398 *error = ZATHURA_ERROR_OUT_OF_MEMORY;
399 }
400 goto error_ret;
401 }
402
403 djvu_document_t* djvu_document = zathura_document_get_data(document);
404
405 miniexp_t annotations = miniexp_nil;
406 while ((annotations = ddjvu_document_get_pageanno(djvu_document->document,
407 zathura_page_get_index(page))) == miniexp_dummy) {
408 handle_messages(djvu_document, true);
409 }
410
411 if (annotations == miniexp_nil) {
412 goto error_free;
413 }
414
415 miniexp_t* hyperlinks = ddjvu_anno_get_hyperlinks(annotations);
416 for (miniexp_t* iter = hyperlinks; *iter != NULL; iter++) {
417 if (miniexp_car(*iter) != miniexp_symbol("maparea")) {
418 continue;
419 }
420
421 miniexp_t inner = miniexp_cdr(*iter);
422
423 /* extract url information */
424 const char* target_string = NULL;
425
426 if (miniexp_caar(inner) == miniexp_symbol("url")) {
427 if (exp_to_str(miniexp_caddr(miniexp_car(inner)), &target_string) == false) {
428 continue;
429 }
430 } else {
431 if (exp_to_str(miniexp_car(inner), &target_string) == false) {
432 continue;
433 }
434 }
435
436 /* skip comment */
437 inner = miniexp_cdr(inner);
438
439 /* extract link area */
440 inner = miniexp_cdr(inner);
441
442 zathura_rectangle_t rect = { 0, 0, 0, 0 };
443 if (exp_to_rect(miniexp_car(inner), &rect) == false) {
444 continue;
445 }
446
447 /* update rect */
448 unsigned int page_height = zathura_page_get_height(page) / ZATHURA_DJVU_SCALE;
449 rect.x1 = rect.x1 * ZATHURA_DJVU_SCALE;
450 rect.x2 = rect.x2 * ZATHURA_DJVU_SCALE;
451 double tmp = rect.y1;
452 rect.y1 = (page_height - rect.y2) * ZATHURA_DJVU_SCALE;
453 rect.y2 = (page_height - tmp) * ZATHURA_DJVU_SCALE;
454
455 /* create zathura link */
456 zathura_link_type_t type = ZATHURA_LINK_INVALID;
457 zathura_link_target_t target = { ZATHURA_LINK_DESTINATION_UNKNOWN, NULL, 0, -1, -1, -1, -1, 0 };;
458
459 /* goto page */
460 if (target_string[0] == '#' && target_string[1] == 'p') {
461 type = ZATHURA_LINK_GOTO_DEST;
462 target.page_number = atoi(target_string + 2) - 1;
463 /* url or other? */
464 } else if (strstr(target_string, "//") != NULL) {
465 type = ZATHURA_LINK_URI;
466 target.value = (char*) target_string;
467 /* TODO: Parse all different links */
468 } else {
469 continue;
470 }
471
472 zathura_link_t* link = zathura_link_new(type, rect, target);
473 if (link != NULL) {
474 girara_list_append(list, link);
475 }
476 }
477
478 return list;
479
480 error_free:
481
482 if (list != NULL) {
483 girara_list_free(list);
484 }
485
486 error_ret:
487
488 return NULL;
489 }
490
491 zathura_error_t
djvu_page_render_cairo(zathura_page_t * page,void * UNUSED (data),cairo_t * cairo,bool GIRARA_UNUSED (printing))492 djvu_page_render_cairo(zathura_page_t* page, void* UNUSED(data), cairo_t* cairo,
493 bool GIRARA_UNUSED(printing))
494 {
495 if (page == NULL || cairo == NULL) {
496 return ZATHURA_ERROR_INVALID_ARGUMENTS;
497 }
498
499 zathura_document_t* document = zathura_page_get_document(page);
500 if (document == NULL) {
501 return ZATHURA_ERROR_UNKNOWN;
502 }
503
504 /* init ddjvu render data */
505 djvu_document_t* djvu_document = zathura_document_get_data(document);
506 ddjvu_page_t* djvu_page = ddjvu_page_create_by_pageno(djvu_document->document, zathura_page_get_index(page));
507
508 if (djvu_page == NULL) {
509 return ZATHURA_ERROR_UNKNOWN;
510 }
511
512 while (!ddjvu_page_decoding_done(djvu_page)) {
513 handle_messages(djvu_document, true);
514 }
515
516 cairo_surface_t* surface = cairo_get_target(cairo);
517
518 if (surface == NULL ||
519 cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ||
520 cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE) {
521 ddjvu_page_release(djvu_page);
522 return ZATHURA_ERROR_UNKNOWN;
523 }
524
525 unsigned int page_width = cairo_image_surface_get_width(surface);
526 unsigned int page_height = cairo_image_surface_get_height(surface);;
527
528 ddjvu_rect_t rrect = { 0, 0, page_width, page_height };
529 ddjvu_rect_t prect = { 0, 0, page_width, page_height };
530
531 char* surface_data = (char*) cairo_image_surface_get_data(surface);
532
533 if (surface_data == NULL) {
534 ddjvu_page_release(djvu_page);
535 return ZATHURA_ERROR_UNKNOWN;
536 }
537
538 /* render page */
539 ddjvu_page_render(djvu_page, DDJVU_RENDER_COLOR, &prect, &rrect,
540 djvu_document->format, cairo_image_surface_get_stride(surface), surface_data);
541
542 ddjvu_page_release(djvu_page);
543
544 return ZATHURA_ERROR_OK;
545 }
546
547 zathura_image_buffer_t*
djvu_page_render(zathura_page_t * page,void * UNUSED (data),zathura_error_t * error)548 djvu_page_render(zathura_page_t* page, void* UNUSED(data), zathura_error_t* error)
549 {
550 if (page == NULL) {
551 if (error != NULL) {
552 *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
553 }
554 return NULL;
555 }
556
557 zathura_document_t* document = zathura_page_get_document(page);
558 if (document == NULL) {
559 return NULL;
560 }
561
562 /* calculate sizes */
563 unsigned int page_width = zathura_document_get_scale(document) * zathura_page_get_width(page);
564 unsigned int page_height = zathura_document_get_scale(document) * zathura_page_get_height(page);
565
566 if (page_width == 0 || page_height == 0) {
567 if (error != NULL) {
568 *error = ZATHURA_ERROR_UNKNOWN;
569 }
570 goto error_out;
571 }
572
573 /* init ddjvu render data */
574 djvu_document_t* djvu_document = zathura_document_get_data(document);
575 ddjvu_page_t* djvu_page = ddjvu_page_create_by_pageno(
576 djvu_document->document, zathura_page_get_index(page));
577
578 if (djvu_page == NULL) {
579 if (error != NULL) {
580 *error = ZATHURA_ERROR_UNKNOWN;
581 }
582 goto error_out;
583 }
584
585 while (!ddjvu_page_decoding_done(djvu_page)) {
586 handle_messages(djvu_document, true);
587 }
588
589 ddjvu_rect_t rrect = { 0, 0, page_width, page_height };
590 ddjvu_rect_t prect = { 0, 0, page_width, page_height };
591
592 zathura_image_buffer_t* image_buffer =
593 zathura_image_buffer_create(page_width, page_height);
594
595 if (image_buffer == NULL) {
596 if (error != NULL) {
597 *error = ZATHURA_ERROR_OUT_OF_MEMORY;
598 }
599 goto error_free;
600 }
601
602 /* set rotation */
603 ddjvu_page_set_rotation(djvu_page, DDJVU_ROTATE_0);
604
605 /* render page */
606 ddjvu_page_render(djvu_page, DDJVU_RENDER_COLOR, &prect, &rrect,
607 djvu_document->format, 3 * page_width, (char*) image_buffer->data);
608
609 return image_buffer;
610
611 error_free:
612
613 ddjvu_page_release(djvu_page);
614 zathura_image_buffer_free(image_buffer);
615
616 error_out:
617
618 return NULL;
619 }
620
621 static const char*
get_extension(const char * path)622 get_extension(const char* path)
623 {
624 if (path == NULL) {
625 return NULL;
626 }
627
628 unsigned int i = strlen(path);
629 for (; i > 0; i--) {
630 if (*(path + i) != '.') {
631 continue;
632 } else {
633 break;
634 }
635 }
636
637 if (i == 0) {
638 return NULL;
639 }
640
641 return path + i + 1;
642 }
643
644 void
handle_messages(djvu_document_t * document,bool wait)645 handle_messages(djvu_document_t* document, bool wait)
646 {
647 if (document == NULL || document->context == NULL) {
648 return;
649 }
650
651 ddjvu_context_t* context = document->context;
652 const ddjvu_message_t* message;
653
654 if (wait == true) {
655 ddjvu_message_wait(context);
656 }
657
658 while ((message = ddjvu_message_peek(context)) != NULL) {
659 ddjvu_message_pop(context);
660 }
661 }
662
663 static void
build_index(djvu_document_t * djvu_document,miniexp_t expression,girara_tree_node_t * root)664 build_index(djvu_document_t *djvu_document, miniexp_t expression, girara_tree_node_t* root)
665 {
666 if (expression == miniexp_nil || root == NULL) {
667 return;
668 }
669
670 int fileno = ddjvu_document_get_filenum(djvu_document->document);
671 int curfile = 0;
672
673 while (miniexp_consp(expression) != 0) {
674 miniexp_t inner = miniexp_car(expression);
675
676 if (miniexp_consp(inner)
677 && miniexp_consp(miniexp_cdr(inner))
678 && miniexp_stringp(miniexp_car(inner))
679 && miniexp_stringp(miniexp_car(inner))
680 ) {
681 const char* name = miniexp_to_str(miniexp_car(inner));
682 const char* link = miniexp_to_str(miniexp_cadr(inner));
683
684 /* TODO: handle other links? */
685 if (link == NULL || link[0] != '#') {
686 expression = miniexp_cdr(expression);
687 continue;
688 }
689
690 zathura_link_type_t type = ZATHURA_LINK_GOTO_DEST;
691 zathura_rectangle_t rect = { 0 };
692 zathura_link_target_t target = { 0 };
693 target.destination_type = ZATHURA_LINK_DESTINATION_XYZ;
694
695 /* Check if link+1 contains a number */
696 bool number = true;
697 const size_t linklen = strlen(link);
698 for (unsigned int k = 1; k < linklen; k++) {
699 if (!isdigit(link[k])) {
700 number = false;
701 break;
702 }
703 }
704
705 /* if link starts with a number assume it is a number */
706 if (number == true) {
707 target.page_number = atoi(link + 1) - 1;
708 } else {
709 /* otherwise assume it is an id for a page */
710 ddjvu_fileinfo_t info;
711 int f, i;
712 for (i=0; i < fileno; i++) {
713 f = (curfile + i) % fileno;
714 ddjvu_document_get_fileinfo(djvu_document->document, f, &info);
715 if (info.id != NULL && !strcmp(link+1, info.id)) {
716 break;
717 }
718 }
719
720 /* got a page */
721 if (i < fileno && info.pageno >= 0) {
722 curfile = (f+1) % fileno;
723 target.page_number = info.pageno;
724 } else {
725 /* give up */
726 expression = miniexp_cdr(expression);
727 continue;
728 }
729 }
730
731 zathura_index_element_t* index_element = zathura_index_element_new(name);
732 if (index_element == NULL) {
733 continue;
734 }
735
736 index_element->link = zathura_link_new(type, rect, target);
737 if (index_element->link == NULL) {
738 zathura_index_element_free(index_element);
739 continue;
740 }
741
742 girara_tree_node_t* node = girara_node_append_data(root, index_element);
743
744 /* search recursive */
745 build_index(djvu_document, miniexp_cddr(inner), node);
746 }
747
748 expression = miniexp_cdr(expression);
749 }
750 }
751
752 static bool
exp_to_str(miniexp_t expression,const char ** string)753 exp_to_str(miniexp_t expression, const char** string)
754 {
755 if (string == NULL) {
756 return false;
757 }
758
759 if (miniexp_stringp(expression)) {
760 *string = miniexp_to_str(expression);
761 return true;
762 }
763
764 return false;
765 }
766
767 static bool
exp_to_int(miniexp_t expression,int * integer)768 exp_to_int(miniexp_t expression, int* integer)
769 {
770 if (integer == NULL) {
771 return false;
772 }
773
774 if (miniexp_numberp(expression)) {
775 *integer = miniexp_to_int(expression);
776 return true;
777 }
778
779 return false;
780 }
781
782 static bool
exp_to_rect(miniexp_t expression,zathura_rectangle_t * rect)783 exp_to_rect(miniexp_t expression, zathura_rectangle_t* rect)
784 {
785 if ((miniexp_car(expression) == miniexp_symbol("rect")
786 || miniexp_car(expression) == miniexp_symbol("oval"))
787 && miniexp_length(expression) == 5) {
788 int min_x = 0;
789 int min_y = 0;
790 int width = 0;
791 int height = 0;
792
793 miniexp_t iter = miniexp_cdr(expression);
794 if (exp_to_int(miniexp_car(iter), &min_x) == false) {
795 return false;
796 }
797 iter = miniexp_cdr(iter);
798 if (exp_to_int(miniexp_car(iter), &min_y) == false) {
799 return false;
800 }
801 iter = miniexp_cdr(iter);
802 if (exp_to_int(miniexp_car(iter), &width) == false) {
803 return false;
804 }
805 iter = miniexp_cdr(iter);
806 if (exp_to_int(miniexp_car(iter), &height) == false) {
807 return false;
808 }
809
810 rect->x1 = min_x;
811 rect->x2 = min_x + width;
812 rect->y1 = min_y;
813 rect->y2 = min_y + height;
814 } else if (miniexp_car(expression) == miniexp_symbol("poly")
815 && miniexp_length(expression) >= 5) {
816 int min_x = 0;
817 int min_y = 0;
818 int max_x = 0;
819 int max_y = 0;
820
821 miniexp_t iter = miniexp_cdr(expression);
822 while (iter != miniexp_nil) {
823 int x = 0;
824 int y = 0;
825
826 if (exp_to_int(miniexp_car(iter), &x) == false) {
827 return false;
828 }
829 iter = miniexp_cdr(iter);
830 if (exp_to_int(miniexp_car(iter), &y) == false) {
831 return false;
832 }
833 iter = miniexp_cdr(iter);
834
835 min_x = MIN(min_x, x);
836 min_y = MIN(min_y, y);
837 max_x = MAX(max_x, x);
838 max_y = MAX(max_y, y);
839 }
840
841 rect->x1 = min_x;
842 rect->x2 = max_x;
843 rect->y1 = min_y;
844 rect->y2 = max_y;
845 }
846
847 return true;
848 }
849