Commit e3d3e1d0 authored by Tomáš Stefan's avatar Tomáš Stefan

Reading xref section (with all subsections)

added
  - tests
  - fn add_xref_entry
  - fn free_xref_entry
  - fn xref_init
  - fn xref_free
  - fn read_xref_table
  - fn print_xref
  - fn skip_leading_whitespaces
  - fn parse_keyword
removed
  - modes (also sigil_process -> sigil_verify)
parent 552ea368
......@@ -2,12 +2,33 @@
#define PDF_SIGIL_AUXILIARY_H
#include <stdio.h>
#include <stdint.h>
#ifndef CHAR_T
#define CHAR_T
typedef char char_t;
typedef unsigned char char_t;
#endif /* CHAR_T */
#ifndef SIGIL_ERR_T
#define SIGIL_ERR_T
typedef uint32_t sigil_err_t;
#endif /* SIGIL_ERR_T */
#ifndef KEYWORD_T
#define KEYWORD_T
typedef uint32_t keyword_t;
#endif /* KEYWORD_T */
#ifndef FREE_INDICATOR_T
#define FREE_INDICATOR_T
typedef uint32_t free_indicator_t;
#endif /* FREE_INDICATOR_T */
#define KEYWORD_xref 0
#define KEYWORD_trailer 1
#define IN_USE_ENTRY 0
#define FREE_ENTRY 1
#define COLOR_RED "\x1b[31m"
#define COLOR_GREEN "\x1b[32m"
......@@ -22,8 +43,11 @@ void sigil_zeroize(void *a, size_t bytes);
int is_digit(const char_t c);
int is_whitespace(const char_t c);
int parse_number(FILE *in, size_t *number);
int parse_free_indicator(FILE *in, char_t *result);
sigil_err_t skip_leading_whitespaces(FILE *in);
sigil_err_t parse_number(FILE *in, size_t *number);
sigil_err_t parse_keyword(FILE *in, keyword_t *keyword);
sigil_err_t parse_free_indicator(FILE *in, free_indicator_t *result);
void print_module_name(const char *module_name, int verbosity);
void print_module_result(int result, int verbosity);
......
......@@ -5,9 +5,13 @@
#ifndef CHAR_T
#define CHAR_T
typedef char char_t;
typedef unsigned char char_t;
#endif /* CHAR_T */
#ifndef SIGIL_ERR_T
#define SIGIL_ERR_T
typedef uint32_t sigil_err_t;
#endif /* SIGIL_ERR_T */
#define ERR_NO 0x0000 // [_|_|_|x] 0000 0000
#define ERR_ALLOC 0x0001 // [_|_|_|x] 0000 0001
......@@ -27,9 +31,7 @@
#define ERR_15 0x4000 // [_|_|x|_] 0100 0000
#define ERR_16 0x8000 // [_|_|x|_] 1000 0000
typedef uint32_t sigil_err_t;
const char_t *sigil_err_string(sigil_err_t err);
const char *sigil_err_string(sigil_err_t err);
int sigil_error_self_test(int verbosity);
......
#ifndef PDF_SIGIL_HEADER_H
#define PDF_SIGIL_HEADER_H
#include "error.h"
#include "sigil.h"
#ifndef SIGIL_ERR_T
#define SIGIL_ERR_T
typedef uint32_t sigil_err_t;
#endif /* SIGIL_ERR_T */
sigil_err_t process_header(sigil_t *sgl);
......
......@@ -2,13 +2,17 @@
#define PDF_SIGIL_SIGIL_H
#include <stdio.h>
#include "error.h"
#ifndef CHAR_T
#define CHAR_T
typedef char char_t;
typedef unsigned char char_t;
#endif /* CHAR_T */
#ifndef SIGIL_ERR_T
#define SIGIL_ERR_T
typedef uint32_t sigil_err_t;
#endif /* SIGIL_ERR_T */
#ifndef XREF_T
#define XREF_T
typedef struct {
......@@ -26,17 +30,9 @@
#define XREF_TYPE_TABLE 1
#define XREF_TYPE_STREAM 2
#define MODE_UNSET 0
#define MODE_VERIFY 1
#define MODE_SIGN 2
typedef uint32_t mode_t;
struct xref_t;
typedef struct {
FILE *file;
char_t *filepath;
mode_t mode;
char *filepath;
short pdf_x, /* numbers from PDF header */
pdf_y; /* %PDF-<pdf_x>.<pdf_y> */
short xref_type;
......@@ -48,13 +44,11 @@ typedef struct {
sigil_err_t sigil_init(sigil_t **sgl);
sigil_err_t sigil_setup_file(sigil_t *sgl, const char_t *filepath);
sigil_err_t sigil_setup_mode(sigil_t *sgl, mode_t mode);
sigil_err_t sigil_setup_file(sigil_t *sgl, const char *filepath);
sigil_err_t sigil_process(sigil_t *sgl);
sigil_err_t sigil_verify(sigil_t *sgl);
// ... get functions TBD
// ... get functions TODO
void sigil_free(sigil_t *sgl);
......
#ifndef PDF_SIGIL_TRAILER_H
#define PDF_SIGIL_TRAILER_H
#include "error.h"
#ifndef SIGIL_ERR_T
#define SIGIL_ERR_T
typedef uint32_t sigil_err_t;
#endif /* SIGIL_ERR_T */
sigil_err_t process_trailer(sigil_t *sgl);
......
#ifndef PDF_SIGIL_XREF_H
#define PDF_SIGIL_XREF_H
#include "error.h"
#include "sigil.h"
#ifndef SIGIL_ERR_T
#define SIGIL_ERR_T
typedef uint32_t sigil_err_t;
#endif /* SIGIL_ERR_T */
#ifndef XREF_T
#define XREF_T
typedef struct {
size_t byte_offset;
size_t generation_num;
} xref_entry_t;
typedef struct {
xref_entry_t **entry;
size_t capacity;
} xref_t;
typedef struct {
size_t byte_offset;
size_t generation_num;
} xref_entry_t;
typedef struct {
xref_entry_t **entry;
size_t capacity;
} xref_t;
#endif /* XREF_T */
xref_t *new_xref();
xref_t *xref_init();
void free_xref(xref_t *xref);
void xref_free(xref_t *xref);
sigil_err_t read_startxref(sigil_t *sgl);
......
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "auxiliary.h"
#include "error.h"
void sigil_zeroize(void *a, size_t bytes)
{
......@@ -29,46 +31,113 @@ int is_whitespace(const char_t c)
c == 0x20); // space
}
int parse_number(FILE *in, size_t *number)
sigil_err_t skip_leading_whitespaces(FILE *in)
{
char c;
char_t c;
while ((c = fgetc(in)) != EOF && is_whitespace(c))
;
if (c == EOF)
return (sigil_err_t)ERR_PDF_CONT;
if (ungetc(c, in) != c)
return (sigil_err_t)ERR_IO;
return (sigil_err_t)ERR_NO;
}
sigil_err_t parse_number(FILE *in, size_t *number)
{
char_t c;
int digits = 0;
sigil_err_t err;
*number = 0;
// skip leading whitespaces
while ((c = fgetc(in)) != EOF && is_whitespace(c))
;
err = skip_leading_whitespaces(in);
if (err != ERR_NO)
return err;
// number
do {
while ((c = fgetc(in)) != EOF) {
if (!is_digit(c)) {
if (ungetc(c, in) != c)
return 1;
return digits == 0;
return (sigil_err_t)ERR_IO;
if (digits > 0) {
return (sigil_err_t)ERR_NO;
} else {
return (sigil_err_t)ERR_PDF_CONT;
}
}
*number = 10 * *number + c - '0';
digits++;
} while ((c = fgetc(in)) != EOF);
}
return 1;
return (sigil_err_t)ERR_PDF_CONT;
}
int parse_free_indicator(FILE *in, char_t *result)
sigil_err_t parse_keyword(FILE *in, keyword_t *keyword)
{
sigil_err_t err;
int count = 0;
const int keyword_max = 10;
char tmp[keyword_max],
c;
sigil_zeroize(tmp, keyword_max * sizeof(*tmp));
err = skip_leading_whitespaces(in);
if (err != ERR_NO)
return err;
while ((c = fgetc(in)) != EOF) {
if (is_whitespace(c)) {
if (count <= 0)
return (sigil_err_t)ERR_PDF_CONT;
if (ungetc(c, in) != c)
return (sigil_err_t)ERR_IO;
if (strncmp(tmp, "xref", 4) == 0) {
*keyword = KEYWORD_xref;
return (sigil_err_t)ERR_NO;
}
if (strncmp(tmp, "trailer", 7) == 0) {
*keyword = KEYWORD_trailer;
return (sigil_err_t)ERR_NO;
}
return (sigil_err_t)ERR_PDF_CONT;
} else {
if (count >= keyword_max - 1)
return (sigil_err_t)ERR_PDF_CONT;
tmp[count] = c;
count++;
}
}
return (sigil_err_t)ERR_PDF_CONT;
}
sigil_err_t parse_free_indicator(FILE *in, free_indicator_t *result)
{
sigil_err_t err;
char c;
// skip leading whitespaces
while ((c = fgetc(in)) != EOF && is_whitespace(c))
;
err = skip_leading_whitespaces(in);
if (err != ERR_NO)
return err;
c = fgetc(in);
switch(c) {
case 'f':
*result = FREE_ENTRY;
return (sigil_err_t)ERR_NO;
case 'n':
*result = c;
return 0;
*result = IN_USE_ENTRY;
return (sigil_err_t)ERR_NO;
default:
return 1;
return (sigil_err_t)ERR_PDF_CONT;
}
}
......@@ -97,7 +166,7 @@ void print_test_item(const char *test_name, int verbosity)
if (verbosity < 2)
return;
printf(" - %-30s", test_name);
printf(" - %-32s", test_name);
}
void print_test_result(int result, int verbosity)
......@@ -177,6 +246,138 @@ int sigil_auxiliary_self_test(int verbosity)
print_test_result(1, verbosity);
// TEST: fn skip_leading_whitespaces
print_test_item("fn skip_leading_whitespaces", verbosity);
{
char *sstream_1 = "x";
char *sstream_2 = "\x00\x09\x0a\x0c\x0d\x20x";
FILE *file;
file = fmemopen(sstream_1,
(strlen(sstream_1) + 1) * sizeof(*sstream_1),
"r");
if (file == NULL)
goto failed;
if (skip_leading_whitespaces(file) != ERR_NO ||
fgetc(file) != 'x')
{
goto failed;
}
fclose(file);
file = fmemopen(sstream_2,
(7 + 1) * sizeof(*sstream_2), // cannot use strlen
"r");
if (file == NULL)
goto failed;
if (skip_leading_whitespaces(file) != ERR_NO ||
fgetc(file) != 'x')
{
goto failed;
}
fclose(file);
}
print_test_result(1, verbosity);
// TEST: fn parse_number
print_test_item("fn parse_number", verbosity);
{
char *sstream = "0123456789 42";
size_t result = 0;
FILE *file;
file = fmemopen(sstream,
(strlen(sstream) + 1) * sizeof(*sstream),
"r");
if (file == NULL)
goto failed;
if (parse_number(file, &result) != ERR_NO ||
result != 123456789)
{
goto failed;
}
if (parse_number(file, &result) != ERR_NO ||
result != 42)
{
goto failed;
}
fclose(file);
}
print_test_result(1, verbosity);
// TEST: fn parse_keyword
print_test_item("fn parse_keyword", verbosity);
{
char *sstream = " xref \n trailer";
keyword_t result;
FILE *file;
file = fmemopen(sstream,
(strlen(sstream) + 1) * sizeof(*sstream),
"r");
if (file == NULL)
goto failed;
if (parse_keyword(file, &result) != ERR_NO ||
result != KEYWORD_xref)
{
goto failed;
}
if (parse_keyword(file, &result) != ERR_NO ||
result != KEYWORD_trailer)
{
goto failed;
}
fclose(file);
}
print_test_result(1, verbosity);
// TEST: fn parse_free_indicator
print_test_item("fn parse_free_indicator", verbosity);
{
char *sstream = " f n";
free_indicator_t result;
FILE *file;
file = fmemopen(sstream,
(strlen(sstream) + 1) * sizeof(*sstream),
"r");
if (file == NULL)
goto failed;
if (parse_free_indicator(file, &result) != ERR_NO ||
result != FREE_ENTRY)
{
goto failed;
}
if (parse_free_indicator(file, &result) != ERR_NO ||
result != IN_USE_ENTRY)
{
goto failed;
}
fclose(file);
}
print_test_result(1, verbosity);
// all tests done
print_module_result(1, verbosity);
return 0;
......
......@@ -4,7 +4,7 @@
#include "error.h"
const char_t *sigil_err_string(sigil_err_t err)
const char *sigil_err_string(sigil_err_t err)
{
if (err == ERR_NO)
return "NO ERROR";
......
......@@ -81,19 +81,18 @@ int sigil_header_self_test(int verbosity)
{
print_module_name("header", verbosity);
// prepare
sigil_t *sgl = NULL;
if (sigil_init(&sgl) != ERR_NO)
goto failed;
// TEST: correct_1
print_test_item("correct_1", verbosity);
print_test_item("fn process_header", verbosity);
char_t *correct_1 = "\x25PDF-1.1\n" \
"abcdefghijklmnopqrstuvwxyz";
sgl->file = fmemopen(correct_1,
(strlen(correct_1) + 1) * sizeof(*correct_1),
char *sstream_1 = "\x25PDF-1.1\n" \
"abcdefghijklmnopqrstuvwxyz";
sgl->file = fmemopen(sstream_1,
(strlen(sstream_1) + 1) * sizeof(*sstream_1),
"r");
if (sgl->file == NULL)
goto failed;
......@@ -106,25 +105,20 @@ int sigil_header_self_test(int verbosity)
goto failed;
}
print_test_result(1, verbosity);
fclose(sgl->file);
sgl->file = NULL;
// TEST: correct_2
print_test_item("correct_2", verbosity);
char_t *correct_2 = "\x1a\x5e\x93\x7e\x6f\x3c\x6a\x71\xbf\xda\x54\x91\xe5" \
"\x86\x08\x84\xaf\x8e\x89\x44\xab\xc4\x58\x0c\xb9\x31" \
"\xd3\x8c\x0f\xc0\x43\x1a\xa5\x07\x4f\xe2\x98\xb3\xd8" \
"\x53\x4b\x5d\x4b\xd6\x48\x26\x98\x09\xde\x0d" \
"\x25PDF-1.2" \
"\x55\xa1\x77\xd3\x47\xab\xc6\x87\xf3\xbc\x2d\x8a\x9f" \
"\x0e\x47\xbb\x74\xd2\x71\x28\x94\x53\x92\xae\x2b\x17" \
"\xd0\x6a\x9c\x13\x84\xc1\x07\x44\xc0\x81\xb8\xd6\x9c" \
"\x31\x08\x13\xd4\xc2\xd6\x2d\xaf\xfb\xea\x6f";
sgl->file = fmemopen(correct_2,
(strlen(correct_2) + 1) * sizeof(*correct_2),
char *sstream_2 = "\x1a\x5e\x93\x7e\x6f\x3c\x6a\x71\xbf\xda\x54\x91\xe5"\
"\x86\x08\x84\xaf\x8e\x89\x44\xab\xc4\x58\x0c\xb9\x31"\
"\xd3\x8c\x0f\xc0\x43\x1a\xa5\x07\x4f\xe2\x98\xb3\xd8"\
"\x53\x4b\x5d\x4b\xd6\x48\x26\x98\x09\xde\x0d" \
"\x25PDF-1.2" \
"\x55\xa1\x77\xd3\x47\xab\xc6\x87\xf3\xbc\x2d\x8a\x9f"\
"\x0e\x47\xbb\x74\xd2\x71\x28\x94\x53\x92\xae\x2b\x17"\
"\xd0\x6a\x9c\x13\x84\xc1\x07\x44\xc0\x81\xb8\xd6\x9c"\
"\x31\x08\x13\xd4\xc2\xd6\x2d\xaf\xfb\xea\x6f";
sgl->file = fmemopen(sstream_2,
(strlen(sstream_2) + 1) * sizeof(*sstream_2),
"r");
if (sgl->file == NULL)
goto failed;
......@@ -137,17 +131,12 @@ int sigil_header_self_test(int verbosity)
goto failed;
}
print_test_result(1, verbosity);
fclose(sgl->file);
sgl->file = NULL;
// TEST: wrong_1
print_test_item("wrong_1", verbosity);
char_t *wrong_1 = "\x25\x25PPD\x25PDF-\x25PDF-1\x25PDF-1..@PDF-1.3";
sgl->file = fmemopen(wrong_1,
(strlen(wrong_1) + 1) * sizeof(*wrong_1),
char *sstream_3 = "\x25\x25PPD\x25PDF-\x25PDF-1\x25PDF-1..@PDF-1.3";
sgl->file = fmemopen(sstream_3,
(strlen(sstream_3) + 1) * sizeof(*sstream_3),
"r");
if (sgl->file == NULL)
goto failed;
......@@ -155,18 +144,17 @@ int sigil_header_self_test(int verbosity)
if (process_header(sgl) == ERR_NO)
goto failed;
print_test_result(1, verbosity);
sigil_free(sgl);
fclose(sgl->file);
sgl->file = NULL;
print_test_result(1, verbosity);
// all tests done
print_module_result(1, verbosity);
return 0;
failed:
if (sgl->file)
fclose(sgl->file);
if (sgl)
sigil_free(sgl);
print_test_result(0, verbosity);
print_module_result(0, verbosity);
......
......@@ -2,20 +2,13 @@
#include <stdio.h>
#include <string.h>
#include "auxiliary.h"
#include "error.h"
#include "header.h"
#include "sigil.h"
#include "trailer.h"
#include "xref.h"
static sigil_err_t validate_mode(mode_t mode)
{
if (mode != MODE_VERIFY && mode != MODE_SIGN)
return (sigil_err_t)ERR_PARAM;
return (sigil_err_t)ERR_NO;
}
sigil_err_t sigil_init(sigil_t **sgl)
{
// function parameter checks
......@@ -30,7 +23,6 @@ sigil_err_t sigil_init(sigil_t **sgl)
// set default values
(*sgl)->file = NULL;
(*sgl)->filepath = NULL;
(*sgl)->mode = MODE_UNSET;
(*sgl)->pdf_x = 0;
(*sgl)->pdf_y = 0;
(*sgl)->xref_type = XREF_TYPE_UNSET;
......@@ -42,7 +34,7 @@ sigil_err_t sigil_init(sigil_t **sgl)
return (sigil_err_t)ERR_NO;
}
sigil_err_t sigil_setup_file(sigil_t *sgl, const char_t *filepath)
sigil_err_t sigil_setup_file(sigil_t *sgl, const char *filepath)
{
// function parameter checks
if (sgl == NULL || filepath == NULL)
......@@ -66,36 +58,16 @@ sigil_err_t sigil_setup_file(sigil_t *sgl, const char_t *filepath)
return (sigil_err_t)ERR_NO;
}
sigil_err_t sigil_setup_mode(sigil_t *sgl, mode_t mode)
{
// function parameter checks
if (sgl == NULL || validate_mode(mode) != ERR_NO)
return (sigil_err_t)ERR_PARAM;
sgl->mode = mode;
return (sigil_err_t)ERR_NO;
}
sigil_err_t sigil_process(sigil_t *sgl)
sigil_err_t sigil_verify(sigil_t *sgl)
{
sigil_err_t err;
// function parameter checks
if (sgl == NULL || sgl->filepath == NULL ||
validate_mode(sgl->mode) != ERR_NO )
{
if (sgl == NULL || sgl->filepath == NULL)
return (sigil_err_t)ERR_PARAM;
}
// open provided file
if (sgl->mode == MODE_VERIFY) {
sgl->file = fopen(sgl->filepath, "r");
} else if (sgl->mode == MODE_SIGN) {
sgl->file = fopen(sgl->filepath, "r+");
}
if (sgl->file == NULL)
if ((sgl->file = fopen(sgl->filepath, "r")) == NULL)
return (sigil_err_t)ERR_IO;
// process header - %PDF-<pdf_x>.<pdf_y>
......@@ -108,6 +80,10 @@ sigil_err_t sigil_process(sigil_t *sgl)
if (err != ERR_NO)
return err;
err = process_trailer(sgl);
if (err != ERR_NO)
return err;
// TODO
return (sigil_err_t)ERR_NO;
......@@ -121,7 +97,7 @@ void sigil_free(sigil_t *sgl)
if (sgl->filepath)
free(sgl->filepath);
if (sgl->xref)
free_xref(sgl->xref);
xref_free(sgl->xref);
free(sgl);
sgl = NULL;
}
......@@ -129,78 +105,69 @@ void sigil_free(sigil_t *sgl)
int sigil_sigil_self_test(int verbosity)
{
print_module_name("sigil", verbosity);
// TEST: fn validate_mode
print_test_item("fn validate_mode", verbosity);
if (validate_mode(MODE_UNSET) != ERR_PARAM ||
validate_mode(MODE_VERIFY) != ERR_NO ||
validate_mode(MODE_SIGN) != ERR_NO ||
validate_mode(0xffff) != ERR_PARAM )
{
goto failed;
}
sigil_err_t err;
sigil_t *sgl = NULL;
print_test_result(1, verbosity);
print_module_name("sigil", verbosity);
// TEST: fn sigil_init
print_test_item("fn sigil_init", verbosity);
sigil_t *sgl = NULL;
sigil_err_t err = sigil_init(&sgl);
if (err != ERR_NO || sgl == NULL)
goto failed;
{
sgl = NULL;
err = sigil_init(&sgl);
if (err != ERR_NO || sgl == NULL)
goto failed;
sigil_free(sgl);
}
print_test_result(1, verbosity);
// TEST: fn sigil_setup_file
print_test_item("fn sigil_setup_file", verbosity);
err = sigil_setup_file(sgl, "test/uznavany_bez_razitka_bez_revinfo_27_2_2012_CMS.pdf");
if (err != ERR_NO || sgl->filepath == NULL)
goto failed;
print_test_result(1, verbosity);
// TEST: fn sigil_setup_mode
print_test_item("fn sigil_setup_mode", verbosity);
{
sgl = NULL;
err = sigil_init(&sgl);
if (err != ERR_NO || sgl == NULL)
goto failed;