document.c 12 KB
Newer Older
Moritz Lipp's avatar
Moritz Lipp committed
1
2
/* See LICENSE file for license and copyright information */

Moritz Lipp's avatar
Moritz Lipp committed
3
4
5
6
#define _BSD_SOURCE
#define _XOPEN_SOURCE 500
// TODO: Implement realpath

Moritz Lipp's avatar
Moritz Lipp committed
7
#include <stdlib.h>
Moritz Lipp's avatar
Moritz Lipp committed
8
#include <stdio.h>
Moritz Lipp's avatar
Moritz Lipp committed
9
#include <string.h>
Moritz Lipp's avatar
Moritz Lipp committed
10
#include <limits.h>
Moritz Lipp's avatar
Moritz Lipp committed
11
12
13
#include <sys/types.h>
#include <dirent.h>
#include <dlfcn.h>
Moritz Lipp's avatar
Moritz Lipp committed
14
15

#include "document.h"
16
17
#include "utils.h"
#include "zathura.h"
Moritz Lipp's avatar
Moritz Lipp committed
18
19
20

#define LENGTH(x) (sizeof(x)/sizeof((x)[0]))

21
22
zathura_document_plugin_t* zathura_document_plugins = NULL;

Moritz Lipp's avatar
Moritz Lipp committed
23
24
25
26
27
28
29
30
31
32
33
34
35
void
zathura_document_plugins_load(void)
{
  /* read all files in the plugin directory */
  DIR* dir = opendir(PLUGIN_DIR);
  if (dir == NULL) {
    fprintf(stderr, "error: could not open plugin directory: %s\n", PLUGIN_DIR);
    return;
  }

  struct dirent* entry;
  while ((entry = readdir(dir)) != NULL) {
    /* check if entry is a file */
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    if (entry->d_type != 0x8) {
      continue;
    }

    void* handle                      = NULL;
    zathura_document_plugin_t* plugin = NULL;
    char* path                        = NULL;

    /* get full path */
    path = string_concat(PLUGIN_DIR, "/", entry->d_name, NULL);

    if (path == NULL) {
      goto error_continue;
    }

    /* load plugin */
    handle = dlopen(path, RTLD_NOW);
Moritz Lipp's avatar
Moritz Lipp committed
53

54
55
56
57
58
59
60
61
    if (handle == NULL) {
      fprintf(stderr, "error: could not load plugin (%s)\n", dlerror());
      goto error_free;
    }

    /* resolve symbol */
    zathura_plugin_register_service_t register_plugin;
    *(void**)(&register_plugin) = dlsym(handle, PLUGIN_REGISTER_FUNCTION);
Moritz Lipp's avatar
Moritz Lipp committed
62

63
64
65
66
    if (register_plugin == NULL) {
      fprintf(stderr, "error: could not find '%s' function in the plugin\n", PLUGIN_REGISTER_FUNCTION);
      goto error_free;
    }
Moritz Lipp's avatar
Moritz Lipp committed
67

68
    plugin = malloc(sizeof(zathura_document_plugin_t));
Moritz Lipp's avatar
Moritz Lipp committed
69

70
71
72
    if (plugin == NULL) {
      goto error_free;
    }
Moritz Lipp's avatar
Moritz Lipp committed
73

74
75
    plugin->file_extension = NULL;
    plugin->open_function  = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
76

77
    register_plugin(plugin);
Moritz Lipp's avatar
Moritz Lipp committed
78

79
    bool r = zathura_document_plugin_register(plugin, handle);
Moritz Lipp's avatar
Moritz Lipp committed
80

81
82
83
    if (r == false) {
      fprintf(stderr, "error: could not register plugin (%s)\n", path);
      goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
84
    }
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

    free(path);

    continue;

error_free:

    free(path);
    free(plugin);

    if (handle) {
      dlclose(handle);
    }

error_continue:

    continue;
Moritz Lipp's avatar
Moritz Lipp committed
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  }

  if (closedir(dir) == -1) {
    fprintf(stderr, "error: could not close plugin directory: %s\n", PLUGIN_DIR);
  }
}

