ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_export_epub.c File Reference

Emit deterministic fixed-layout EPUB3 chapter containers. More...

#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "mdl_export.h"
#include "mdl_export_epub_internal.h"
#include "mdl_export_internal.h"
#include "mdl_sanitize.h"
#include "mdl_urlname.h"
#include "miniz.h"
#include "ra8_attributes.h"
Include dependency graph for mdl_export_epub.c:

Go to the source code of this file.

Functions

static ra8_err_t internal_epub_media_type_from_sniff (mdl_storage_t *storage, const char *dir, const char *name, const char **out)
 Classify one page's image media type from sniffed portable bytes.
static void internal_epub_media_type_from_suffix (const char *name, const char **out)
 Classify one page's image media type from its filename suffix.
static ra8_err_t internal_epub_media_type (mdl_storage_t *storage, const char *dir, const char *name, const char **out)
 Resolve one page's image media type from portable bytes then suffix.
bool priv_mdl_epub_str_cat (char *dst, size_t cap, const char *text)
 Append text to NUL-terminated dst; report whether it fully fit.
bool priv_mdl_epub_add_str (mz_zip_archive *zip, const char *name, const char *body)
 Add an in-memory string as a stored ZIP entry.
static ra8_err_t internal_epub_add_external_cover (mz_zip_archive *zip, mdl_storage_t *storage, const mdl_external_cover_t *cover, char *mani, size_t cap)
 Store and declare a validated external EPUB cover.
static ra8_err_t internal_epub_append_frags (char *mani, char *spine, char *nav, size_t cap, const char *esc_name, const char *media, size_t idx, unsigned n, bool is_cover)
 Append one page's manifest, spine, and navigation fragments.
static bool internal_epub_page_is_cover (const mdl_export_meta_t *meta, const char *name, size_t idx)
 Is one exported image the publication's declared cover?
static ra8_err_t internal_epub_write_page_xhtml (mz_zip_archive *zip, const char *name, unsigned n, char *esc, size_t esc_cap)
 Escape a page name and write its XHTML wrapper into the ZIP.
static ra8_err_t internal_epub_add_page (mdl_storage_t *storage, mz_zip_archive *zip, const char *dir, const char *name, size_t idx, char *mani, char *spine, char *nav, size_t cap, const mdl_export_meta_t *meta)
 Add one fixed-layout EPUB page and its image.
static const mdl_export_meta_tinternal_epub_page_meta (const mdl_external_cover_t *cover, const mdl_export_meta_t *meta, mdl_export_meta_t *page_meta)
 Select page metadata after accounting for an external cover.
static ra8_err_t internal_epub_carve_workspace (mdl_export_workspace_t *ws, size_t cap, char **mani, char **spine, char **nav, char **opf, char **navdoc)
 Carve the five bounded XML/ZIP accumulators from workspace arena.
static ra8_err_t internal_epub_finish_writer (mz_zip_archive *zip, bool zip_open, mdl_zip_allocator_t *zip_alloc, ra8_err_t rc, const mdl_export_output_t *output)
 End the ZIP writer and translate exhaustion/output faults to status.
ra8_err_t priv_mdl_export_epub (mdl_storage_t *storage, const char *dir, char names[][k_name_max], size_t count, mdl_export_output_t *output, const mdl_export_meta_t *meta, mdl_export_workspace_t *ws)
 Package chapter pages into a valid fixed-layout EPUB3.

Variables

static const char *const s_epub_container_xml
 OCF container pointing at the OPF package (fixed).

Detailed Description

Emit deterministic fixed-layout EPUB3 chapter containers.

Owns EPUB media typing, page XHTML, cover integration, and final ZIP assembly over bounded caller storage. The package document, navigation document, and publication identifier are rendered by mdl_export_epub_meta.c.

[Ring 4 / Domain] {World: NS}

Definition in file mdl_export_epub.c.

Function Documentation

◆ internal_epub_add_external_cover()

ra8_err_t internal_epub_add_external_cover ( mz_zip_archive * zip,
mdl_storage_t * storage,
const mdl_external_cover_t * cover,
char * mani,
size_t cap )
static

