Coverage Report

Created: 2026-08-25 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ebook-tools-0.2.2/src/libepub/epub.c
Line
Count
Source
1
#include "epub.h"
2
#include "epublib.h"
3
#include <stdarg.h>
4
5
const char _epub_error_oom[] = "out of memory";
6
7
9.04k
struct epub *epub_open(const char *filename, int debug) {
8
9.04k
  char *opfName = NULL;
9
9.04k
  char *opfStr = NULL;
10
9.04k
  char *pathsep_index = NULL;
11
12
9.04k
  struct epub *epub = malloc(sizeof(struct epub));
13
9.04k
  if (! epub) {
14
0
    return NULL;
15
0
  }
16
9.04k
  epub->ocf = NULL;
17
9.04k
  epub->opf = NULL;
18
9.04k
  _epub_err_set_str(&epub->error, "", 0);
19
9.04k
  epub->debug = debug;
20
9.04k
  _epub_print_debug(epub, DEBUG_INFO, "opening '%s'", filename);
21
  
22
9.04k
  LIBXML_TEST_VERSION;
23
  
24
9.04k
  if (! (epub->ocf = _ocf_parse(epub, filename))) {
25
3.84k
    epub_close(epub);
26
3.84k
    return NULL;
27
3.84k
  }
28
29
5.20k
  opfName = _ocf_root_fullpath_by_type(epub->ocf, 
30
5.20k
                                             "application/oebps-package+xml");
31
5.20k
  if (!opfName) {
32
3.42k
    epub_close(epub);
33
3.42k
    return NULL;
34
3.42k
  }
35
36
1.78k
  epub->ocf->datapath = malloc(sizeof(char) *(strlen(opfName) +1));
37
1.78k
  pathsep_index = strrchr(opfName, '/'); // '/' is per OCF specs
38
1.78k
  if (pathsep_index) {
39
1.77k
    strncpy(epub->ocf->datapath, opfName, pathsep_index + 1 - opfName); 
40
1.77k
    epub->ocf->datapath[pathsep_index - opfName + 1] = 0;
41
1.77k
  }    
42
10
  else {
43
10
    epub->ocf->datapath[0] = 0;
44
10
  }
45
46
1.78k
  _epub_print_debug(epub, DEBUG_INFO, "data path is %s", epub->ocf->datapath );
47
48
1.78k
  _ocf_get_file(epub->ocf, opfName, &opfStr);
49
1.78k
  free(opfName);
50
    
51
52
1.78k
  if (!opfStr) {
53
51
    epub_close(epub);
54
51
    return NULL;
55
51
  }
56
57
1.73k
  epub->opf = _opf_parse(epub, opfStr);
58
1.73k
  if (!epub->opf) {
59
1.21k
    free(opfStr);
60
1.21k
    epub_close(epub);
61
1.21k
    return NULL;
62
1.21k
  }
63
  
64
516
  free(opfStr);
65
66
516
  return epub;
67
1.73k
}
68
69
1.94k
xmlChar *_getXmlStr(void *str) {
70
1.94k
  return xmlStrdup((xmlChar *)str); 
71
1.94k
}
72
73
0
xmlChar *_getIdStr(void *id) {
74
0
  struct id *data = (struct id *)id;
75
0
  xmlChar buff[10000];
76
77
0
  xmlStrPrintf(buff, 10000, (xmlChar *)"%s (%s:%s)", 
78
0
               ((data->scheme)?data->scheme:(xmlChar *)"Unspecified"), 
79
0
               (data->id?data->id:(xmlChar *)"Unspecified"),
80
0
                data->string);
81
  
82
0
  return xmlStrdup(buff);
83
0
}
84
85
557
xmlChar *_getDateStr(void *date) {
86
557
  struct date *data = (struct date *)date;
87
557
  xmlChar buff[10000];
88
89
557
  xmlStrPrintf(buff, 10000, (xmlChar *)"%s: %s", 
90
557
               ((data->event)?data->event:(xmlChar *)"Unspecified"), 
91
557
               data->date);
92
93
557
  return xmlStrdup(buff);
94
557
}
95
96
0
xmlChar *_getMetaStr(void *meta) {
97
0
  struct meta *data = (struct meta *)meta;
98
0
  xmlChar buff[10000];
99
100
0
  xmlStrPrintf(buff, 10000, (xmlChar *)"%s: %s", 
101
0
               ((data->name)?data->name:(xmlChar *)"Unspecified"),
102
0
               ((data->content)?data->content:(xmlChar *)"Unspecified"));
103
  
104
0
  return xmlStrdup(buff);
105
0
}
106
107
558
xmlChar *_getRoleStr(void *creator) {
108
558
  struct creator *data = (struct creator *)creator;
109
558
  xmlChar buff[10000];
110
558
  xmlStrPrintf(buff, 10000, (xmlChar *)"%s: %s(%s)", 
111
558
               ((data->role)?data->role:(xmlChar *)"Author"), 
112
558
               data->name, ((data->fileAs)?data->fileAs:data->name));
113
  
114
558
  return xmlStrdup(buff);
115
558
}
116
117
xmlChar **epub_get_metadata(struct epub *epub, enum epub_metadata type, 
118
3.09k
                            int *size) {
119
3.09k
  xmlChar **data = NULL;
120
3.09k
  listPtr list = NULL;
121
3.09k
  xmlChar *(*getStr)(void *) = NULL;
122
3.09k
  int i;
123
124
3.09k
  if (!epub || !epub->opf || !epub->opf->metadata) {
125
48
    _epub_print_debug(epub, DEBUG_INFO, "no metadata information available");
126
48
    return NULL;
127
48
  }
128
129
3.04k
  switch(type) {
130
0
  case EPUB_ID:
131
0
    list = epub->opf->metadata->id;
132
0
    getStr = _getIdStr;
133
0
    break;
134
508
  case EPUB_TITLE:
135
508
    list = epub->opf->metadata->title;
136
508
    getStr = _getXmlStr;
137
508
    break;
138
508
  case EPUB_SUBJECT:
139
508
    list = epub->opf->metadata->subject;
140
508
    getStr = _getXmlStr;
141
508
    break;
142
508
  case EPUB_PUBLISHER:
143
508
    list = epub->opf->metadata->publisher;
144
508
    getStr = _getXmlStr;
145
508
    break;
146
508
  case EPUB_DESCRIPTION:
147
508
    list = epub->opf->metadata->description;
148
508
    getStr = _getXmlStr;
149
508
    break;
150
508
  case EPUB_DATE:
151
508
    list = epub->opf->metadata->date;
152
508
    getStr = _getDateStr;
153
508
    break;
154
0
  case EPUB_TYPE:
155
0
    list = epub->opf->metadata->type;
156
0
    getStr = _getXmlStr;
157
0
    break;
158
0
  case EPUB_FORMAT:
159
0
    list = epub->opf->metadata->format;
160
0
    getStr = _getXmlStr;
161
0
    break;
162
0
  case EPUB_SOURCE:
163
0
    list = epub->opf->metadata->source;
164
0
    getStr = _getXmlStr;
165
0
    break;
166
0
  case EPUB_LANG:
167
0
    list = epub->opf->metadata->lang;
168
0
    getStr = _getXmlStr;
169
0
    break;
170
0
  case EPUB_RELATION:
171
0
    list = epub->opf->metadata->relation;
172
0
    getStr = _getXmlStr;
173
0
    break;
174
0
  case EPUB_COVERAGE:
175
0
    list = epub->opf->metadata->coverage;
176
0
    getStr = _getXmlStr;
177
0
    break;
178
0
  case EPUB_RIGHTS:
179
0
    list = epub->opf->metadata->rights;
180
0
    getStr = _getXmlStr;
181
0
    break;
182
508
  case EPUB_CREATOR:
183
508
    list = epub->opf->metadata->creator;
184
508
    getStr = _getRoleStr;
185
508
    break;
186
0
  case EPUB_CONTRIB:
187
0
    list = epub->opf->metadata->contrib;
188
0
    getStr = _getRoleStr;
189
0
    break;
190
0
  case EPUB_META:
191
0
    list = epub->opf->metadata->meta;
192
0
    getStr = _getMetaStr;
193
0
    break;
194
0
  default:
195
0
    _epub_print_debug(epub, DEBUG_INFO, "fetching metadata: unknown type %d", type);
196
0
    return NULL;
197
3.04k
  }
198
199
3.04k
  if (list->Size <= 0)
200
236
    return NULL;
201
202
2.81k
  data = malloc(list->Size * sizeof(xmlChar *));
203
2.81k
  if (! data) {
204
0
    _epub_err_set_oom(&epub->error);
205
0
    return NULL;
206
0
  }
207
2.81k
  if (size) {
208
2.81k
    *size = list->Size;
209
2.81k
  }
210
2.81k
  list->Current = list->Head;
211
212
2.81k
  data[0] = getStr(GetNode(list));
213
3.05k
  for (i=1;i<list->Size;i++) {
214
246
    data[i] = getStr(NextNode(list));
215
246
  }
216
217
2.81k
  return data;
218
2.81k
}
219
220
// returns the next node that the iterator should return
221
// if init also check if the current node is good
222
// if linear is 0 return non linear else return linear
223
0
listnodePtr _get_spine_it_next(listnodePtr curr, int linear, int init) {
224
0
  struct spine *node; 
225
226
0
  if (! curr)
227
0
    return NULL;
228
  
229
0
  if ( ! init) {
230
0
    curr = curr->Next;
231
0
  }
232
233
0
  node = (struct spine *)GetNodeData(curr);
234
  
235
0
  while(curr) {
236
0
    if (! node)
237
0
      return NULL;
238
    
239
0
    node = (struct spine *)GetNodeData(curr);
240
    
241
0
    if (node->linear == linear)
242
0
      return curr;
243
    
244
0
    curr = curr->Next;
245
0
  }
246
247
0
  return NULL;
248
0
}
249
250
1.46k
char *_get_spine_it_url(struct eiterator *it) {
251
1.46k
  struct manifest *tmp;
252
1.46k
  void *data;
253
254
1.46k
  if (!it) 
255
0
    return NULL;
256
  
257
1.46k
  data = GetNodeData(it->curr);
258
1.46k
  tmp = _opf_manifest_get_by_id(it->epub->opf, 
259
1.46k
                                ((struct spine *)data)->idref);
260
1.46k
  if (!tmp) {
261
123
    _epub_print_debug(it->epub, DEBUG_ERROR, 
262
123
            "spine parsing error idref %s is not in the manifest",
263
123
            ((struct spine *)data)->idref);
264
123
    return NULL;
265
123
  }
266
267
1.33k
  return (char *)tmp->href;
268
1.46k
}
269
270
struct eiterator *epub_get_iterator(struct epub *epub, 
271
516
                                    enum eiterator_type type, int opt) {
272
273
516
  struct eiterator *it = NULL;
274
275
516
  if (!epub) {
276
0
    return NULL;
277
0
  }
278
279
516
  it = malloc(sizeof(struct eiterator));
280
516
  if (!it) {
281
0
    _epub_err_set_oom(&epub->error);
282
0
    return NULL;
283
0
  }
284
516
  it->type = type;
285
516
  it->epub = epub;
286
516
  it->opt = opt;
287
516
  it->cache = NULL;
288
289
516
  switch (type) {
290
516
  case EITERATOR_SPINE:
291
516
    it->curr = epub->opf->spine->Head;
292
516
    break;
293
0
  case EITERATOR_NONLINEAR:
294
0
    it->curr = _get_spine_it_next(epub->opf->spine->Head, 0, 1); 
295
0
    break;
296
0
  case EITERATOR_LINEAR:
297
0
    it->curr = _get_spine_it_next(epub->opf->spine->Head, 1, 1); 
298
0
    break;
299
516
  }
300
301
302
516
  return it;
303
516
}
304
305
516
void epub_free_iterator(struct eiterator *it) {
306
516
  if (!it) {
307
0
    return;
308
0
  }
309
310
516
  if (it->cache)
311
0
    free(it->cache);
312
313
516
  free(it);
314
516
}
315
316
317
946
char *epub_it_get_curr_url(struct eiterator *it) {
318
946
  if (!it) {
319
0
    return NULL;
320
0
  }
321
322
946
  switch (it->type) {
323
946
  case EITERATOR_SPINE:
324
946
  case EITERATOR_NONLINEAR:
325
946
  case EITERATOR_LINEAR:
326
946
    return _get_spine_it_url(it);
327
946
  }
328
  
329
0
  return NULL;
330
946
}
331
332
946
char *epub_it_get_curr(struct eiterator *it) {
333
334
946
  if (!it || !it->curr)
335
430
    return NULL;
336
337
516
  if (!it->cache) {
338
       
339
516
    switch (it->type) {
340
516
    case EITERATOR_SPINE:
341
516
    case EITERATOR_NONLINEAR:
342
516
    case EITERATOR_LINEAR:
343
516
      _ocf_get_data_file(it->epub->ocf, _get_spine_it_url(it), &(it->cache));
344
516
      break;
345
516
    }
346
516
  }
347
  
348
516
  return it->cache;
349
516
}
350
946
char *epub_it_get_next(struct eiterator *it) {
351
946
  if (!it) {
352
0
    return NULL;
353
0
  }
354
355
946
  if (it->cache) {
356
430
    free(it->cache);
357
430
    it->cache = NULL;
358
430
  }
359
360
946
  if (!it->curr)
361
0
    return NULL;
362
363
946
  switch (it->type) {
364
365
946
  case EITERATOR_SPINE:
366
946
    it->curr = it->curr->Next;
367
946
    break;
368
    
369
0
  case EITERATOR_NONLINEAR:
370
0
    it->curr = _get_spine_it_next(it->curr, 0, 0); 
371
0
    break;
372
373
0
  case EITERATOR_LINEAR:
374
0
    it->curr = _get_spine_it_next(it->curr, 1, 0); 
375
0
    break;
376
946
  }
377
  
378
946
  return epub_it_get_curr(it);
379
946
}
380
381
9.04k
int epub_close(struct epub *epub) {
382
9.04k
  if (!epub) {
383
0
    return 0;
384
0
  }
385
386
9.04k
  if (epub->ocf)
387
5.20k
    _ocf_close(epub->ocf);
388
389
9.04k
  if (epub->opf)
390
516
    _opf_close(epub->opf);
391
392
9.04k
  if (epub)
393
9.04k
    free(epub);
394
395
  
396
9.04k
  return 1;
397
9.04k
}
398
399
0
void epub_set_debug(struct epub *epub, int debug) {
400
0
  if (!epub) {
401
0
    return;
402
0
  }
403
404
0
  epub->debug = debug;
405
0
}
406
407
88.8k
void _epub_print_debug(struct epub *epub, int debug, const char *format, ...) {
408
88.8k
  va_list ap;
409
88.8k
  char strerr[1025];
410
411
88.8k
  va_start(ap, format);
412
413
88.8k
  vsnprintf(strerr, 1024, format, ap);
414
88.8k
  strerr[1024] = 0;
415
  
416
88.8k
  if (epub && (debug == DEBUG_ERROR)) {
417
6.88k
    _epub_err_set_str(&epub->error, strerr, strlen(strerr));
418
6.88k
  }
419
420
88.8k
  if (! epub || (epub->debug >= debug)) {
421
6.88k
    fprintf(stderr, "libepub ");
422
6.88k
    switch(debug) {
423
6.88k
    case DEBUG_ERROR: 
424
      
425
6.88k
      fprintf(stderr, "(EE)");
426
6.88k
    break;
427
0
    case DEBUG_WARNING:
428
0
      fprintf(stderr, "(WW)");
429
0
      break;
430
0
    case DEBUG_INFO:
431
0
      fprintf(stderr, "(II)");
432
0
      break;
433
0
    case DEBUG_VERBOSE:
434
0
      fprintf(stderr, "(VV)");
435
0
      break;
436
6.88k
    }
437
6.88k
    fprintf(stderr, ": \t%s\n" , strerr);
438
6.88k
  }
439
88.8k
  va_end(ap);
440
88.8k
}
441
442
967
int epub_tit_next(struct titerator *tit) {
443
967
  listnodePtr curr = NULL;
444
445
967
  if (!tit) {
446
0
    return 0;
447
0
  }
448
449
967
  curr = tit->next;
450
967
  if (! curr) {
451
503
    tit->valid = 0;
452
503
    return 0;
453
503
  }
454
455
464
  tit->next = curr->Next;
456
  
457
464
  switch (tit->type) {
458
0
    struct guide* guide;
459
0
    struct tocItem *ti;
460
461
452
  case TITERATOR_GUIDE:
462
452
    guide = GetNodeData(curr);
463
452
    tit->cache.label = (char *)guide->title;
464
452
    tit->cache.link = (char *)guide->href;
465
452
    tit->cache.depth = 1;
466
467
452
    break;
468
469
12
  case TITERATOR_NAVMAP:
470
12
  case TITERATOR_PAGES:
471
12
    ti = GetNodeData(curr);
472
12
    tit->cache.label = 
473
12
      (char *)_opf_label_get_by_doc_lang(tit->epub->opf, ti->label);
474
475
12
    if (! tit->cache.label)
476
0
      tit->cache.label = (char *)ti->id;
477
478
12
    tit->cache.depth = ti->depth;
479
12
    tit->cache.link = (char *)ti->src;
480
12
    break;
481
482
464
  }
483
484
464
  tit->valid = 1;
485
464
  return 1;
486
464
}
487
488
struct titerator *epub_get_titerator(struct epub *epub, 
489
981
                                     enum titerator_type type, int opt) {
490
981
  struct titerator *it = NULL;
491
492
981
  if (!epub) {
493
0
    return NULL;
494
0
  }
495
496
981
  switch (type) {
497
516
  case TITERATOR_NAVMAP:
498
516
    if (! epub->opf->toc || ! epub->opf->toc->navMap)
499
465
      return NULL;
500
51
    break;
501
465
  case TITERATOR_GUIDE:
502
465
    if (! epub->opf->guide) 
503
13
      return NULL;
504
452
    break;
505
452
  case TITERATOR_PAGES:
506
0
    if (! epub->opf->toc || epub->opf->toc->pageList)
507
0
      return NULL;
508
0
    break;
509
981
  }
510
511
503
  it = malloc(sizeof(struct titerator));
512
503
  if (!it) {
513
0
    _epub_err_set_oom(&epub->error);
514
0
    return NULL;
515
0
  }
516
503
  it->type = type;
517
503
  it->epub = epub;
518
503
  it->opt = opt;
519
503
  it->next = NULL;
520
503
  it->valid = 0;
521
522
503
  it->cache.label = NULL;
523
503
  it->cache.link = NULL;
524
503
  it->cache.depth = -1;
525
526
527
503
  switch (type) {
528
51
  case TITERATOR_NAVMAP:
529
51
    it->next = epub->opf->toc->navMap->items->Head;
530
51
    if (epub->opf->toc->navMap->label) {
531
51
      it->cache.label = 
532
51
        (char *)_opf_label_get_by_doc_lang(epub->opf, 
533
51
                                           epub->opf->toc->navMap->label);
534
51
      it->cache.depth = 0;
535
51
    }
536
51
    it->valid = 1;
537
51
    break;
538
539
452
  case TITERATOR_GUIDE:
540
452
    it->next = epub->opf->guide->Head;
541
452
    break;
542
    
543
0
  case TITERATOR_PAGES:
544
0
    it->next = epub->opf->toc->pageList->items->Head;
545
0
    if (epub->opf->toc->pageList->label) {
546
0
      it->cache.label = 
547
0
        (char *)_opf_label_get_by_doc_lang(epub->opf, 
548
0
                                           epub->opf->toc->pageList->label);
549
0
      it->cache.depth = 1;
550
0
    }
551
0
    it->valid = 1;
552
0
    break;
553
503
  }
554
  
555
503
  if ( ! it->cache.label)
556
503
    epub_tit_next(it);
557
  
558
503
  return it;
559
503
}
560
561
503
int epub_tit_curr_valid(struct titerator *tit) {
562
503
  if (!tit) {
563
0
    return 0;
564
0
  }
565
566
503
  return tit->valid;
567
503
}
568
569
0
char *epub_tit_get_curr_label(struct titerator *tit) {
570
0
  if (!tit) {
571
0
    return NULL;
572
0
  }
573
574
  // FIXME how can there be unlabeled curr?
575
0
  return tit->cache.label?strdup(tit->cache.label):NULL;
576
0
}
577
578
0
int epub_tit_get_curr_depth(struct titerator *tit) {
579
0
  if (!tit) {
580
0
    return 0;
581
0
  }
582
583
0
  return tit->cache.depth;
584
0
}
585
586
464
char *epub_tit_get_curr_link(struct titerator *tit) {
587
464
  if (!tit) {
588
0
    return NULL;
589
0
  }
590
591
464
  if (!tit->cache.link) {
592
20
    return NULL;
593
20
  }
594
  
595
444
  return strdup(tit->cache.link);
596
597
464
}
598
599
503
void epub_free_titerator(struct titerator *tit) {
600
503
  if (!tit) {
601
0
    return;
602
0
  }
603
604
503
  free(tit);
605
503
}
606
  