void
zathura_document_plugins_free(void)
{
  /* free registered plugins */
  zathura_document_plugin_t* plugin = zathura_document_plugins;
  while (plugin) {
    zathura_document_plugin_t* tmp = plugin->next;
Moritz Lipp's avatar
Moritz Lipp committed
116
    free(plugin->file_extension);
Moritz Lipp's avatar
Moritz Lipp committed
117
118
119
120
121
122
123
    free(plugin);
    plugin = tmp;
  }

  zathura_document_plugins = NULL;
}

124
bool
125
zathura_document_plugin_register(zathura_document_plugin_t* new_plugin, void* handle)
126
{
127
  if( (new_plugin == NULL) || (new_plugin->file_extension == NULL) || (new_plugin->open_function == NULL)
128
      || (handle == NULL) ) {
129
130
131
132
133
134
135
    fprintf(stderr, "plugin: could not register\n");
    return false;
  }

  /* search existing plugins */
  zathura_document_plugin_t* plugin = zathura_document_plugins;
  while (plugin) {
136
137
    if (!strcmp(plugin->file_extension, new_plugin->file_extension)) {
      fprintf(stderr, "plugin: already registered for filetype %s\n", plugin->file_extension);
138
139
140
141
142
143
144
145
146
147
148
      return false;
    }

    if (plugin->next == NULL) {
      break;
    }

    plugin = plugin->next;
  }

  /* create new plugin */
149
150
  new_plugin->handle = handle;
  new_plugin->next   = NULL;
151
152
153
154
155
156
157
158
159
160
161

  /* append to list */
  if (plugin == NULL) {
    zathura_document_plugins = new_plugin;
  } else {
    plugin->next = new_plugin;
  }

  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
162
zathura_document_t*
Moritz Lipp's avatar
Moritz Lipp committed
163
zathura_document_open(const char* path, const char* password)
Moritz Lipp's avatar
Moritz Lipp committed
164
{
Moritz Lipp's avatar
Moritz Lipp committed
165
  if (!path) {
Moritz Lipp's avatar
Moritz Lipp committed
166
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
167
168
  }

Moritz Lipp's avatar
Moritz Lipp committed
169
  if (!file_exists(path)) {
Moritz Lipp's avatar
Moritz Lipp committed
170
    fprintf(stderr, "error: file does not exist\n");
Moritz Lipp's avatar
Moritz Lipp committed
171
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
172
173
174
  }

  const char* file_extension = file_get_extension(path);
Moritz Lipp's avatar
Moritz Lipp committed
175
  if (!file_extension) {
Moritz Lipp's avatar
Moritz Lipp committed
176
    fprintf(stderr, "error: could not determine file type\n");
Moritz Lipp's avatar
Moritz Lipp committed
177
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
178
179
  }

Moritz Lipp's avatar
Moritz Lipp committed
180
181
182
183
184
185
  /* determine real path */
  size_t path_max;
#ifdef PATH_MAX
  path_max = PATH_MAX;
#else
  path_max = pathconf(path,_PC_PATH_MAX);
Moritz Lipp's avatar
Moritz Lipp committed
186
  if (path_max <= 0)
Moritz Lipp's avatar
Moritz Lipp committed
187
188
189
    path_max = 4096;
#endif

Moritz Lipp's avatar
Moritz Lipp committed
190
191
192
193
  char* real_path              = NULL;
  zathura_document_t* document = NULL;

  real_path = malloc(sizeof(char) * path_max);
Moritz Lipp's avatar
Moritz Lipp committed
194
  if (!real_path) {
Moritz Lipp's avatar
Moritz Lipp committed
195
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
196
197
  }

Moritz Lipp's avatar
Moritz Lipp committed
198
  if (!realpath(path, real_path)) {
Moritz Lipp's avatar
Moritz Lipp committed
199
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
200
201
  }

Moritz Lipp's avatar
Moritz Lipp committed
202
  document = malloc(sizeof(zathura_document_t));
Moritz Lipp's avatar
Moritz Lipp committed
203
  if (!document) {
Moritz Lipp's avatar
Moritz Lipp committed
204
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
205
206
  }

Moritz Lipp's avatar
Moritz Lipp committed
207
  document->file_path           = real_path;
Moritz Lipp's avatar
Moritz Lipp committed
208
209
210
  document->password            = password;
  document->current_page_number = 0;
  document->number_of_pages     = 0;
Moritz Lipp's avatar
Moritz Lipp committed
211
  document->scale               = 1.0;
Moritz Lipp's avatar
Moritz Lipp committed
212
  document->rotate              = 0;
Moritz Lipp's avatar
Moritz Lipp committed
213
  document->data                = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
214
  document->pages               = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
215
216
217
218
219
220
221
222
223
224
225
226
227

  document->functions.document_free            = NULL;
  document->functions.document_index_generate  = NULL;
  document->functions.document_save_as         = NULL;
  document->functions.document_attachments_get = NULL;
  document->functions.page_get                 = NULL;
  document->functions.page_free                = NULL;
  document->functions.page_search_text         = NULL;
  document->functions.page_links_get           = NULL;
  document->functions.page_form_fields_get     = NULL;
  document->functions.page_render              = NULL;

  /* init plugin with associated file type */
228
229
230
231
232
  zathura_document_plugin_t* plugin = zathura_document_plugins;
  while (plugin) {
    if (!strcmp(file_extension, plugin->file_extension)) {
      if (plugin->open_function) {
        if (plugin->open_function(document)) {
Moritz Lipp's avatar
Moritz Lipp committed
233
          /* update statusbar */
Moritz Lipp's avatar
Moritz Lipp committed
234
          girara_statusbar_item_set_text(Zathura.UI.session, Zathura.UI.statusbar.file, real_path);
Moritz Lipp's avatar
Moritz Lipp committed
235
236
237

          /* read all pages */
          document->pages = calloc(document->number_of_pages, sizeof(zathura_page_t*));
Moritz Lipp's avatar
Moritz Lipp committed
238
          if (!document->pages) {
Moritz Lipp's avatar
Moritz Lipp committed
239
240
241
            goto error_free;
          }

242
          for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
Moritz Lipp's avatar
Moritz Lipp committed
243
            zathura_page_t* page = zathura_page_get(document, page_id);
Moritz Lipp's avatar
Moritz Lipp committed
244
            if (!page) {
Moritz Lipp's avatar
Moritz Lipp committed
245
246
247
248
249
250
              goto error_free;
            }

            document->pages[page_id] = page;
          }

Moritz Lipp's avatar
Moritz Lipp committed
251
          return document;
Moritz Lipp's avatar
Moritz Lipp committed
252
253
        } else {
          fprintf(stderr, "error: could not open file\n");
Moritz Lipp's avatar
Moritz Lipp committed
254
          goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
255
256
257
        }
      }
    }
258
259

    plugin = plugin->next;
Moritz Lipp's avatar
Moritz Lipp committed
260
261
  }

Moritz Lipp's avatar
Moritz Lipp committed
262
263
  fprintf(stderr, "error: unknown file type\n");

Moritz Lipp's avatar
Moritz Lipp committed
264
265
error_free:

Moritz Lipp's avatar
Moritz Lipp committed
266
  free(real_path);
Moritz Lipp's avatar
Moritz Lipp committed
267

Moritz Lipp's avatar
Moritz Lipp committed
268
269
  if (document && document->pages) {
    for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++)
Moritz Lipp's avatar
Moritz Lipp committed
270
271
272
273
274
275
276
    {
      zathura_page_free(document->pages[page_id]);
    }

    free(document->pages);
  }