Store and declare a validated external EPUB cover.

Writes the file under its canonical OEBPS path and appends one cover-image manifest item using byte-derived MIME data.

Parameters
[in,out]zipInitialized EPUB ZIP writer.
[in,out]storageInjected portable cover reader.
[in]coverPrepared cover descriptor.
[in,out]maniNUL-terminated manifest accumulator.
[in]capCapacity of mani.
Returns
Cover-addition status.
Return values
k_ra8_okNo external cover was requested or it was added.
k_ra8_failA path, ZIP, or manifest operation failed.
Precondition
All pointers are non-NULL and mani is terminated within cap.
An external descriptor has already passed content validation.
Postcondition
Success adds at most one canonical cover member and declaration.
The trusted host source path is not exposed in the manifest.
Note
Not thread-safe for a shared ZIP writer or manifest buffer.
Since
0.1.0

Definition at line 207 of file mdl_export_epub.c.

References mdl_external_cover_t::entry, mdl_external_cover_t::external, k_epub_entry_max, k_epub_frag_max, k_ra8_fail, k_ra8_ok, mdl_external_cover_t::mime, priv_mdl_epub_str_cat(), priv_mdl_export_snprintf_fit(), priv_mdl_export_zip_add_file(), RA8_INTERNAL, and mdl_external_cover_t::source.

Referenced by priv_mdl_export_epub().

◆ internal_epub_add_page()

ra8_err_t internal_epub_add_page ( mdl_storage_t * storage,
mz_zip_archive * zip,
const char * dir,
const char * name,
size_t idx,
char * mani,
char * spine,
char * nav,
size_t cap,
const mdl_export_meta_t * meta )
static

Add one fixed-layout EPUB page and its image.

Escapes the source name, writes page XHTML and stored image members, derives the real MIME where possible, and appends package fragments.

Parameters
[in,out]storageInjected portable file reader.
[in,out]zipInitialized EPUB ZIP writer.
[in]dirChapter directory.
[in]namePage filename.
[in]idxZero-based page index.
[in,out]maniManifest accumulator.
[in,out]spineSpine accumulator.
[in,out]navNavigation accumulator.
[in]capCapacity shared by accumulators.
[in]metaMetadata controlling cover selection, or NULL.
Returns
Page-addition status.
Return values
k_ra8_okImage, XHTML, and fragments were added.
k_ra8_failEscaping, formatting, ZIP writing, or append failed.
Precondition
Paths and accumulators are valid NUL-terminated strings.
zip is initialized and accumulator buffers are distinct.
Postcondition
Success adds one XHTML and one image member.
Success appends matching manifest, spine, and navigation references.
Note
Not thread-safe for a shared ZIP writer or buffers.
Since
0.1.0

Definition at line 405 of file mdl_export_epub.c.

References internal_epub_append_frags(), internal_epub_media_type(), internal_epub_page_is_cover(), internal_epub_write_page_xhtml(), k_epub_entry_max, k_epub_name_esc_max, k_fw_fs_path_cap, k_ra8_err_invalid_size, k_ra8_fail, k_ra8_ok, priv_mdl_export_path_join(), priv_mdl_export_snprintf_fit(), priv_mdl_export_zip_add_file(), and RA8_INTERNAL.

Referenced by priv_mdl_export_epub().

◆ internal_epub_append_frags()

ra8_err_t internal_epub_append_frags ( char * mani,
char * spine,
char * nav,
size_t cap,
const char * esc_name,
const char * media,
size_t idx,
unsigned n,
bool is_cover )
static

Append one page's manifest, spine, and navigation fragments.

Builds all three bounded fragments from an escaped filename and marks the image manifest item when it is the logical cover.