607
0
int epub_get_ocf_file(struct epub *epub, const char *filename, char **data) {
608
0
  if (!epub) {
609
0
    return -1;
610
0
  }
611
612
0
  return _ocf_get_file(epub->ocf, filename, data);
613
0
}
614
615
1.33k
int epub_get_data(struct epub *epub, const char *name, char **data) {
616
1.33k
  if (!epub) {
617
0
    return -1;
618
0
  }
619
620
1.33k
  return _ocf_get_data_file(epub->ocf, name, data);
621
1.33k
}
622
623
0
void epub_dump(struct epub *epub) {
624
0
  if (!epub) {
625
0
    return;
626
0
  }
627
628
0
  _ocf_dump(epub->ocf);
629
0
  _opf_dump(epub->opf);
630
0
}
631
632
0
void epub_cleanup() {
633
0
  xmlCleanupParser();
634
0
}
635
636
0
char *epub_last_errStr(struct epub *epub) {
637
0
  char *res = NULL;
638
639
0
  if (!epub) {
640
0
    return NULL;
641
0
  }
642
643
0
  switch (epub->error.type) {
644
0
  case 0:
645
0
    res = malloc(epub->error.len + 1);
646
0
    if (!res) {
647
0
      _epub_err_set_oom(&epub->error);
648
0
      return NULL;
649
0
    }
650
0
    strncpy(res, epub->error.lastStr, epub->error.len);
651
0
    res[epub->error.len] = 0;
652
0
    break;
653
0
  case 1:
654
0
    res = strdup(epub->error.str);
655
0
    if (!res) {
656
0
      _epub_err_set_oom(&epub->error);
657
0
      return NULL;
658
0
    }
659
0
    break;
660
0
  }
661
662
0
  return res;
663
0
}
664