Examples
Integration Examples
FetchContent Integration — FetchContent integration with cross-platform testing
API Usage Examples
merge.c — File merge
extract.c — Image extraction
filter.c — Compression filters
sign.c — Digital signature
sign_custom.c — Custom digital signature using interface callbacks
verify.c — Signature verification
validate.c — File structure validation
decrypt.c — File decryption
write_custom.c — Custom file writer callbacks
Utilities
Print library info
error_type process_library_info() {
// Misc
string_type library_author = NULL;
// Version info
integer_type library_version_major = 0;
integer_type library_version_minor = 0;
integer_type library_version_patch = 0;
integer_type library_version_build = 0;
// Build time information
integer_type library_build_day = 0;
integer_type library_build_month = 0;
integer_type library_build_year = 0;
RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetVersionMajor(&library_version_major));
RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetVersionMinor(&library_version_minor));
RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetVersionPatch(&library_version_patch));
RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetVersionBuild(&library_version_build));
RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetAuthor(&library_author));
RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetBuildDay(&library_build_day));
RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetBuildMonth(&library_build_month));
RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetBuildYear(&library_build_year));
print_text("Library vanillapdf %d.%d.%d.%d by %s\n",
library_version_major,
library_version_minor,
library_version_patch,
library_version_build,
library_author
);
print_text("Built on %d.%d.%d\n",
library_build_day,
library_build_month,
library_build_year
);
return VANILLAPDF_TEST_ERROR_SUCCESS;
}
Print last error
error_type print_last_error() {
error_type error = 0;
char* error_message = NULL;
char* error_code_name = NULL;
size_type error_code_name_length = 0;
size_type error_message_length = 0;
RETURN_ERROR_IF_NOT_SUCCESS(Errors_GetLastError(&error));
// Last error message
RETURN_ERROR_IF_NOT_SUCCESS(Errors_GetLastErrorMessageLength(&error_message_length));
if (error_message_length >= SIZE_MAX) {
unsigned long long length_converted = error_message_length;
printf("Buffer size is too big: %llu bytes\n", length_converted);
return VANILLAPDF_TEST_ERROR_FAILURE;
}
error_message = (char*) calloc(error_message_length, sizeof(char));
if (NULL == error_message) {
unsigned long long length_converted = error_message_length;
printf("Could not allocate memory: %llu bytes\n", length_converted);
return VANILLAPDF_TEST_ERROR_FAILURE;
}
RETURN_ERROR_IF_NOT_SUCCESS(Errors_GetLastErrorMessage(error_message, error_message_length));
// error code name
RETURN_ERROR_IF_NOT_SUCCESS(Errors_GetPrintableErrorTextLength(error, &error_code_name_length));
if (error_code_name_length >= SIZE_MAX) {
unsigned long long length_converted = error_code_name_length;
printf("Buffer size is too big: %llu bytes\n", length_converted);
return VANILLAPDF_TEST_ERROR_FAILURE;
}
error_code_name = (char*) calloc(error_code_name_length, sizeof(char));
if (NULL == error_code_name) {
unsigned long long length_converted = error_code_name_length;
printf("Could not allocate memory: %llu bytes\n", length_converted);
return VANILLAPDF_TEST_ERROR_FAILURE;
}
RETURN_ERROR_IF_NOT_SUCCESS(Errors_GetPrintableErrorText(error, error_code_name, error_code_name_length));
if (error_message_length == 0) {
printf("Error %u (%s)\n", error, error_code_name);
} else {
printf("Error %u (%s): %s\n", error, error_code_name, error_message);
}
free(error_message);
free(error_code_name);
return VANILLAPDF_TEST_ERROR_SUCCESS;
}
Print buffer
error_type process_buffer(BufferHandle* buffer, int nested) {
string_type data = NULL;
char* local_string = NULL;
size_type size = 0;
size_type print_size = 0;
unsigned long long size_converted = 0;
print_spaces(nested);
print_text("Buffer begin\n");
RETURN_ERROR_IF_NOT_SUCCESS(Buffer_GetData(buffer, &data, &size));
if (size >= SIZE_MAX) {
unsigned long long size_long_long = size;
print_text("Buffer size is too big: %llu bytes\n", size_long_long);
return VANILLAPDF_TEST_ERROR_FAILURE;
}
if (size > 0 && data == NULL) {
print_text("Buffer has non-zero size but null data pointer\n");
return VANILLAPDF_TEST_ERROR_FAILURE;
}
print_size = size > 20 ? 10 : size;
size_converted = size;
local_string = (char*) calloc(print_size + 1, sizeof(char));
if (NULL == local_string) {
unsigned long long print_size_converted = print_size;
print_text("Could not allocate memory: %llu bytes\n", print_size_converted + 1);
return VANILLAPDF_TEST_ERROR_FAILURE;
}
if (print_size > 0) {
memcpy(local_string, data, print_size);
}
print_spaces(nested + 1);
print_text("Size: %llu\n", size_converted);
print_spaces(nested + 1);
print_text("Data: %s\n", local_string);
free(local_string);
print_spaces(nested);
print_text("Buffer end\n");
return VANILLAPDF_TEST_ERROR_SUCCESS;
}
Test logging
error_type process_logging() {
// Disable logging for unit testing
RETURN_ERROR_IF_NOT_SUCCESS(Logging_SetSeverity(LoggingSeverity_Off));
return VANILLAPDF_TEST_ERROR_SUCCESS;
}
Print date
error_type process_date(DateHandle* obj, int nested) {
integer_type year = 0;
integer_type month = 0;
integer_type day = 0;
integer_type hour = 0;
integer_type minute = 0;
integer_type second = 0;
TimezoneType timezone;
integer_type hour_offset = 0;
integer_type minute_offset = 0;
print_spaces(nested);
print_text("Date begin\n");
RETURN_ERROR_IF_NOT_SUCCESS(Date_GetYear(obj, &year));
RETURN_ERROR_IF_NOT_SUCCESS(Date_GetMonth(obj, &month));
RETURN_ERROR_IF_NOT_SUCCESS(Date_GetDay(obj, &day));
RETURN_ERROR_IF_NOT_SUCCESS(Date_GetHour(obj, &hour));
RETURN_ERROR_IF_NOT_SUCCESS(Date_GetMinute(obj, &minute));
RETURN_ERROR_IF_NOT_SUCCESS(Date_GetSecond(obj, &second));
RETURN_ERROR_IF_NOT_SUCCESS(Date_GetTimezone(obj, &timezone));
RETURN_ERROR_IF_NOT_SUCCESS(Date_GetHourOffset(obj, &hour_offset));
RETURN_ERROR_IF_NOT_SUCCESS(Date_GetMinuteOffset(obj, &minute_offset));
print_spaces(nested + 1);
if (timezone == TimezoneType_UTC) {
print_text("%04d-%02d-%02d %02d:%02d:%02dZ\n",
year, month, day,
hour, minute, second);
} else {
char timezone_character;
if (timezone == TimezoneType_Later) {
timezone_character = '+';
} else if (timezone == TimezoneType_Earlier) {
timezone_character = '-';
} else {
print_text("Timezone is neither UTC, Earlier nor later\n");
return VANILLAPDF_TEST_ERROR_FAILURE;
}
print_text("%04d-%02d-%02d %02d:%02d:%02d %c%02d:%02d\n",
year, month, day,
hour, minute, second,
timezone_character, hour_offset, minute_offset);
}
print_spaces(nested);
print_text("Date end\n");
return VANILLAPDF_TEST_ERROR_SUCCESS;
}
Validate file structure
RETURN_ERROR_IF_NOT_SUCCESS(FileStructureValidator_Validate(file, &result));
RETURN_ERROR_IF_NOT_SUCCESS(FileStructureValidationResult_IsValid(result, &is_valid));
RETURN_ERROR_IF_NOT_SUCCESS(FileStructureValidationResult_GetIssueCount(result, &issue_count));
RETURN_ERROR_IF_NOT_SUCCESS(FileStructureValidationResult_GetErrorCount(result, &error_count));
RETURN_ERROR_IF_NOT_SUCCESS(FileStructureValidationResult_GetWarningCount(result, &warning_count));
printf("Issues: %llu (%llu error(s), %llu warning(s))\n",
(unsigned long long)issue_count,
(unsigned long long)error_count,
(unsigned long long)warning_count);
for (size_type i = 0; i < issue_count; i++) {
FileStructureIssueHandle* issue = NULL;
FileStructureIssueSeverityType severity = FileStructureIssueSeverity_Undefined;
FileStructureIssueCodeType code = FileStructureIssueCode_Undefined;
BufferHandle* message = NULL;
string_type data = NULL;
size_type size = 0;
RETURN_ERROR_IF_NOT_SUCCESS(FileStructureValidationResult_GetIssueAt(result, i, &issue));
RETURN_ERROR_IF_NOT_SUCCESS(FileStructureIssue_GetSeverity(issue, &severity));
RETURN_ERROR_IF_NOT_SUCCESS(FileStructureIssue_GetCode(issue, &code));
RETURN_ERROR_IF_NOT_SUCCESS(FileStructureIssue_GetMessage(issue, &message));
RETURN_ERROR_IF_NOT_SUCCESS(Buffer_GetData(message, &data, &size));
printf("[severity=%d code=%d]: %.*s\n", (int)severity, (int)code, (int)size, data);
if (message) Buffer_Release(message);
if (issue) FileStructureIssue_Release(issue);
}
Enumerate xref
error_type process_file(FileHandle* file, int nested) {
XrefChainHandle* chain = NULL;
XrefChainIteratorHandle* chain_iterator = NULL;
boolean_type valid = VANILLAPDF_RV_FALSE;
RETURN_ERROR_IF_NOT_SUCCESS(File_XrefChain(file, &chain));
RETURN_ERROR_IF_NOT_SUCCESS(XrefChain_GetIterator(chain, &chain_iterator));
while (VANILLAPDF_ERROR_SUCCESS == XrefChainIterator_IsValid(chain_iterator, &valid)
&& VANILLAPDF_RV_TRUE == valid) {
XrefHandle* xref = NULL;
RETURN_ERROR_IF_NOT_SUCCESS(XrefChainIterator_GetValue(chain_iterator, &xref));
RETURN_ERROR_IF_NOT_SUCCESS(process_xref(xref, nested));
RETURN_ERROR_IF_NOT_SUCCESS(Xref_Release(xref));
RETURN_ERROR_IF_NOT_SUCCESS(XrefChainIterator_Next(chain_iterator));
}
RETURN_ERROR_IF_NOT_SUCCESS(XrefChainIterator_Release(chain_iterator));
RETURN_ERROR_IF_NOT_SUCCESS(XrefChain_Release(chain));
return VANILLAPDF_TEST_ERROR_SUCCESS;
}