/*
* Copyright (c) 2020-2022, yzrh <yzrh@noema.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include "cnki.h"
#include "iconv.h"
#include "pdf.h"
/*
* It will write first, list, and count to *stat
* so that when called recursively, it knows
* what to do
*/
static int
_outline(pdf_object_t **pdf, object_outline_tree_t **outline_tree, int id, int **stat)
{
*stat = malloc(3 * sizeof(int));
if (*stat == NULL)
return 1;
int size;
char *str;
int *ret;
char buf[64];
char dictionary[1024];
object_outline_tree_t *ptr = *outline_tree;
(*stat)[0] = ptr->id;
(*stat)[2] = 0;
while (ptr != NULL) {
memset(dictionary, 0, 1024);
strcat(dictionary, "<<\n");
size = 514;
str = NULL;
if (strconv(&str, "UTF-16BE",
ptr->item->title, "GB18030",
&size) == 0) {
strcat(dictionary, "/Title <feff");
for (int i = 0; i < size - 2; i++) {
snprintf(buf, 64, "%02x", (unsigned char) str[i]);
strcat(dictionary, buf);
}
strcat(dictionary, ">\n");
}
free(str);
snprintf(buf, 64, "/Parent %d 0 R\n", id);
strcat(dictionary, buf);
if (ptr->up != NULL && ptr->up->id != id) {
snprintf(buf, 64, "/Prev %d 0 R\n", ptr->up->id);
strcat(dictionary, buf);
}
if (ptr->left != NULL) {
snprintf(buf, 64, "/Next %d 0 R\n", ptr->left->id);
strcat(dictionary, buf);
}
if (ptr->right != NULL) {
_outline(pdf, &ptr->right, ptr->id, &ret);
snprintf(buf, 64, "/First %d 0 R\n", ret[0]);
strcat(dictionary, buf);
snprintf(buf, 64, "/Last %d 0 R\n", ret[1]);
strcat(dictionary, buf);
snprintf(buf, 64, "/Count -%d\n", ret[2]);
strcat(dictionary, buf);
free(ret);
}
/* Page starts from 0 */
snprintf(buf, 64, "/Dest [%d /XYZ null null null]\n>>",
atoi(ptr->item->page) - 1);
strcat(dictionary, buf);
pdf_obj_append(pdf, ptr->id, NULL, dictionary, NULL, 0);
if (ptr->left == NULL)
(*stat)[1] = ptr->id;
(*stat)[2]++;
ptr = ptr->left;
}
return 0;
}
static int
_outline_free(object_outline_tree_t **outline_tree)
{
object_outline_tree_t *ptr = *outline_tree;
for (;;) {
if (ptr->right != NULL)
_outline_free(&ptr->right);
if (ptr->left != NULL) {
ptr = ptr->left;
free(ptr->up);
} else {
free(ptr);
break;
}
}
return 0;
}
int
pdf_cnki_outline(pdf_object_t **pdf, object_outline_t **outline, int **ids)
{
if (*pdf == NULL || *outline == NULL || *ids == NULL)
return 1;
object_outline_tree_t *outline_tree = NULL;
cnki_outline_tree(&outline_tree, outline, *ids);
char buf[128];
int *ret;
_outline(pdf, &outline_tree->left, outline_tree->id, &ret);
_outline_free(&outline_tree);
snprintf(buf, 128,
"<<\n/Type Outlines\n/First %d 0 R\n/Last %d 0 R\n/Count %d\n>>",
ret[0], ret[1], ret[2]);
free(ret);
pdf_obj_append(pdf, (*ids)[0], NULL, buf, NULL, 0);
return 0;
}