document.c 12.8 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
#define _BSD_SOURCE
4
#define _XOPEN_SOURCE 700
Moritz Lipp's avatar
Moritz Lipp committed
5
6
// TODO: Implement realpath

Moritz Lipp's avatar
Moritz Lipp committed
7
#include <sys/wait.h>
Moritz Lipp's avatar
Moritz Lipp committed
8
#include <stdlib.h>
Moritz Lipp's avatar
Moritz Lipp committed
9
#include <stdio.h>
Moritz Lipp's avatar
Moritz Lipp committed
10
#include <string.h>
Moritz Lipp's avatar
Moritz Lipp committed
11
#include <limits.h>
12
#include <errno.h>
13
#include <glib.h>
14
#include <glib/gi18n.h>
Moritz Lipp's avatar
Moritz Lipp committed
15

16
17
18
19
20
21
#include <girara/datastructures.h>
#include <girara/utils.h>
#include <girara/statusbar.h>
#include <girara/session.h>
#include <girara/settings.h>

Moritz Lipp's avatar
Moritz Lipp committed
22
#include "document.h"
23
24
#include "utils.h"
#include "zathura.h"
Moritz Lipp's avatar
Update    
Moritz Lipp committed
25
#include "render.h"
Pavel Borzenkov's avatar
Pavel Borzenkov committed
26
#include "database.h"
Moritz Lipp's avatar
Moritz Lipp committed
27
#include "page.h"
28
#include "page-widget.h"
29
#include "plugin.h"
30

31
32
33
/** Read a most GT_MAX_READ bytes before falling back to file. */
static const size_t GT_MAX_READ = 1 << 16;

34
static const gchar* guess_type(const char* path);
35

36
37
38
/**
 * Document
 */
Moritz Lipp's avatar
Moritz Lipp committed
39
struct zathura_document_s {
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  char* file_path; /**< File path of the document */
  const char* password; /**< Password of the document */
  unsigned int current_page_number; /**< Current page number */
  unsigned int number_of_pages; /**< Number of pages */
  double scale; /**< Scale value */
  unsigned int rotate; /**< Rotation */
  void* data; /**< Custom data */
  zathura_adjust_mode_t adjust_mode; /**< Adjust mode (best-fit, width) */
  unsigned int page_offset; /**< Page offset */

  /**
   * Document pages
   */
  zathura_page_t** pages;

55
56
57
58
  /**
   * Used plugin
   */
  zathura_plugin_t* plugin;
59
60
61
};


62
zathura_document_t*
63
zathura_document_open(zathura_plugin_manager_t* plugin_manager, const char*
Moritz Lipp's avatar
Moritz Lipp committed
64
                      path, const char* password, zathura_error_t* error)
