/*
* Copyright (c) 2020-2022, yzrh <yzrh@noema.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef __linux__
#define _GNU_SOURCE
#endif /* __linux__ */
#include <stdlib.h>
#include <string.h>
#include "pdf.h"
static int
_id_in(int id, int *ids)
{
for (int i = 1; i <= ids[0]; i++)
if (ids[i] == id)
return 1;
return 0;
}
int
pdf_get_obj(pdf_object_t **pdf, int id, pdf_object_t **obj)
{
if (*pdf == NULL || id <= 0)
return 1;
pdf_object_t *ptr = *pdf;
while (ptr->next != NULL) {
if (ptr->next->id == id) {
*obj = ptr->next;
return 0;
}
ptr = ptr->next;
}
return 1;
}
int
pdf_get_count(pdf_object_t **pdf)
{
if (*pdf == NULL)
return 1;
int count = 0;
pdf_object_t *ptr = (*pdf)->next;
while (ptr != NULL) {
count++;
ptr = ptr->next;
}
return count;
}
int
pdf_get_size(pdf_object_t **pdf)
{
if (*pdf == NULL)
return 1;
int size = 0;
pdf_object_t *ptr = (*pdf)->next;
while (ptr != NULL) {
size += ptr->size;
ptr = ptr->next;
}
return size;
}
int
pdf_get_free_id(pdf_object_t **pdf)
{
if (*pdf == NULL)
return 1;
int free_id = 0;
pdf_object_t *ptr;
int id = 0;
for (int i = 1; i < 100000000; i++) {
ptr = (*pdf)->next;
while (ptr != NULL) {
if (ptr->id == i) {
id = i;
break;
}
ptr = ptr->next;
}
if (i != id) {
free_id = i;
break;
}
}
return free_id;
}
int
pdf_get_free_ids(pdf_object_t **pdf, int **ids, int count)
{
if (*pdf == NULL || *ids != NULL || count <= 0)
return 1;
*ids = malloc(count * sizeof(int));
if (*ids == NULL)
return 1;
int pos = 0;
int id = 0;
pdf_object_t *ptr;
for (int i = 1; i < 100000000; i++) {
ptr = (*pdf)->next;
while (ptr != NULL) {
if (ptr->id == i) {
id = i;
break;
}
ptr = ptr->next;
}
if (i != id) {
(*ids)[pos] = i;
if (pos == count - 1)
return 0;
pos++;
}
}
return 1;
}
int
pdf_get_catalog_id(pdf_object_t **pdf)
{
if (*pdf == NULL)
return 1;
int catalog_id = 0;
pdf_object_t *ptr = (*pdf)->next;
while (ptr != NULL) {
if (ptr->dictionary != NULL &&
memmem(ptr->dictionary, ptr->dictionary_size,
"/Catalog", 8) != NULL)
catalog_id = ptr->id;
ptr = ptr->next;
}
return catalog_id;
}
int
pdf_get_xref_id(pdf_object_t **pdf)
{
if (*pdf == NULL)
return 1;
int xref_id = 0;
pdf_object_t *ptr = (*pdf)->next;
while (ptr != NULL) {
if (ptr->dictionary != NULL &&
memmem(ptr->dictionary, ptr->dictionary_size,
"/XRef", 5) != NULL)
xref_id = ptr->id;
ptr = ptr->next;
}
return xref_id;
}
int
pdf_get_parent_id(pdf_object_t **pdf, int **id)
{
if (*pdf == NULL || *id != NULL)
return 1;
int id_size = 1;
*id = malloc(sizeof(int));
if (*id == NULL)
return 1;
(*id)[0] = 0;
pdf_object_t *ptr = (*pdf)->next;
char *head;
char *tail;
char str[8];
int str_val;
int *ret;
while (ptr != NULL) {
if (ptr->dictionary != NULL &&
(head = memmem(ptr->dictionary, ptr->dictionary_size,
"/Parent ", 8)) != NULL &&
(tail = strchr(head + 8, ' ')) != NULL) {
memset(str, 0, 8);
memcpy(str, head + 8, (tail - head) - 8);
str_val = atoi(str);
if (!_id_in(str_val, *id)) {
ret = realloc(*id, ++id_size * sizeof(int));
if (ret == NULL)
return 1;
else
*id = ret;
(*id)[0]++;
(*id)[id_size - 1] = str_val;
}
}
ptr = ptr->next;
}
return 0;
}
int
pdf_get_kid_id(pdf_object_t **pdf, int id, int **kid)
{
if (*pdf == NULL || *kid != NULL)
return 1;
int kid_size = 1;
*kid = malloc(sizeof(int));
if (*kid == NULL)
return 1;
pdf_object_t *ptr = (*pdf)->next;
char str[32];
int *ret;
snprintf(str, 32, "/Parent %d 0 R", id);
while (ptr != NULL) {
if (ptr->id == id) {
(*kid)[0] = 0;
return 1;
}
if (ptr->dictionary != NULL &&
memmem(ptr->dictionary, ptr->dictionary_size,
str, strlen(str)) != NULL) {
ret = realloc(*kid, ++kid_size * sizeof(int));
if (ret == NULL)
return 1;
else
*kid = ret;
(*kid)[kid_size - 1] = ptr->id;
}
ptr = ptr->next;
}
(*kid)[0] = kid_size - 1;
return 0;
}
int
pdf_get_kid_count(pdf_object_t **pdf, int id)
{
if (*pdf == NULL || id <= 0)
return 1;
int count = 0;
pdf_object_t *ptr = (*pdf)->next;
char id_str[32];
char *pos;
char str[8];
int str_val;
snprintf(id_str, 32, "/Parent %d 0 R", id);
while (ptr != NULL) {
if (ptr->dictionary != NULL &&
memmem(ptr->dictionary, ptr->dictionary_size,
id_str, strlen(id_str)) != NULL &&
(pos = memmem(ptr->dictionary, ptr->dictionary_size,
"/Count ", 7)) != NULL) {
for (int i = 8; i >= 0; i--) {
if (i + 7 <= ptr->dictionary_size - (pos - ptr->dictionary) &&
pos[i + 7] >= '0' && pos[i + 7] <= '9') {
memset(str, 0, 8);
memcpy(str, pos + 7, i + 1);
str_val = atoi(str);
count += str_val;
break;
}
}
}
ptr = ptr->next;
}
return count;
}