Moritz Lipp's avatar
Moritz Lipp committed
277
278
  free(document);

Moritz Lipp's avatar
Moritz Lipp committed
279
280
error_out:

Moritz Lipp's avatar
Moritz Lipp committed
281
282
283
  return NULL;
}

Moritz Lipp's avatar
Moritz Lipp committed
284
285
bool
zathura_document_free(zathura_document_t* document)
Moritz Lipp's avatar
Moritz Lipp committed
286
{
Moritz Lipp's avatar
Moritz Lipp committed
287
  if (!document) {
Moritz Lipp's avatar
Moritz Lipp committed
288
    return false;
Moritz Lipp's avatar
Moritz Lipp committed
289
290
  }

Moritz Lipp's avatar
Moritz Lipp committed
291
  /* free pages */
Moritz Lipp's avatar
Moritz Lipp committed
292
  for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++)
Moritz Lipp's avatar
Moritz Lipp committed
293
294
295
296
297
298
299
  {
    zathura_page_free(document->pages[page_id]);
  }

  free(document->pages);

  /* free document */
Moritz Lipp's avatar
Moritz Lipp committed
300
  if (!document->functions.document_free) {
Moritz Lipp's avatar
Moritz Lipp committed
301
    fprintf(stderr, "error: %s not implemented\n", __FUNCTION__);
Moritz Lipp's avatar
Moritz Lipp committed
302

Moritz Lipp's avatar
Moritz Lipp committed
303
    if (document->file_path) {
Moritz Lipp's avatar
Moritz Lipp committed
304
305
306
      free(document->file_path);
    }

Moritz Lipp's avatar
Moritz Lipp committed
307
308
    free(document);
    return true;
Moritz Lipp's avatar
Moritz Lipp committed
309
310
  }

