aboutsummaryrefslogblamecommitdiffstats
path: root/src/pdf_writer.c
blob: 465d26bfaa847c557d06eba52811673d57a28fb3 (plain) (tree)
1
2
3
4
5
6
7
8
9
  
                                                 




                                      

                 
                















                                                    
                                              
                                                                              

                                                 
                                                                      

                                                 
                                             
                 






































































































                                                                              


                                                              
                                                               
      
 

                           
 

                                                                          






















                                                      
                                                  

















                                                     

                  

                 
/*
 * Copyright (c) 2020-2022, yzrh <yzrh@noema.org>
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdlib.h>
#include <time.h>

#include "md5.h"
#include "pdf.h"

int
pdf_dump_obj(pdf_object_t **pdf, FILE **fp)
{
	if (*pdf == NULL || *fp == NULL)
		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;

	/*
	 * TODO: Document information dictionary
	 * `"/Producer (Melon)"'
	 * `"/CreationDate (D:YYYYMMDDHHmmSS+00'00')"'
	 *
	 * Trailer dictionary
	 * `"/Info %d 0 R"'
	 */
	fprintf(*fp,
		"/Size %d\n/Root %d 0 R\n",
		ptr->id + 1,
		pdf_get_catalog_id(pdf));

	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;
}