/*
* Copyright (c) 2020-2023, yzrh <yzrh@noema.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "version.h"
#include "md5.h"
#include "pdf.h"
static int
_info_obj(pdf_object_t **pdf)
{
char dictionary[128] = "<<\n"
"/Producer (Melon " VERSION "." RELEASE "." PATCH EXTRA ")\n"
"/CreationDate (D:";
char buf[64];
time_t timestamp = time(NULL);
strftime(buf, 64, "%Y%m%d%H%M%S", gmtime(×tamp));
strcat(dictionary, buf);
strcat(dictionary, "+00'00')\n>>");
return pdf_obj_append(pdf, 0, NULL, dictionary, NULL, 0);
}
int
pdf_dump_obj(pdf_object_t **pdf, FILE **fp)
{
if (*pdf == NULL || *fp == NULL || _info_obj(pdf) != 0)
return 1;
long cur;
pdf_object_t *ptr = (*pdf)->next;
while (ptr != NULL) {
ptr->address = cur = ftell(*fp);
fprintf(*fp, "%d 0 obj\n", ptr->id);
if (ptr->dictionary != NULL) {
fwrite(ptr->dictionary, ptr->dictionary_size, 1, *fp);
fputs("\n", *fp);
} else if (ptr->object != NULL) {
fwrite(ptr->object, ptr->object_size, 1, *fp);
fputs("\n", *fp);
} else if (ptr->stream == NULL) {
fputs("null\n", *fp);
}
if (ptr->stream != NULL) {
fputs("stream\r\n", *fp);
fwrite(ptr->stream, ptr->stream_size, 1, *fp);
fputs("endstream\n", *fp);
}
fputs("endobj\n", *fp);
ptr->size = ftell(*fp) - cur;
ptr = ptr->next;
}
return 0;
}
int
pdf_dump_header(pdf_object_t **pdf, FILE **fp)
{
if (*pdf == NULL || *fp == NULL)
return 1;
fputs("%PDF-1.7\n", *fp);
const unsigned char bin[4] = {
0xf6,
0xe4,
0xfc,
0xdf,
};
fputs("%", *fp);
fwrite(bin, 4, 1, *fp);
fputs("\n", *fp);
return 0;
}
int
pdf_dump_xref(pdf_object_t **pdf, FILE **fp)
{
if (*pdf == NULL || *fp == NULL)
return 1;
fputs("xref\n", *fp);
pdf_object_t *ptr = *pdf;
pdf_object_t *start = ptr;
int count = 1;
while (ptr != NULL) {
if (ptr->next == NULL ||
(ptr->next != NULL && ptr->next->id != ptr->id + 1)) {
fprintf(*fp, "%d %d\n", start->id, count);
for (; count > 0; count--) {
fprintf(*fp, "%010d %05d %s\r\n",
start->address,
start->address > 0 ? 0 : 65535,
start->size > 0 ? "n" : "f");
start = start->next;
}
if (ptr->next != NULL)
start = ptr->next;
}
ptr = ptr->next;
count++;
}
return 0;
}
int
pdf_dump_trailer(pdf_object_t **pdf, FILE **fp, int xref)
{
if (*pdf == NULL || *fp == NULL)
return 1;
fputs("trailer\n", *fp);
fputs("<<\n", *fp);
/*
* File identifiers should be generated using
* (a) Current time
* (b) File path
* (c) Size of file
* (d) Values of all entries in the
* file's document information dictionary
*
* It is recommended to be computed according to RFC 1321
*/
time_t timestamp = time(NULL);
int size = pdf_get_size(pdf);
int buf_size;
char buf[64];
#ifdef __ILP32__
buf_size = snprintf(buf, 64, "%x%x", timestamp, size);
#else
buf_size = snprintf(buf, 64, "%lx%x", timestamp, size);
#endif
int fid_size;
unsigned char *fid;
if (strmd5(&fid, &fid_size, (unsigned char *) buf, buf_size) != 0)
return 1;
pdf_object_t *ptr = *pdf;
while (ptr->next != NULL)
ptr = ptr->next;
fprintf(*fp,
"/Size %d\n/Root %d 0 R\n/Info %d 0 R\n",
ptr->id + 1,
pdf_get_catalog_id(pdf),
ptr->id);
fputs("/ID [", *fp);
for (int i = 0; i < 2; i++) {
fputs("<", *fp);
for (int j = 0; j < fid_size; j++)
fprintf(*fp, "%02x", fid[j]);
fputs(">", *fp);
if (i < 1)
fputs(" ", *fp);
}
fputs("]\n", *fp);
fputs(">>\n", *fp);
fputs("startxref\n", *fp);
fprintf(*fp, "%d\n", xref);
fputs("%%EOF\n", *fp);
free(fid);
return 0;
}