Moritz Lipp's avatar
Moritz Lipp committed
311
312
  bool r = document->functions.document_free(document);

Moritz Lipp's avatar
Moritz Lipp committed
313
  if (document->file_path) {
Moritz Lipp's avatar
Moritz Lipp committed
314
315
316
    free(document->file_path);
  }

Moritz Lipp's avatar
Moritz Lipp committed
317
318
319
  free(document);

  return r;
Moritz Lipp's avatar
Moritz Lipp committed
320
321
322
323
324
}

bool
zathura_document_save_as(zathura_document_t* document, const char* path)
{
Moritz Lipp's avatar
Moritz Lipp committed
325
  if (!document || !path) {
Moritz Lipp's avatar
Moritz Lipp committed
326
327
328
    return false;
  }

Moritz Lipp's avatar
Moritz Lipp committed
329
  if (!document->functions.document_save_as) {
Moritz Lipp's avatar
Moritz Lipp committed
330
331
332
333
334
    fprintf(stderr, "error: %s not implemented\n", __FUNCTION__);
    return false;
  }

  return document->functions.document_save_as(document, path);
Moritz Lipp's avatar
Moritz Lipp committed
335
336
}

337
girara_tree_node_t*
Moritz Lipp's avatar
Moritz Lipp committed
338
zathura_document_index_generate(zathura_document_t* document)
Moritz Lipp's avatar
Moritz Lipp committed
339
{
Moritz Lipp's avatar
Moritz Lipp committed
340
  if (!document) {
Moritz Lipp's avatar
Moritz Lipp committed
341
342
343
    return NULL;
  }

Moritz Lipp's avatar
Moritz Lipp committed
344
  if (!document->functions.document_index_generate) {
Moritz Lipp's avatar
Moritz Lipp committed
345
346
347
348
349
    fprintf(stderr, "error: %s not implemented\n", __FUNCTION__);
    return NULL;
  }

  return document->functions.document_index_generate(document);
Moritz Lipp's avatar
Moritz Lipp committed
350
351
352
}

zathura_list_t*
Moritz Lipp's avatar
Moritz Lipp committed
353
zathura_document_attachments_get(zathura_document_t* document)
Moritz Lipp's avatar
Moritz Lipp committed
354
{
Moritz Lipp's avatar
Moritz Lipp committed
355
  if (!document) {
Moritz Lipp's avatar
Moritz Lipp committed
356
357
358
    return NULL;
  }

Moritz Lipp's avatar
Moritz Lipp committed
359
  if (!document->functions.document_attachments_get) {
Moritz Lipp's avatar
Moritz Lipp committed
360
361
362
363
364
    fprintf(stderr, "error: %s not implemented\n", __FUNCTION__);
    return NULL;
  }

  return document->functions.document_attachments_get(document);
Moritz Lipp's avatar
Moritz Lipp committed
365
366
367
}

bool
Moritz Lipp's avatar
Moritz Lipp committed
368
zathura_document_attachments_free(zathura_list_t* list)
Moritz Lipp's avatar
Moritz Lipp committed
369
370
371
372
{
  return false;
}