Parameters
[in,out]maniManifest accumulator.
[in,out]spineSpine accumulator.
[in,out]navNavigation accumulator.
[in]capCapacity shared by all accumulators.
[in]esc_nameXML-escaped image filename.
[in]mediaImage MIME string.
[in]idxZero-based manifest identifier index.
[in]nOne-based displayed page number.
[in]is_coverWhether to emit the cover-image property.
Returns
Fragment append status.
Return values
k_ra8_okAll fragments fit.
k_ra8_failFormatting or any accumulator overflowed.
Precondition
All strings and accumulators are NUL-terminated within their bounds.
mani, spine, and nav reference distinct writable buffers.
Postcondition
Success appends coherent identifiers across all three documents.
Failure is explicit and no truncated fragment is reported as valid.
Note
Thread-safe across distinct accumulator sets.
Since
0.1.0

Definition at line 262 of file mdl_export_epub.c.

References k_epub_frag_max, k_ra8_fail, k_ra8_ok, priv_mdl_epub_str_cat(), priv_mdl_export_snprintf_fit(), and RA8_INTERNAL.

Referenced by internal_epub_add_page().

◆ internal_epub_carve_workspace()

ra8_err_t internal_epub_carve_workspace ( mdl_export_workspace_t * ws,
size_t cap,
char ** mani,
char ** spine,
char ** nav,
char ** opf,
char ** navdoc )
static

Carve the five bounded XML/ZIP accumulators from workspace arena.

Reserves one cap-byte block per accumulator and NUL-terminates the three accumulators the caller builds incrementally.

Parameters
[in,out]wsExclusive caller-owned workspace.
[in]capByte capacity reserved for each accumulator.
[out]maniReceives the manifest accumulator.
[out]spineReceives the spine accumulator.
[out]navReceives the navigation accumulator.
[out]opfReceives the OPF render buffer.
[out]navdocReceives the navigation-document render buffer.
Returns
Workspace-carve status.
Return values
k_ra8_okAll five accumulators were reserved.
k_ra8_err_invalid_sizeThe workspace arena is exhausted.
Precondition
ws is exclusive and owns writable arena storage.
The five out-pointers are non-NULL and address distinct storage.
Postcondition
On success every out-pointer is non-NULL and the three text accumulators are empty NUL-terminated strings.
Failure terminates no accumulator and publishes no usable block.
Note
Not thread-safe for a shared workspace.
Since
0.1.0

Definition at line 498 of file mdl_export_epub.c.

References k_ra8_err_invalid_size, k_ra8_ok, mdl_export_workspace_take(), and RA8_INTERNAL.

Referenced by priv_mdl_export_epub().

◆ internal_epub_finish_writer()

ra8_err_t internal_epub_finish_writer ( mz_zip_archive * zip,
bool zip_open,
mdl_zip_allocator_t * zip_alloc,
ra8_err_t rc,
const mdl_export_output_t * output )
static

End the ZIP writer and translate exhaustion/output faults to status.

Always ends an opened writer before releasing the workspace allocator, then maps a generic write failure to the more specific exhaustion or captured-output error when one is available.

Parameters
[in,out]zipZIP writer to end when zip_open.
[in]zip_openWhether zip was successfully initialized.
[in,out]zip_allocWorkspace allocator bound to zip.
[in]rcStatus accumulated by the writer stages.
[in]outputValidated-publication output whose captured error may refine a generic write failure.
Returns
Refined writer status.
Return values
k_ra8_err_invalid_sizerc was k_ra8_fail and the arena was exhausted.
otherrc, or output->error when it refines a generic failure.
Precondition
zip_alloc is bound to zip via priv_mdl_zip_workspace_bind.
output is the validated-publication output bound to the writer.
Postcondition
The ZIP writer is ended and the workspace allocator is released.
A failing rc is never refined into a success status.
Note
Not thread-safe for a shared workspace or writer.
Since
0.1.0

Definition at line 542 of file mdl_export_epub.c.

References mdl_export_output_t::error, mdl_zip_allocator_t::exhausted, k_ra8_err_invalid_size, k_ra8_fail, k_ra8_ok, priv_mdl_zip_workspace_release(), and RA8_INTERNAL.

Referenced by priv_mdl_export_epub().

◆ internal_epub_media_type()

ra8_err_t internal_epub_media_type ( mdl_storage_t * storage,
const char * dir,
const char * name,
const char ** out )
static