65
66
67
68
69
{
  if (path == NULL) {
    return NULL;
  }

70
  if (g_file_test(path, G_FILE_TEST_EXISTS) == FALSE) {
71
72
73
74
75
76
77
78
    girara_error("File '%s' does not exist", path);
    return NULL;
  }

  const gchar* content_type = guess_type(path);
  if (content_type == NULL) {
    girara_error("Could not determine file type.");
    return NULL;
79
80
  }

Moritz Lipp's avatar
Moritz Lipp committed
81
  /* determine real path */
82
  long path_max;
Moritz Lipp's avatar
Moritz Lipp committed
83
84
85
86
#ifdef PATH_MAX
  path_max = PATH_MAX;
#else
  path_max = pathconf(path,_PC_PATH_MAX);
87
  if (path_max <= 0)
Moritz Lipp's avatar
Moritz Lipp committed
88
89
90
    path_max = 4096;
#endif

Moritz Lipp's avatar
Moritz Lipp committed
91
92
93
94
  char* real_path              = NULL;
  zathura_document_t* document = NULL;

  real_path = malloc(sizeof(char) * path_max);
Moritz Lipp's avatar
Moritz Lipp committed
95
  if (real_path == NULL) {
96
97
    g_free((void*)content_type);
    return NULL;
Moritz Lipp's avatar
Moritz Lipp committed
98
99
  }

Moritz Lipp's avatar
Moritz Lipp committed
100
  if (realpath(path, real_path) == NULL) {
101
102
103
104
105
    g_free((void*)content_type);
    free(real_path);
    return NULL;
  }

106
  zathura_plugin_t* plugin = zathura_plugin_manager_get_plugin(plugin_manager, content_type);
107
108
109
110
  g_free((void*)content_type);

  if (plugin == NULL) {
    girara_error("unknown file type\n");
111
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
112
113
  }

Moritz Lipp's avatar
Moritz Lipp committed
114
  document = g_malloc0(sizeof(zathura_document_t));
Moritz Lipp's avatar
Moritz Lipp committed
115

Moritz Lipp's avatar
Moritz Lipp committed
116
117
118
119
120
  document->file_path   = real_path;
  document->password    = password;
  document->scale       = 1.0;
  document->plugin      = plugin;
  document->adjust_mode = ZATHURA_ADJUST_NONE;
Moritz Lipp's avatar
Moritz Lipp committed
121

122
  /* open document */
123
124
  zathura_plugin_functions_t* functions = zathura_plugin_get_functions(plugin);
  if (functions->document_open == NULL) {
125
126
127
128
    girara_error("plugin has no open function\n");
    goto error_free;
  }

129
  zathura_error_t int_error = functions->document_open(document);
130
131
132
  if (int_error != ZATHURA_ERROR_OK) {
    if (error != NULL) {
      *error = int_error;
133
134
135
136
137
138
    }

    girara_error("could not open document\n");
    goto error_free;
  }

Moritz Lipp's avatar
Moritz Lipp committed
139
140
141
142
143
  /* read all pages */
  document->pages = calloc(document->number_of_pages, sizeof(zathura_page_t*));
  if (document->pages == NULL) {
    goto error_free;
  }
144

Moritz Lipp's avatar
Moritz Lipp committed
145
  for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
146
    zathura_page_t* page = zathura_page_new(document, page_id, NULL);
Moritz Lipp's avatar
Moritz Lipp committed
147
148
    if (page == NULL) {
      goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
149
    }
Moritz Lipp's avatar
Moritz Lipp committed
150
151
152
153
154

    document->pages[page_id] = page;
  }

  return document;
Moritz Lipp's avatar
Moritz Lipp committed
155

Moritz Lipp's avatar
Moritz Lipp committed
156
157
error_free:

Moritz Lipp's avatar
Moritz Lipp committed
158
  free(real_path);
Moritz Lipp's avatar
Moritz Lipp committed
159

Moritz Lipp's avatar
Moritz Lipp committed
160
161
  if (document != NULL && document->pages != NULL) {
    for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
Moritz Lipp's avatar
Moritz Lipp committed
162
163
164
165
166
167
      zathura_page_free(document->pages[page_id]);
    }

    free(document->pages);
  }

Moritz Lipp's avatar
Moritz Lipp committed
168
  g_free(document);
Moritz Lipp's avatar
Moritz Lipp committed
169
170
171
  return NULL;
}

172
zathura_error_t
Moritz Lipp's avatar
Moritz Lipp committed
173
zathura_document_free(zathura_document_t* document)
Moritz Lipp's avatar
Moritz Lipp committed
174
{
175
  if (document == NULL || document->plugin == NULL) {
176
    return ZATHURA_ERROR_INVALID_ARGUMENTS;
Moritz Lipp's avatar
Moritz Lipp committed
177
178
  }

Moritz Lipp's avatar
Moritz Lipp committed
179
  /* free pages */
Moritz Lipp's avatar
Moritz Lipp committed
180
  for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
Moritz Lipp's avatar
Moritz Lipp committed
181
    zathura_page_free(document->pages[page_id]);
Pavel Borzenkov's avatar
Pavel Borzenkov committed
182
    document->pages[page_id] = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
183
184
185
186
187
  }

  free(document->pages);

  /* free document */