Moritz Lipp's avatar
Moritz Lipp committed
373
zathura_page_t*
374
zathura_page_get(zathura_document_t* document, unsigned int page_id)
Moritz Lipp's avatar
Moritz Lipp committed
375
{
Moritz Lipp's avatar
Moritz Lipp committed
376
  if (!document) {
Moritz Lipp's avatar
Moritz Lipp committed
377
378
379
    return NULL;
  }

Moritz Lipp's avatar
Moritz Lipp committed
380
  if (!document->functions.page_get) {
Moritz Lipp's avatar
Moritz Lipp committed
381
382
383
384
    fprintf(stderr, "error: %s not implemented\n", __FUNCTION__);
    return NULL;
  }

385
386
  zathura_page_t* page = document->functions.page_get(document, page_id);

Moritz Lipp's avatar
Moritz Lipp committed
387
  if (page) {
Moritz Lipp's avatar
Moritz Lipp committed
388
389
390
391
392
393
394
    page->number       = page_id;
    page->rendered     = false;
    page->event_box    = gtk_event_box_new();
    page->drawing_area = gtk_drawing_area_new();

    gtk_container_add(GTK_CONTAINER(page->event_box), page->drawing_area);

395
396
397
398
    g_static_mutex_init(&(page->lock));
  }

  return page;
Moritz Lipp's avatar
Moritz Lipp committed
399
400
}

Moritz Lipp's avatar
Moritz Lipp committed
401
402
403
bool
zathura_page_free(zathura_page_t* page)
{
Moritz Lipp's avatar
Moritz Lipp committed
404
  if (!page || !page->document) {
Moritz Lipp's avatar
Moritz Lipp committed
405
406
407
    return false;
  }

Moritz Lipp's avatar
Moritz Lipp committed
408
  if (!page->document->functions.page_free) {
Moritz Lipp's avatar
Moritz Lipp committed
409
410
411
412
413
414
415
    fprintf(stderr, "error: %s not implemented\n", __FUNCTION__);
    return false;
  }

  return page->document->functions.page_free(page);
}

Moritz Lipp's avatar
Moritz Lipp committed
416
zathura_list_t*
Moritz Lipp's avatar
Moritz Lipp committed
417
zathura_page_search_text(zathura_page_t* page, const char* text)
Moritz Lipp's avatar
Moritz Lipp committed
418
{
Moritz Lipp's avatar
Moritz Lipp committed
419
  if (!page || !page->document || !text) {
Moritz Lipp's avatar
Moritz Lipp committed
420
421
422
    return NULL;
  }

Moritz Lipp's avatar
Moritz Lipp committed
423
  if (!page->document->functions.page_search_text) {
Moritz Lipp's avatar
Moritz Lipp committed
424
425
426
427
428
    fprintf(stderr, "error: %s not implemented\n", __FUNCTION__);
    return NULL;
  }

  return page->document->functions.page_search_text(page, text);
Moritz Lipp's avatar
Moritz Lipp committed
429
430
}

Moritz Lipp's avatar
Moritz Lipp committed
431
432
zathura_list_t*
zathura_page_links_get(zathura_page_t* page)
Moritz Lipp's avatar
Moritz Lipp committed
433
{
Moritz Lipp's avatar
Moritz Lipp committed
434
  if (!page || !page->document) {
Moritz Lipp's avatar
Moritz Lipp committed
435
436
437
    return NULL;
  }

Moritz Lipp's avatar
Moritz Lipp committed
438
  if (!page->document->functions.page_links_get) {
Moritz Lipp's avatar
Moritz Lipp committed
439
440
441
442
443
    fprintf(stderr, "error: %s not implemented\n", __FUNCTION__);
    return NULL;
  }

  return page->document->functions.page_links_get(page);
Moritz Lipp's avatar
Moritz Lipp committed
444
445
446
}

bool
Moritz Lipp's avatar
Moritz Lipp committed
447
zathura_page_links_free(zathura_list_t* list)
Moritz Lipp's avatar
Moritz Lipp committed
448
449
450
451
452
{
  return false;
}

