File-Raw-XML

 view release on metacpan or  search on metacpan

include/frx_abi.h  view on Meta::CPAN

 * table; everything a version 1 consumer resolved is where it was.
 *
 * Perl headers (EXTERN.h / perl.h / XSUB.h) must be included before this
 * file so SV, STRLEN and pTHX are defined. Only the entries that touch an
 * SV take pTHX_; the tree accessors are plain C, callable from a harness
 * with no interpreter.
 *
 * Three departures from the design in Punk/plan/punk-saml/01-file-raw-xml.md:
 *
 *   - frx_c14n.mode replaces `int exclusive`: three algorithms ship
 *     (Exclusive 1.0, Canonical XML 1.0, Canonical XML 1.1).
 *   - FRX_DOCUMENT is a node kind: a signature whose Reference has URI=""
 *     is over the whole document, and canonicalising it means an apex that
 *     is the document node, with top-level comments and processing
 *     instructions rendered under the document-level newline rules. The
 *     document node's children are the top-level misc and the root
 *     element; root() still returns the root element; parent() of the root
 *     is the document node.
 *   - document() is appended after root().
 *
 * Ownership: every string the table returns is borrowed from the document,
 * NUL-terminated, and valid until doc_free. Every node is borrowed from its
 * document: a consumer that holds a node holds the document. Every SV the
 * table returns has a reference count of one owned by the caller.
 *
 * One entry departs from that, and only one: `doc_to_sv` takes ownership of
 * the document it is given, because the point of it is to put the document
 * under the blessed SV's magic. It is called out again where it is
 * declared.
 *
 * Two lifetimes are shorter than that, and both are the reader's. A
 * string from `reader_str` or `reader_attr` lives in the arena the reader
 * releases at the end of each record, so it is valid until the next
 * `reader_next` and not after; copy it if you need it longer. The
 * `frx_err *` from `reader_error` is valid while the reader is.
 *
 * A message never is. `frx_err.what` is a static string and so is the
 * compile refusal from `xpath_compile`, precisely so that a consumer can
 * free what failed and then report it: a message built from arena memory
 * and read after the free is a use-after-free whose only symptom is a
 * wrong message, which is the hardest kind to notice. */

#define FRX_ABI_VERSION 2

typedef struct frx_doc  frx_doc;      /* opaque; owns every node and string */
typedef struct frx_node frx_node;     /* opaque; borrowed from its doc */

/* ---- refusals -----------------------------------------------------------
 *
 * The core never croaks: it fills an frx_err and returns NULL or 0. The
 * `parse` entry renders that into a mortal SV, because it is the entry a
 * consumer reaches for first and a message is what it wants; every other
 * entry that can fail takes an frx_err * and the consumer renders it with
 * `err_format`, so no entry needs a wrapper to translate one. */

typedef enum {
    FRX_OK = 0,
    FRX_E_NOMEM,          /* an allocation failed */
    FRX_E_TOO_LARGE,      /* over max_bytes */
    FRX_E_TOO_DEEP,       /* over max_depth */
    FRX_E_ENCODING,       /* not UTF-8: a BOM, a declaration, a first pair */
    FRX_E_DOCTYPE,        /* <!DOCTYPE, or any <! that is not -- or [CDATA[ */
    FRX_E_UTF8,           /* a byte sequence that is not UTF-8, or not Char */
    FRX_E_SYNTAX,         /* not well-formed */
    FRX_E_NAME,           /* not a Name, or a QName with the wrong colons */
    FRX_E_REFERENCE,      /* an undeclared entity, or a reference to a non-Char */
    FRX_E_NAMESPACE,      /* unbound prefix, xmlns misuse, a relative URI */
    FRX_E_DUP_ATTR,       /* the same attribute twice, literally or expanded */
    FRX_E_DUP_ID,         /* two elements with one ID value */
    FRX_E_ROOT,           /* no root element, or more than one */
    FRX_E_DTD,            /* full: a markup declaration that is not well-formed */
    FRX_E_ENTITY,         /* full: an entity well-formedness constraint */
    FRX_E_EXPANSION,      /* full: an entity expansion budget crossed */
    FRX_E_VALIDITY        /* full: a validity constraint, under validate */
} frx_code;

typedef struct frx_err {
    frx_code    code;
    size_t      offset;
    const char *what;     /* static; never arena memory */
    const char *enc;      /* the input's encoding when it was transcoded and
                           * offset indexes the caller's bytes; NULL otherwise */
} frx_err;

/* node kinds; CDATA is text in the data model and merges into it at parse */
enum { FRX_ELEMENT = 1, FRX_TEXT, FRX_COMMENT, FRX_PI, FRX_DOCUMENT };

/* canonicalisation algorithms */
enum { FRX_C14N_EXC = 0, FRX_C14N_INC10, FRX_C14N_INC11 };

/* Parse options. Fill with opts_init() (or pass NULL to parse) for the
 * defaults, then set what you need. */
typedef struct frx_opts {
    size_t max_bytes;                 /* 0: no cap */
    int    max_depth;                 /* 0: the default, 256 */
    const char *const *id_attrs;      /* attribute local names that are IDs,
                                       * in any namespace; NULL: no index */
    int    n_id_attrs;
} frx_opts;

/* Canonicalisation options. */
typedef struct frx_c14n {
    int mode;                         /* FRX_C14N_* */
    int comments;                     /* 1: render comments */
    const char *const *prefix_list;   /* InclusiveNamespaces PrefixList;
                                       * "#default" names the default ns */
    int n_prefix;
    const frx_node *const *without;   /* subtrees omitted from the node set:
                                       * the enveloped-signature transform */
    int n_without;
} frx_c14n;

/* ---- the full profile's options ------------------------------------------
 *
 * frx_opts is in the table by pointer with no size field, so once this
 * ships it can never grow: a later provider would read past an older
 * consumer's struct. frx_opts_ex is the struct the full profile grows
 * into instead. It begins with `size`, the sizeof the consumer was
 * compiled with, and every reader copies min(size, its own sizeof) over a
 * defaults block, so a later version can append fields and an older
 * consumer's shorter struct is still read whole. A field that turns out



( run in 1.193 second using v1.01-cache-2.11-cpan-8dfa8b56332 )