Resolve one page's image media type from portable bytes then suffix.

Prefers recognized image magic read through the injected storage; only a clean unsupported signature falls back to the page suffix.

Parameters
[in,out]storageInjected portable file reader.
[in]dirCanonical chapter directory.
[in]nameBounded page leaf name.
[out]outBorrowed canonical MIME pointer.
Returns
Classification or filesystem status.
Return values
k_ra8_okA magic-derived or suffix fallback MIME was selected.
k_ra8_err_invalid_sizeThe composed path exceeded its bound.
otherA portable open, read, or close failure propagated.
Precondition
All pointers are non-NULL and paths are canonical under storage.
name is NUL-terminated and fits the exporter filename contract.
Postcondition
Success initializes out to process-lifetime constant storage.
The page file is consumed only through fw_fs_file_t.
Note
Not thread-safe for a shared storage workspace.
Since
0.1.0

Definition at line 150 of file mdl_export_epub.c.

References internal_epub_media_type_from_sniff(), internal_epub_media_type_from_suffix(), k_ra8_err_not_found, k_ra8_ok, and RA8_INTERNAL.

Referenced by internal_epub_add_page().

◆ internal_epub_media_type_from_sniff()

ra8_err_t internal_epub_media_type_from_sniff ( mdl_storage_t * storage,
const char * dir,
const char * name,
const char ** out )
static

Classify one page's image media type from sniffed portable bytes.

Joins the canonical path and sniffs the file's magic through injected storage. An unrecognized (but cleanly read) signature is reported as k_ra8_err_not_found rather than an error, so the caller can fall back to the suffix classifier.

Parameters
[in,out]storageInjected portable file reader.
[in]dirCanonical chapter directory.
[in]nameBounded page leaf name.
[out]outBorrowed canonical MIME pointer, valid only on k_ra8_ok.
Returns
Sniff classification or filesystem status.
Return values
k_ra8_okA magic-derived MIME was selected; out is valid.
k_ra8_err_not_foundThe signature was read cleanly but unrecognized.
k_ra8_err_invalid_sizeThe composed path exceeded its bound.
otherA portable open, read, or close failure propagated.
Precondition
All pointers are non-NULL and paths are canonical under storage.
name is NUL-terminated and fits the exporter filename contract.
Postcondition
The page file is consumed only through fw_fs_file_t.
Any status other than k_ra8_ok leaves out unchanged.
Note
Not thread-safe for a shared storage workspace.
Since
0.1.0

Definition at line 59 of file mdl_export_epub.c.

References k_fw_fs_path_cap, k_ra8_err_invalid_size, k_ra8_err_not_found, k_ra8_err_validation_failed, k_ra8_ok, mdl_urlname_sniff_file(), priv_mdl_export_path_join(), RA8_INTERNAL, and strcmp().

Referenced by internal_epub_media_type().

◆ internal_epub_media_type_from_suffix()

void internal_epub_media_type_from_suffix ( const char * name,
const char ** out )
static

Classify one page's image media type from its filename suffix.

Falls back to JPEG when no recognized suffix is present, since the exporter must always publish some MIME for a manifest entry.

Parameters
[in]nameBounded page leaf name.
[out]outBorrowed canonical MIME pointer.
Returns
Nothing; a MIME is always selected.
Precondition
name is NUL-terminated.
out is non-NULL and addresses one writable pointer.
Postcondition
out addresses process-lifetime constant storage.
No file is opened and name is unchanged.
Note
Pure and thread-safe.
Since
0.1.0

Definition at line 107 of file mdl_export_epub.c.

References RA8_INTERNAL, strcmp(), and strrchr().

Referenced by internal_epub_media_type().

◆ internal_epub_page_is_cover()

bool internal_epub_page_is_cover ( const mdl_export_meta_t * meta,
const char * name,
size_t idx )
static

Is one exported image the publication's declared cover?

Matches by declared cover index first, then by declared cover path name, so either identification method marks the same image.