zathura_list_t*
Moritz Lipp's avatar
Moritz Lipp committed
453
zathura_page_form_fields_get(zathura_page_t* page)
Moritz Lipp's avatar
Moritz Lipp committed
454
{
Moritz Lipp's avatar
Moritz Lipp committed
455
  if (!page || !page->document) {
Moritz Lipp's avatar
Moritz Lipp committed
456
457
458
    return NULL;
  }

Moritz Lipp's avatar
Moritz Lipp committed
459
  if (!page->document->functions.page_form_fields_get) {
Moritz Lipp's avatar
Moritz Lipp committed
460
461
462
463
464
    fprintf(stderr, "error: %s not implemented\n", __FUNCTION__);
    return NULL;
  }

  return page->document->functions.page_form_fields_get(page);
Moritz Lipp's avatar
Moritz Lipp committed
465
466
467
}

bool
Moritz Lipp's avatar
Moritz Lipp committed
468
zathura_page_form_fields_free(zathura_list_t* list)
Moritz Lipp's avatar
Moritz Lipp committed
469
470
471
{
  return false;
}
Moritz Lipp's avatar
Moritz Lipp committed
472

473
zathura_image_buffer_t*
Moritz Lipp's avatar
Moritz Lipp committed
474
475
zathura_page_render(zathura_page_t* page)
{
Moritz Lipp's avatar
Moritz Lipp committed
476
  if (!page || !page->document) {
Moritz Lipp's avatar
Moritz Lipp committed
477
478
479
    return NULL;
  }

Moritz Lipp's avatar
Moritz Lipp committed
480
  if (!page->document->functions.page_render) {
Moritz Lipp's avatar
Moritz Lipp committed
481
482
483
484
    fprintf(stderr, "error: %s not implemented\n", __FUNCTION__);
    return NULL;
  }

485
  zathura_image_buffer_t* buffer = page->document->functions.page_render(page);
Moritz Lipp's avatar
Moritz Lipp committed
486

487
  if (buffer) {
Moritz Lipp's avatar
Moritz Lipp committed
488
489
490
    page->rendered = true;
  }

491
  return buffer;
Moritz Lipp's avatar
Moritz Lipp committed
492
}
493
494
495
496

zathura_index_element_t*
zathura_index_element_new(const char* title)
{
Moritz Lipp's avatar
Moritz Lipp committed
497
  if (!title) {
498
    return NULL;
Moritz Lipp's avatar
Moritz Lipp committed
499
  }
500
501

  zathura_index_element_t* res = g_malloc0(sizeof(zathura_index_element_t));
Moritz Lipp's avatar
Moritz Lipp committed
502

Moritz Lipp's avatar
Moritz Lipp committed
503
  if (!res) {
504
    return NULL;
Moritz Lipp's avatar
Moritz Lipp committed
505
506
  }

507
  res->title = g_strdup(title);
Moritz Lipp's avatar
Moritz Lipp committed
508

509
510
511
512
513
514
  return res;
}

void
zathura_index_element_free(zathura_index_element_t* index)
{
Moritz Lipp's avatar
Moritz Lipp committed
515
  if (!index) {
516
    return;
Moritz Lipp's avatar
Moritz Lipp committed
517
  }
518
519

  g_free(index->title);
Moritz Lipp's avatar
Moritz Lipp committed
520

Moritz Lipp's avatar
Moritz Lipp committed
521
  if (index->type == ZATHURA_LINK_EXTERNAL) {
522
    g_free(index->target.uri);
Moritz Lipp's avatar
Moritz Lipp committed
523
524
  }

525
526
  g_free(index);
}
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543

zathura_image_buffer_t*
zathura_image_buffer_create(unsigned int width, unsigned int height)
{
  zathura_image_buffer_t* image_buffer = malloc(sizeof(zathura_image_buffer_t));

  if (image_buffer == NULL) {
    return NULL;
  }

  image_buffer->data = calloc(width * height * 3, sizeof(unsigned char));

  if (image_buffer->data == NULL) {
    free(image_buffer);
    return NULL;
  }

Moritz Lipp's avatar
Moritz Lipp committed
544
545
546
  image_buffer->width     = width;
  image_buffer->height    = height;
  image_buffer->rowstride = width * 3;
547
548
549
550
551
552
553
554
555
556
557
558
559

  return image_buffer;
}

void
zathura_image_buffer_free(zathura_image_buffer_t* image_buffer)
{
  if (image_buffer == NULL) {
    return;
  }

  free(image_buffer->data);
}