188
  zathura_error_t error = ZATHURA_ERROR_OK;
189
190
  zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
  if (functions->document_free == NULL) {
191
    error = ZATHURA_ERROR_NOT_IMPLEMENTED;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
192
  } else {
193
    error = functions->document_free(document, document->data);
Moritz Lipp's avatar
Moritz Lipp committed
194
195
  }

Moritz Lipp's avatar
Moritz Lipp committed
196
  if (document->file_path != NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
197
198
199
    free(document->file_path);
  }

Moritz Lipp's avatar
Moritz Lipp committed
200
  g_free(document);
Moritz Lipp's avatar
Moritz Lipp committed
201

Moritz Lipp's avatar
Moritz Lipp committed
202
  return error;
Moritz Lipp's avatar
Moritz Lipp committed
203
204
}

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
const char*
zathura_document_get_path(zathura_document_t* document)
{
  if (document == NULL) {
    return NULL;
  }

  return document->file_path;
}

const char*
zathura_document_get_password(zathura_document_t* document)
{
  if (document == NULL) {
    return NULL;
  }

  return document->password;
}

225
226
227
228
229
230
231
232
233
234
zathura_page_t*
zathura_document_get_page(zathura_document_t* document, unsigned int index)
{
  if (document == NULL || document->pages == NULL || (document->number_of_pages <= index)) {
    return NULL;
  }

  return document->pages[index];
}

235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
void*
zathura_document_get_data(zathura_document_t* document)
{
  if (document == NULL) {
    return NULL;
  }

  return document->data;
}

void
zathura_document_set_data(zathura_document_t* document, void* data)
{
  if (document == NULL) {
    return;
  }

  document->data = data;
}

unsigned int
zathura_document_get_number_of_pages(zathura_document_t* document)
{
  if (document == NULL) {
    return 0;
  }

  return document->number_of_pages;
}

void
zathura_document_set_number_of_pages(zathura_document_t* document, unsigned int number_of_pages)
{
  if (document == NULL) {
    return;
  }

  document->number_of_pages = number_of_pages;
}

unsigned int
276
zathura_document_get_current_page_number(zathura_document_t* document)
277
278
279
280
281
282
283
284
285
{
  if (document == NULL) {
    return 0;
  }

  return document->current_page_number;
}

void
286
zathura_document_set_current_page_number(zathura_document_t* document, unsigned int
287
288
289
290
291
292
293
294
295
    current_page)
{
  if (document == NULL) {
    return;
  }

  document->current_page_number = current_page;
}

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
double
zathura_document_get_scale(zathura_document_t* document)
{
  if (document == NULL) {
    return 0;
  }

  return document->scale;
}

void
zathura_document_set_scale(zathura_document_t* document, double scale)
{
  if (document == NULL) {
    return;
  }

  document->scale = scale;
}

unsigned int
zathura_document_get_rotation(zathura_document_t* document)
{
  if (document == NULL) {
    return 0;
  }

  return document->rotate;
}

void
zathura_document_set_rotation(zathura_document_t* document, unsigned int rotation)
{
  if (document == NULL) {
    return;
  }

  document->rotate = rotation % 360;

Moritz Lipp's avatar
Moritz Lipp committed
335
  if (document->rotate > 0 && document->rotate <= 90) {
336
    document->rotate = 90;
Moritz Lipp's avatar
Moritz Lipp committed
337
  } else if (document->rotate > 0 && document->rotate <= 180) {
338
    document->rotate = 180;
Moritz Lipp's avatar
Moritz Lipp committed
339
  } else if (document->rotate > 0 && document->rotate <= 270) {
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
    document->rotate = 270;
  } else {
    document->rotate = 0;
  }
}

zathura_adjust_mode_t
zathura_document_get_adjust_mode(zathura_document_t* document)
{
  if (document == NULL) {
    return ZATHURA_ADJUST_NONE;
  }

  return document->adjust_mode;
}

