1 /* SPDX-License-Identifier: Zlib */
2 
3 #include <stdlib.h>
4 #include <string.h>
5 #include <limits.h>
6 #include <glib.h>
7 #include <gio/gio.h>
8 #include <math.h>
9 
10 #include <girara/datastructures.h>
11 #include <girara/utils.h>
12 
13 #include "adjustment.h"
14 #include "document.h"
15 #include "utils.h"
16 #include "zathura.h"
17 #include "page.h"
18 #include "plugin.h"
19 #include "content-type.h"
20 
21 /**
22  * Document
23  */
24 struct zathura_document_s {
25   char* file_path; /**< File path of the document */
26   char* uri; /**< URI of the document */
27   char* basename; /**< Basename of the document */
28   uint8_t hash_sha256[32]; /**< SHA256 hash of the document */
29   const char* password; /**< Password of the document */
30   unsigned int current_page_number; /**< Current page number */
31   unsigned int number_of_pages; /**< Number of pages */
32   double zoom; /**< Zoom value */
33   unsigned int rotate; /**< Rotation */
34   void* data; /**< Custom data */
35   zathura_adjust_mode_t adjust_mode; /**< Adjust mode (best-fit, width) */
36   int page_offset; /**< Page offset */
37   double cell_width; /**< width of a page cell in the document (not transformed by scale and rotation) */
38   double cell_height; /**< height of a page cell in the document (not transformed by scale and rotation) */
39   unsigned int view_width; /**< width of current viewport */
40   unsigned int view_height; /**< height of current viewport */
41   double view_ppi; /**< PPI of the current viewport */
42   zathura_device_factors_t device_factors; /**< x and y device scale factors (for e.g. HiDPI) */
43   unsigned int pages_per_row; /**< number of pages in a row */
44   unsigned int first_page_column; /**< column of the first page */
45   unsigned int page_padding; /**< padding between pages */
46   double position_x; /**< X adjustment */
47   double position_y; /**< Y adjustment */
48 
49   /**
50    * Document pages
51    */
52   zathura_page_t** pages;
53 
54   /**
55    * Used plugin
56    */
57   zathura_plugin_t* plugin;
58 };
59 
60 static void
check_set_error(zathura_error_t * error,zathura_error_t code)61 check_set_error(zathura_error_t* error, zathura_error_t code) {
62   if (error != NULL) {
63     *error = code;
64   }
65 }
66 
67 static bool
hash_file_sha256(uint8_t * dst,const char * path)68 hash_file_sha256(uint8_t* dst, const char* path)
69 {
70   FILE* f = fopen(path, "rb");
71   if (f == NULL) {
72     return false;
73   }
74 
75   GChecksum* checksum = g_checksum_new(G_CHECKSUM_SHA256);
76   if (checksum == NULL) {
77     fclose(f);
78     return false;
79   }
80 
81   uint8_t buf[BUFSIZ];
82   size_t read;
83   while ((read = fread(buf, 1, sizeof(buf), f)) != 0) {
84     g_checksum_update(checksum, buf, read);
85   }
86 
87   if (ferror(f) != 0) {
88     g_checksum_free(checksum);
89     fclose(f);
90     return false;
91   }
92 
93   fclose(f);
94   gsize dst_size = 32;
95   g_checksum_get_digest(checksum, dst, &dst_size);
96   g_checksum_free(checksum);
97   return true;
98 }
99 
100 zathura_document_t*
zathura_document_open(zathura_t * zathura,const char * path,const char * uri,const char * password,zathura_error_t * error)101 zathura_document_open(zathura_t* zathura, const char* path, const char* uri,
102                       const char* password, zathura_error_t* error)
103 {
104   if (zathura == NULL || path == NULL) {
105     return NULL;
106   }
107 
108   GFile* file = g_file_new_for_path(path);
109   char* real_path = NULL;
110   char* content_type = NULL;
111   zathura_plugin_t* plugin = NULL;
112   zathura_document_t* document = NULL;
113 
114   if (file == NULL) {
115     girara_error("Error while handling path '%s'.", path);
116     check_set_error(error, ZATHURA_ERROR_UNKNOWN);
117     goto error_free;
118   }
119 
120   real_path = g_file_get_path(file);
121   if (real_path == NULL) {
122     girara_error("Error while handling path '%s'.", path);
123     check_set_error(error, ZATHURA_ERROR_UNKNOWN);
124     goto error_free;
125   }
126 
127   content_type = zathura_content_type_guess(zathura->content_type_context, real_path, zathura_plugin_manager_get_content_types(zathura->plugins.manager));
128   if (content_type == NULL) {
129     girara_error("Could not determine file type.");
130     check_set_error(error, ZATHURA_ERROR_UNKNOWN);
131     goto error_free;
132   }
133 
134   plugin = zathura_plugin_manager_get_plugin(zathura->plugins.manager, content_type);
135   if (plugin == NULL) {
136     girara_error("Unknown file type: '%s'", content_type);
137     check_set_error(error, ZATHURA_ERROR_UNKNOWN);
138 
139     g_free((void*)content_type);
140     content_type = NULL;
141 
142     goto error_free;
143   }
144 
145   g_free(content_type);
146   content_type = NULL;
147 
148   document = g_try_malloc0(sizeof(zathura_document_t));
149   if (document == NULL) {
150     check_set_error(error, ZATHURA_ERROR_OUT_OF_MEMORY);
151     goto error_free;
152   }
153 
154   document->file_path   = real_path;
155   document->uri         = g_strdup(uri);
156   if (document->uri == NULL) {
157     document->basename    = g_file_get_basename(file);
158   } else {
159     GFile*gf = g_file_new_for_uri(document->uri);
160     document->basename = g_file_get_basename(gf);
161     g_object_unref(gf);
162   }
163   hash_file_sha256(document->hash_sha256, document->file_path);
164   document->password    = password;
165   document->zoom        = 1.0;
166   document->plugin      = plugin;
167   document->adjust_mode = ZATHURA_ADJUST_NONE;
168   document->cell_width  = 0.0;
169   document->cell_height = 0.0;
170   document->view_height = 0;
171   document->view_width  = 0;
172   document->view_ppi    = 0.0;
173   document->device_factors.x = 1.0;
174   document->device_factors.y = 1.0;
175   document->position_x  = 0.0;
176   document->position_y  = 0.0;
177 
178   real_path = NULL;
179   g_object_unref(file);
180   file = NULL;
181 
182   /* open document */
183   const zathura_plugin_functions_t* functions = zathura_plugin_get_functions(plugin);
184   if (functions->document_open == NULL) {
185     girara_error("plugin has no open function\n");
186     goto error_free;
187   }
188 
189   zathura_error_t int_error = functions->document_open(document);
190   if (int_error != ZATHURA_ERROR_OK) {
191     check_set_error(error, int_error);
192     girara_error("could not open document\n");
193     goto error_free;
194   }
195 
196   /* read all pages */
197   document->pages = calloc(document->number_of_pages, sizeof(zathura_page_t*));
198   if (document->pages == NULL) {
199     check_set_error(error, ZATHURA_ERROR_OUT_OF_MEMORY);
200     goto error_free;
201   }
202 
203   for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
204     zathura_page_t* page = zathura_page_new(document, page_id, NULL);
205     if (page == NULL) {
206       check_set_error(error, ZATHURA_ERROR_OUT_OF_MEMORY);
207       goto error_free;
208     }
209 
210     document->pages[page_id] = page;
211 
212     /* cell_width and cell_height is the maximum of all the pages width and height */
213     const double width = zathura_page_get_width(page);
214     if (document->cell_width < width)
215       document->cell_width = width;
216 
217     const double height = zathura_page_get_height(page);
218     if (document->cell_height < height)
219       document->cell_height = height;
220   }
221 
222   return document;
223 
224 error_free:
225 
226   if (file != NULL) {
227     g_object_unref(file);
228   }
229 
230   g_free(real_path);
231 
232   if (document != NULL) {
233     zathura_document_free(document);
234     document = NULL; /* prevent double-free */
235   }
236 
237   g_free(document);
238 
239   return NULL;
240 }
241 
242 zathura_error_t
zathura_document_free(zathura_document_t * document)243 zathura_document_free(zathura_document_t* document)
244 {
245   if (document == NULL || document->plugin == NULL) {
246     return ZATHURA_ERROR_INVALID_ARGUMENTS;
247   }
248 
249   if (document->pages != NULL) {
250     /* free pages */
251     for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
252       zathura_page_free(document->pages[page_id]);
253       document->pages[page_id] = NULL;
254     }
255     free(document->pages);
256   }
257 
258   /* free document */
259   zathura_error_t error = ZATHURA_ERROR_OK;
260   const zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
261   if (functions->document_free == NULL) {
262     error = ZATHURA_ERROR_NOT_IMPLEMENTED;
263   } else {
264     error = functions->document_free(document, document->data);
265   }
266 
267   g_free(document->file_path);
268   g_free(document->uri);
269   g_free(document->basename);
270 
271   g_free(document);
272 
273   return error;
274 }
275 
276 const char*
zathura_document_get_path(zathura_document_t * document)277 zathura_document_get_path(zathura_document_t* document)
278 {
279   if (document == NULL) {
280     return NULL;
281   }
282 
283   return document->file_path;
284 }
285 
286 const uint8_t*
zathura_document_get_hash(zathura_document_t * document)287 zathura_document_get_hash(zathura_document_t* document)
288 {
289   if (document == NULL) {
290     return NULL;
291   }
292 
293   return document->hash_sha256;
294 }
295 
296 const char*
zathura_document_get_uri(zathura_document_t * document)297 zathura_document_get_uri(zathura_document_t* document)
298 {
299   if (document == NULL) {
300     return NULL;
301   }
302 
303   return document->uri;
304 }
305 
306 const char*
zathura_document_get_basename(zathura_document_t * document)307 zathura_document_get_basename(zathura_document_t* document)
308 {
309   if (document == NULL) {
310     return NULL;
311   }
312 
313   return document->basename;
314 }
315 
316 const char*
zathura_document_get_password(zathura_document_t * document)317 zathura_document_get_password(zathura_document_t* document)
318 {
319   if (document == NULL) {
320     return NULL;
321   }
322 
323   return document->password;
324 }
325 
326 zathura_page_t*
zathura_document_get_page(zathura_document_t * document,unsigned int index)327 zathura_document_get_page(zathura_document_t* document, unsigned int index)
328 {
329   if (document == NULL || document->pages == NULL || (document->number_of_pages <= index)) {
330     return NULL;
331   }
332 
333   return document->pages[index];
334 }
335 
336 void*
zathura_document_get_data(zathura_document_t * document)337 zathura_document_get_data(zathura_document_t* document)
338 {
339   if (document == NULL) {
340     return NULL;
341   }
342 
343   return document->data;
344 }
345 
346 void
zathura_document_set_data(zathura_document_t * document,void * data)347 zathura_document_set_data(zathura_document_t* document, void* data)
348 {
349   if (document == NULL) {
350     return;
351   }
352 
353   document->data = data;
354 }
355 
356 unsigned int
zathura_document_get_number_of_pages(zathura_document_t * document)357 zathura_document_get_number_of_pages(zathura_document_t* document)
358 {
359   if (document == NULL) {
360     return 0;
361   }
362 
363   return document->number_of_pages;
364 }
365 
366 void
zathura_document_set_number_of_pages(zathura_document_t * document,unsigned int number_of_pages)367 zathura_document_set_number_of_pages(zathura_document_t* document, unsigned int number_of_pages)
368 {
369   if (document == NULL) {
370     return;
371   }
372 
373   document->number_of_pages = number_of_pages;
374 }
375 
376 unsigned int
zathura_document_get_current_page_number(zathura_document_t * document)377 zathura_document_get_current_page_number(zathura_document_t* document)
378 {
379   if (document == NULL) {
380     return 0;
381   }
382 
383   return document->current_page_number;
384 }
385 
386 void
zathura_document_set_current_page_number(zathura_document_t * document,unsigned int current_page)387 zathura_document_set_current_page_number(zathura_document_t* document, unsigned int
388     current_page)
389 {
390   if (document == NULL) {
391     return;
392   }
393 
394   document->current_page_number = current_page;
395 }
396 
397 double
zathura_document_get_position_x(zathura_document_t * document)398 zathura_document_get_position_x(zathura_document_t* document)
399 {
400   if (document == NULL) {
401     return 0;
402   }
403 
404   return document->position_x;
405 }
406 
407 double
zathura_document_get_position_y(zathura_document_t * document)408 zathura_document_get_position_y(zathura_document_t* document)
409 {
410   if (document == NULL) {
411     return 0;
412   }
413 
414   return document->position_y;
415 }
416 
417 void
zathura_document_set_position_x(zathura_document_t * document,double position_x)418 zathura_document_set_position_x(zathura_document_t* document, double position_x)
419 {
420   if (document == NULL) {
421     return;
422   }
423 
424   document->position_x = position_x;
425 }
426 
427 void
zathura_document_set_position_y(zathura_document_t * document,double position_y)428 zathura_document_set_position_y(zathura_document_t* document, double position_y)
429 {
430   if (document == NULL) {
431     return;
432   }
433 
434   document->position_y = position_y;
435 }
436 
437 double
zathura_document_get_zoom(zathura_document_t * document)438 zathura_document_get_zoom(zathura_document_t* document)
439 {
440   if (document == NULL) {
441     return 0;
442   }
443 
444   return document->zoom;
445 }
446 
447 void
zathura_document_set_zoom(zathura_document_t * document,double zoom)448 zathura_document_set_zoom(zathura_document_t* document, double zoom)
449 {
450   if (document == NULL) {
451     return;
452   }
453 
454   document->zoom = zoom;
455 }
456 
457 double
zathura_document_get_scale(zathura_document_t * document)458 zathura_document_get_scale(zathura_document_t* document)
459 {
460   if (document == NULL) {
461     return 0;
462   }
463 
464   double ppi = document->view_ppi;
465   if (ppi < DBL_EPSILON) {
466     /* No PPI information -> use a typical value */
467     ppi = 100;
468   }
469 
470   /* scale = pixels per point, and there are 72 points in one inch */
471   return document->zoom * ppi / 72.0;
472 }
473 
474 unsigned int
zathura_document_get_rotation(zathura_document_t * document)475 zathura_document_get_rotation(zathura_document_t* document)
476 {
477   if (document == NULL) {
478     return 0;
479   }
480 
481   return document->rotate;
482 }
483 
484 void
zathura_document_set_rotation(zathura_document_t * document,unsigned int rotation)485 zathura_document_set_rotation(zathura_document_t* document, unsigned int rotation)
486 {
487   if (document == NULL) {
488     return;
489   }
490 
491   rotation = rotation % 360;
492   if (rotation == 0 || rotation > 270) {
493     document->rotate = 0;
494   } else if (rotation <= 90) {
495     document->rotate = 90;
496   } else if (rotation <= 180) {
497     document->rotate = 180;
498   } else {
499     document->rotate = 270;
500   }
501 }
502 
503 zathura_adjust_mode_t
zathura_document_get_adjust_mode(zathura_document_t * document)504 zathura_document_get_adjust_mode(zathura_document_t* document)
505 {
506   if (document == NULL) {
507     return ZATHURA_ADJUST_NONE;
508   }
509 
510   return document->adjust_mode;
511 }
512 
513 void
zathura_document_set_adjust_mode(zathura_document_t * document,zathura_adjust_mode_t mode)514 zathura_document_set_adjust_mode(zathura_document_t* document, zathura_adjust_mode_t mode)
515 {
516   if (document == NULL) {
517     return;
518   }
519 
520   document->adjust_mode = mode;
521 }
522 
523 int
zathura_document_get_page_offset(zathura_document_t * document)524 zathura_document_get_page_offset(zathura_document_t* document)
525 {
526   if (document == NULL) {
527     return 0;
528   }
529 
530   return document->page_offset;
531 }
532 
533 void
zathura_document_set_page_offset(zathura_document_t * document,unsigned int page_offset)534 zathura_document_set_page_offset(zathura_document_t* document, unsigned int page_offset)
535 {
536   if (document == NULL) {
537     return;
538   }
539 
540   document->page_offset = page_offset;
541 }
542 
543 void
zathura_document_set_viewport_width(zathura_document_t * document,unsigned int width)544 zathura_document_set_viewport_width(zathura_document_t* document, unsigned int width)
545 {
546   if (document == NULL) {
547     return;
548   }
549   document->view_width = width;
550 }
551 
552 void
zathura_document_set_viewport_height(zathura_document_t * document,unsigned int height)553 zathura_document_set_viewport_height(zathura_document_t* document, unsigned int height)
554 {
555   if (document == NULL) {
556     return;
557   }
558   document->view_height = height;
559 }
560 
561 void
zathura_document_set_viewport_ppi(zathura_document_t * document,double ppi)562 zathura_document_set_viewport_ppi(zathura_document_t* document, double ppi)
563 {
564   if (document == NULL) {
565     return;
566   }
567   document->view_ppi = ppi;
568 }
569 
570 void
zathura_document_get_viewport_size(zathura_document_t * document,unsigned int * height,unsigned int * width)571 zathura_document_get_viewport_size(zathura_document_t* document,
572                                    unsigned int *height, unsigned int* width)
573 {
574   g_return_if_fail(document != NULL && height != NULL && width != NULL);
575   *height = document->view_height;
576   *width = document->view_width;
577 }
578 
579 double
zathura_document_get_viewport_ppi(zathura_document_t * document)580 zathura_document_get_viewport_ppi(zathura_document_t* document)
581 {
582   if (document == NULL) {
583     return 0.0;
584   }
585   return document->view_ppi;
586 }
587 
588 void
zathura_document_set_device_factors(zathura_document_t * document,double x_factor,double y_factor)589 zathura_document_set_device_factors(zathura_document_t* document,
590                                     double x_factor, double y_factor)
591 {
592   if (document == NULL) {
593     return;
594   }
595   if (fabs(x_factor) < DBL_EPSILON || fabs(y_factor) < DBL_EPSILON) {
596     girara_debug("Ignoring new device factors %0.2f and %0.2f: too small",
597         x_factor, y_factor);
598     return;
599   }
600 
601   document->device_factors.x = x_factor;
602   document->device_factors.y = y_factor;
603 }
604 
605 zathura_device_factors_t
zathura_document_get_device_factors(zathura_document_t * document)606 zathura_document_get_device_factors(zathura_document_t* document)
607 {
608   if (document == NULL) {
609     /* The function is guaranteed to not return zero values */
610     return (zathura_device_factors_t){1.0, 1.0};
611   }
612 
613   return document->device_factors;
614 }
615 
616 void
zathura_document_get_cell_size(zathura_document_t * document,unsigned int * height,unsigned int * width)617 zathura_document_get_cell_size(zathura_document_t* document,
618                                unsigned int* height, unsigned int* width)
619 {
620   g_return_if_fail(document != NULL && height != NULL && width != NULL);
621 
622   page_calc_height_width(document, document->cell_height, document->cell_width,
623                          height, width, true);
624 }
625 
626 void
zathura_document_get_document_size(zathura_document_t * document,unsigned int * height,unsigned int * width)627 zathura_document_get_document_size(zathura_document_t* document,
628                                    unsigned int* height, unsigned int* width)
629 {
630   g_return_if_fail(document != NULL && height != NULL && width != NULL);
631 
632   const unsigned int npag = zathura_document_get_number_of_pages(document);
633   const unsigned int ncol = zathura_document_get_pages_per_row(document);
634 
635   if (npag == 0 || ncol == 0) {
636     return;
637   }
638 
639   const unsigned int c0    = zathura_document_get_first_page_column(document);
640   const unsigned int nrow  = (npag + c0 - 1 + ncol - 1) / ncol;  /* number of rows */
641   const unsigned int pad   = zathura_document_get_page_padding(document);
642 
643   unsigned int cell_height = 0;
644   unsigned int cell_width  = 0;
645   zathura_document_get_cell_size(document, &cell_height, &cell_width);
646 
647   *width  = ncol * cell_width + (ncol - 1) * pad;
648   *height = nrow * cell_height + (nrow - 1) * pad;
649 }
650 
651 void
zathura_document_set_page_layout(zathura_document_t * document,unsigned int page_padding,unsigned int pages_per_row,unsigned int first_page_column)652 zathura_document_set_page_layout(zathura_document_t* document, unsigned int page_padding,
653                                  unsigned int pages_per_row, unsigned int first_page_column)
654 {
655   g_return_if_fail(document != NULL);
656 
657   document->page_padding = page_padding;
658   document->pages_per_row = pages_per_row;
659 
660   if (first_page_column < 1) {
661     first_page_column = 1;
662   } else if (first_page_column > pages_per_row) {
663     first_page_column = ((first_page_column - 1) % pages_per_row) + 1;
664   }
665 
666   document->first_page_column = first_page_column;
667 }
668 
669 unsigned int
zathura_document_get_page_padding(zathura_document_t * document)670 zathura_document_get_page_padding(zathura_document_t* document)
671 {
672   if (document == NULL) {
673     return 0;
674   }
675   return document->page_padding;
676 }
677 
678 unsigned int
zathura_document_get_pages_per_row(zathura_document_t * document)679 zathura_document_get_pages_per_row(zathura_document_t* document)
680 {
681   if (document == NULL) {
682     return 0;
683   }
684   return document->pages_per_row;
685 }
686 
687 unsigned int
zathura_document_get_first_page_column(zathura_document_t * document)688 zathura_document_get_first_page_column(zathura_document_t* document)
689 {
690   if (document == NULL) {
691     return 0;
692   }
693   return document->first_page_column;
694 }
695 
696 zathura_error_t
zathura_document_save_as(zathura_document_t * document,const char * path)697 zathura_document_save_as(zathura_document_t* document, const char* path)
698 {
699   if (document == NULL || document->plugin == NULL || path == NULL) {
700     return ZATHURA_ERROR_UNKNOWN;
701   }
702 
703   const zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
704   if (functions->document_save_as == NULL) {
705     return ZATHURA_ERROR_NOT_IMPLEMENTED;
706   }
707 
708   return functions->document_save_as(document, document->data, path);
709 }
710 
711 girara_tree_node_t*
zathura_document_index_generate(zathura_document_t * document,zathura_error_t * error)712 zathura_document_index_generate(zathura_document_t* document, zathura_error_t* error)
713 {
714   if (document == NULL || document->plugin == NULL) {
715     check_set_error(error, ZATHURA_ERROR_INVALID_ARGUMENTS);
716     return NULL;
717   }
718 
719   const zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
720   if (functions->document_index_generate == NULL) {
721     check_set_error(error, ZATHURA_ERROR_NOT_IMPLEMENTED);
722     return NULL;
723   }
724 
725   return functions->document_index_generate(document, document->data, error);
726 }
727 
728 girara_list_t*
zathura_document_attachments_get(zathura_document_t * document,zathura_error_t * error)729 zathura_document_attachments_get(zathura_document_t* document, zathura_error_t* error)
730 {
731   if (document == NULL || document->plugin == NULL) {
732     check_set_error(error, ZATHURA_ERROR_INVALID_ARGUMENTS);
733     return NULL;
734   }
735 
736   const zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
737   if (functions->document_attachments_get == NULL) {
738     check_set_error(error, ZATHURA_ERROR_NOT_IMPLEMENTED);
739     return NULL;
740   }
741 
742   return functions->document_attachments_get(document, document->data, error);
743 }
744 
745 zathura_error_t
zathura_document_attachment_save(zathura_document_t * document,const char * attachment,const char * file)746 zathura_document_attachment_save(zathura_document_t* document, const char* attachment, const char* file)
747 {
748   if (document == NULL || document->plugin == NULL) {
749     return ZATHURA_ERROR_INVALID_ARGUMENTS;
750   }
751 
752   const zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
753   if (functions->document_attachment_save == NULL) {
754     return ZATHURA_ERROR_NOT_IMPLEMENTED;
755   }
756 
757   return functions->document_attachment_save(document, document->data, attachment, file);
758 }
759 
760 girara_list_t*
zathura_document_get_information(zathura_document_t * document,zathura_error_t * error)761 zathura_document_get_information(zathura_document_t* document, zathura_error_t* error)
762 {
763   if (document == NULL || document->plugin == NULL) {
764     check_set_error(error, ZATHURA_ERROR_INVALID_ARGUMENTS);
765     return NULL;
766   }
767 
768   const zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
769   if (functions->document_get_information == NULL) {
770     check_set_error(error, ZATHURA_ERROR_NOT_IMPLEMENTED);
771     return NULL;
772   }
773 
774   girara_list_t* result = functions->document_get_information(document, document->data, error);
775   if (result != NULL) {
776     girara_list_set_free_function(result, (girara_free_function_t) zathura_document_information_entry_free);
777   }
778 
779   return result;
780 }
781 
782 zathura_plugin_t*
zathura_document_get_plugin(zathura_document_t * document)783 zathura_document_get_plugin(zathura_document_t* document)
784 {
785   if (document == NULL) {
786     return NULL;
787   }
788 
789   return document->plugin;
790 }
791