Parameters
[in]metaResolved metadata controlling cover selection, or NULL.
[in]nameImage file name being exported.
[in]idxZero-based export position of name.
Returns
Whether this image is the declared cover.
Return values
trueidx matches the declared cover index, or name matches the declared cover path.
falsemeta is NULL, or neither identification method matches.
Precondition
name is non-NULL and NUL-terminated.
meta is NULL or holds a bounded NUL-terminated cover path.
Postcondition
No state is modified.
The result depends only on the supplied arguments.
Note
Pure and thread-safe.
Since
0.1.0

Definition at line 321 of file mdl_export_epub.c.

References mdl_export_meta_t::cover_index, mdl_export_meta_t::cover_path, and strcmp().

Referenced by internal_epub_add_page().

◆ internal_epub_page_meta()

const mdl_export_meta_t * internal_epub_page_meta ( const mdl_external_cover_t * cover,
const mdl_export_meta_t * meta,
mdl_export_meta_t * page_meta )
static

Select page metadata after accounting for an external cover.

Copies metadata only when the external cover consumes the cover role, clearing the page cover fields without mutating caller input.

Parameters
[in]coverPrepared canonical cover descriptor.
[in]metaResolved caller metadata.
[out]page_metaCaller-owned adjusted metadata storage.
Returns
Metadata object to use for page manifest generation.
Return values
metaNo external cover adjustment is required.
page_metaAn adjusted caller-owned copy is ready.
Precondition
All pointers are non-NULL and stable for the call.
page_meta does not alias meta or cover.
Postcondition
Caller metadata and cover descriptor remain unchanged.
An adjusted result has no page cover index or cover path.
Note
Thread-safe across distinct arguments.
Since
0.1.0

Definition at line 463 of file mdl_export_epub.c.

References mdl_export_meta_t::cover_index, mdl_export_meta_t::cover_path, and mdl_external_cover_t::external.

Referenced by priv_mdl_export_epub().

◆ internal_epub_write_page_xhtml()

ra8_err_t internal_epub_write_page_xhtml ( mz_zip_archive * zip,
const char * name,
unsigned n,
char * esc,
size_t esc_cap )
static

Escape a page name and write its XHTML wrapper into the ZIP.

Escapes the source name for XML use, renders the fixed page markup, and writes it under the page's OEBPS entry name.

Parameters
[in,out]zipInitialized EPUB ZIP writer.
[in]namePage filename.
[in]nOne-based page number.
[out]escReceives the escaped name for later fragment use.
[in]esc_capCapacity of esc.
Returns
Page-XHTML write status.
Return values
k_ra8_okThe escaped name and XHTML entry were written.
k_ra8_failEscaping, formatting, or ZIP writing failed.
Precondition
name is a NUL-terminated untrusted filename.
esc addresses esc_cap writable bytes.
Postcondition
Success writes exactly one XHTML ZIP member.
Failure adds no member and esc holds no usable name.
Note
Not thread-safe for a shared ZIP writer.
Since
0.1.0

Definition at line 351 of file mdl_export_epub.c.

References k_epub_entry_max, k_epub_xhtml_max, k_ra8_fail, k_ra8_ok, mdl_xml_escape(), priv_mdl_epub_add_str(), priv_mdl_export_snprintf_fit(), and RA8_INTERNAL.

Referenced by internal_epub_add_page().

◆ priv_mdl_epub_add_str()

bool priv_mdl_epub_add_str ( mz_zip_archive * zip,
const char * name,
const char * body )

Add an in-memory string as a stored ZIP entry.

Passes the complete string length to miniz without compression.

Parameters
[in,out]zipInitialized ZIP writer.
[in]nameSafe NUL-terminated member name.
[in]bodyNUL-terminated member body.
Returns
Whether miniz accepted the complete member.
Return values
trueThe entry was added.
falseThe ZIP writer rejected it.
Precondition
All pointers are non-NULL and strings are NUL-terminated.
zip remains initialized for writing.
Postcondition
Success adds exactly one stored member.
Input strings remain unchanged.
Note
Not thread-safe for a shared ZIP writer.
Since
0.1.0