void
zathura_document_set_adjust_mode(zathura_document_t* document, zathura_adjust_mode_t mode)
{
  if (document == NULL) {
    return;
  }

  if (mode == ZATHURA_ADJUST_BESTFIT || mode == ZATHURA_ADJUST_WIDTH) {
    document->adjust_mode = mode;
  } else {
    document->adjust_mode = ZATHURA_ADJUST_NONE;
  }
}

unsigned int
zathura_document_get_page_offset(zathura_document_t* document)
{
  if (document == NULL) {
    return 0;
  }

  return document->page_offset;
}

void
zathura_document_set_page_offset(zathura_document_t* document, unsigned int page_offset)
{
  if (document == NULL) {
    return;
  }

  if (page_offset < document->number_of_pages) {
    document->page_offset = page_offset;
  }
}

392
zathura_error_t
Moritz Lipp's avatar
Moritz Lipp committed
393
394
zathura_document_save_as(zathura_document_t* document, const char* path)
{
395
  if (document == NULL || document->plugin == NULL || path == NULL) {
396
    return ZATHURA_ERROR_UNKNOWN;
Moritz Lipp's avatar
Moritz Lipp committed
397
398
  }

399
400
  zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
  if (functions->document_save_as == NULL) {
401
    return ZATHURA_ERROR_NOT_IMPLEMENTED;
Moritz Lipp's avatar
Moritz Lipp committed
402
403
  }

404
  return functions->document_save_as(document, document->data, path);
Moritz Lipp's avatar
Moritz Lipp committed
405
406
}

407
girara_tree_node_t*
408
zathura_document_index_generate(zathura_document_t* document, zathura_error_t* error)
Moritz Lipp's avatar
Moritz Lipp committed
409
{
410
  if (document == NULL || document->plugin == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
411
    if (error != NULL) {
412
      *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
Moritz Lipp's avatar
Moritz Lipp committed
413
    }
Moritz Lipp's avatar
Moritz Lipp committed
414
415
416
    return NULL;
  }

417
418
  zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
  if (functions->document_index_generate == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
419
    if (error != NULL) {
420
      *error = ZATHURA_ERROR_NOT_IMPLEMENTED;
Moritz Lipp's avatar
Moritz Lipp committed
421
    }
Moritz Lipp's avatar
Moritz Lipp committed
422
423
424
    return NULL;
  }

425
  return functions->document_index_generate(document, document->data, error);
Moritz Lipp's avatar
Moritz Lipp committed
426
427
}

Sebastian Ramacher's avatar
Sebastian Ramacher committed
428
girara_list_t*
429
zathura_document_attachments_get(zathura_document_t* document, zathura_error_t* error)
Moritz Lipp's avatar
Moritz Lipp committed
430
{
431
  if (document == NULL || document->plugin == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
432
    if (error != NULL) {
433
      *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
Moritz Lipp's avatar
Moritz Lipp committed
434
    }
Moritz Lipp's avatar
Moritz Lipp committed
435
436
437
    return NULL;
  }

438
439
  zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
  if (functions->document_attachments_get == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
440
    if (error != NULL) {
441
      *error = ZATHURA_ERROR_NOT_IMPLEMENTED;
Moritz Lipp's avatar
Moritz Lipp committed
442
    }
Moritz Lipp's avatar
Moritz Lipp committed
443
444
445
    return NULL;
  }

446
  return functions->document_attachments_get(document, document->data, error);
Moritz Lipp's avatar
Moritz Lipp committed
447
448
}

449
zathura_error_t
450
zathura_document_attachment_save(zathura_document_t* document, const char* attachment, const char* file)
Moritz Lipp's avatar
Moritz Lipp committed
451
{
452
  if (document == NULL || document->plugin == NULL) {
453
    return ZATHURA_ERROR_INVALID_ARGUMENTS;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
454
455
  }

456
457
  zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
  if (functions->document_attachment_save == NULL) {
458
    return ZATHURA_ERROR_NOT_IMPLEMENTED;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
459
460
  }

461
  return functions->document_attachment_save(document, document->data, attachment, file);
Moritz Lipp's avatar
Moritz Lipp committed
462
463
}

464
465
girara_list_t*
zathura_document_get_information(zathura_document_t* document, zathura_error_t* error)
Moritz Lipp's avatar
Moritz Lipp committed
466
{
467
  if (document == NULL || document->plugin == NULL) {
468
    if (error != NULL) {
469
      *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
470
    }
Moritz Lipp's avatar
Moritz Lipp committed
471
472
473
    return NULL;
  }

474
475
  zathura_plugin_functions_t* functions = zathura_plugin_get_functions(document->plugin);
  if (functions->document_get_information == NULL) {
476
    if (error != NULL) {
477
      *error = ZATHURA_ERROR_NOT_IMPLEMENTED;
478
    }
Moritz Lipp's avatar
Moritz Lipp committed
479
480
481
    return NULL;
  }

482
  girara_list_t* result = functions->document_get_information(document, document->data, error);
483
484
485
486
487
  if (result != NULL) {
    girara_list_set_free_function(result, (girara_free_function_t) zathura_document_information_entry_free);
  }

  return result;
Moritz Lipp's avatar
Moritz Lipp committed
488
489
}

490
491
static const gchar*
guess_type(const char* path)
492
{
493
494
495
  gboolean uncertain;
  const gchar* content_type = g_content_type_guess(path, NULL, 0, &uncertain);
  if (content_type == NULL) {
496
    return NULL;
Moritz Lipp's avatar
Moritz Lipp committed
497
  }
498

499
500
  if (uncertain == FALSE) {
    return content_type;
Moritz Lipp's avatar
Moritz Lipp committed
501
502
  }

503
  girara_debug("g_content_type is uncertain, guess: %s\n", content_type);
504

505
506
  FILE* f = fopen(path, "rb");
  if (f == NULL) {
507
508
509
    return NULL;
  }

510
511
512
513
514
515
  const int fd = fileno(f);
  guchar* content = NULL;
  size_t length = 0u;
  while (uncertain == TRUE && length < GT_MAX_READ) {
    g_free((void*)content_type);
    content_type = NULL;
516

517
518
519
520
521
    content = g_realloc(content, length + BUFSIZ);
    const ssize_t r = read(fd, content + length, BUFSIZ);
    if (r == -1) {
      break;
    }
522

523
524
525
526
    length += r;
    content_type = g_content_type_guess(NULL, content, length, &uncertain);
    girara_debug("new guess: %s uncertain: %d, read: %zu\n", content_type, uncertain, length);
  }
527

528
529
530
531
  fclose(f);
  g_free(content);
  if (uncertain == FALSE) {
    return content_type;
532
533
  }

534
535
  g_free((void*)content_type);
  content_type = NULL;
536

537
  girara_debug("falling back to file");
538

539
540
  GString* command = g_string_new("file -b --mime-type ");
  char* tmp        = g_shell_quote(path);
541

542
543
  g_string_append(command, tmp);
  g_free(tmp);
544

545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  GError* error = NULL;
  char* out = NULL;
  int ret = 0;
  g_spawn_command_line_sync(command->str, &out, NULL, &ret, &error);
  g_string_free(command, TRUE);
  if (error != NULL) {
    girara_warning("failed to execute command: %s", error->message);
    g_error_free(error);
    g_free(out);
    return NULL;
  }
  if (WEXITSTATUS(ret) != 0) {
    girara_warning("file failed with error code: %d", WEXITSTATUS(ret));
    g_free(out);
    return NULL;
560
561
  }

562
563
  g_strdelimit(out, "\n\r", '\0');
  return out;
564
}
565
566
567
568
569
570
571
572
573
574

zathura_plugin_t*
zathura_document_get_plugin(zathura_document_t* document)
{
  if (document == NULL) {
    return NULL;
  }

  return document->plugin;
}