Definition at line 179 of file mdl_export_epub.c.

References k_ra8_ok, priv_mdl_export_zip_add_memory(), RA8_PRIV, and strlen().

Referenced by internal_epub_render_meta(), internal_epub_write_page_xhtml(), and priv_mdl_export_epub().

◆ priv_mdl_epub_str_cat()

bool priv_mdl_epub_str_cat ( char * dst,
size_t cap,
const char * text )

Append text to NUL-terminated dst; report whether it fully fit.

Never truncates: if the append (plus its NUL) would not fit in cap it leaves dst unchanged and returns false, so the caller can fail loudly rather than emit a manifest cut off mid-element.

Returns
true when the whole of text was appended, false if it would overrun.
Parameters
[in,out]dstExisting NUL-terminated accumulator.
[in]capTotal writable capacity of dst.
[in]textNUL-terminated text to append.
Return values
trueThe complete text and terminator fit.
falseCapacity is insufficient and dst is unchanged.
Precondition
dst and text are non-NULL and do not overlap.
dst is NUL-terminated within cap.
Postcondition
Success appends the complete source string.
Failure preserves the original destination.
Note
Thread-safe across distinct accumulators.
Since
0.1.0

Definition at line 168 of file mdl_export_epub.c.

References memcpy(), RA8_PRIV, and strlen().

Referenced by internal_epub_add_external_cover(), internal_epub_append_frags(), and internal_epub_prepare_creators().

◆ priv_mdl_export_epub()

ra8_err_t priv_mdl_export_epub ( mdl_storage_t * storage,
const char * dir,
char names[][k_name_max],
size_t count,
mdl_export_output_t * output,
const mdl_export_meta_t * meta,
mdl_export_workspace_t * ws )

Package chapter pages into a valid fixed-layout EPUB3.

Write a fixed-layout EPUB3 archive.

Carves all XML accumulators from caller storage, adds OCF roots, canonical cover, page members, metadata, and finalizes the staged archive.

Parameters
[in,out]storageInjected portable file reader.
[in]dirChapter directory.
[in]namesSorted page-name rows.
[in]countNumber of page rows.
[in,out]outputActive validated-publication output.
[in]metaMetadata to encode, or NULL.
[in,out]wsExclusive caller-owned workspace.
Returns
EPUB writer status.
Return values
k_ra8_okA complete finalized EPUB was written.
k_ra8_err_invalid_sizeWorkspace or metadata bounds were exceeded.
k_ra8_err_validation_failedExternal cover validation failed.
k_ra8_failZIP, XHTML, or metadata writing failed.
Precondition
Paths and rows are valid, stable, and NUL-terminated.
ws is exclusive and owns writable arena storage.
Postcondition
The ZIP writer is ended on every initialized path.
Success includes required mimetype, container, OPF, and navigation members.
Note
Not thread-safe for shared output or workspace.
Since
0.1.0

Definition at line 584 of file mdl_export_epub.c.

References internal_epub_add_external_cover(), internal_epub_add_page(), internal_epub_carve_workspace(), internal_epub_finish_writer(), internal_epub_page_meta(), k_epub_base_bytes, k_epub_per_page_bytes, k_name_max, k_ra8_fail, k_ra8_ok, priv_mdl_epub_add_meta(), priv_mdl_epub_add_str(), priv_mdl_export_prepare_cover(), priv_mdl_export_zip_write(), priv_mdl_zip_workspace_bind(), priv_mdl_zip_workspace_error(), RA8_PRIV, and s_epub_container_xml.

Referenced by internal_export_dispatch(), and internal_write_temp_epub().

Variable Documentation

◆ s_epub_container_xml

const char* const s_epub_container_xml
static
Initial value:
=
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<container version=\"1.0\" "
"xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\"><rootfiles>"
"<rootfile full-path=\"OEBPS/content.opf\" "
"media-type=\"application/oebps-package+xml\"/></rootfiles></container>"

OCF container pointing at the OPF package (fixed).

Definition at line 30 of file mdl_export_epub.c.

Referenced by priv_mdl_export_epub().