Iconvex Bibliographic

iconvex_bibliographic provides source-qualified library, cataloging, and TeX codecs. It extends Iconvex with pure Elixir code. It uses no NIF, port process, platform iconv, or iconvex_specs runtime dependency.

Add the package and its Core dependency:

def deps do
[
{:iconvex, "~> 0.1.1"},
{:iconvex_bibliographic, "~> 0.1"}
]
end

The OTP application registers every byte codec in one transaction. Stopping it removes only routes that this package owns.

Codec families

FamilyCanonical encodingWhat makes it interesting
MARCMARC-8Stateful ISO 2022 designations, EACC 24-bit characters, ANSEL combining marks, and spanning half marks
MARCANSELStrict ANSI/NISO Z39.47 ASCII + Extended Latin environment
CorkTEX-T1-EC-GLYPHThe EC glyph interpretation, including ligature scalars and exact SS sequence semantics
CorkTEX-T1-CMAP-1.0JCTAN CMap extraction with deterministic longest-match ffi/ffl/ff/fi/fl encoding
OT1TEX-OT1-CMAP-1.0JNormal CTAN OT1 extraction. Byte 20 remains undefined.
OT1TEX-OT1TT-CMAP-1.0JTypewriter OT1, where byte 20 is U+2423 OPEN BOX
TeX mathTEX-LIVE-OML-CMMI10-TOUNICODE-2026Exact 7-bit cmmi10 ToUnicode semantics, with packed MSB/LSB transports
TeX mathTEX-LIVE-OMS-CMSY10-TOUNICODE-2026Exact 7-bit cmsy10 ToUnicode semantics, with packed MSB/LSB transports
Glyph vectorsCTAN-LY1-TEXNANSI-1.1-AGL-4036A9CAA pinned TeX'n'ANSI 1.1 vector resolved through a pinned Adobe Glyph List revision
Glyph vectorsADOBE-POSTSCRIPT-3-ISOLATIN1-AGL-4036A9CAPostScript LanguageLevel 3 ISOLatin1Encoding—specifically not ISO-8859-1

Iconvex.Bibliographic.registrations/0, codecs/0, encodings/0, and packed_profiles/0 return the complete manifest-ordered surface.

MARC-8: combining marks and EACC

MARC-8 stores an ANSEL combining mark before its base character. Iconvex returns the base character before its combining mark.

iex> Iconvex.convert(<<0xE2, ?e>>, "MARC-8", "UTF-8")
{:ok, "e\u0301"}
iex> Iconvex.convert("e\u0301", "UTF-8", "MARC8")
{:ok, <<0xE2, ?e>>}

The same codec handles custom and ISO 2022 designations plus three-byte EACC:

iex> Iconvex.Bibliographic.MARC8.decode(<<0x1B, ?$, ?1, 0x21, 0x30, 0x21>>)
{:ok, [0x4E00]}
iex> Iconvex.Bibliographic.MARC8.decode(<<0xEB, ?a, 0xEC, ?b>>)
{:ok, [?a, 0x0361, ?b]}

TeX ligatures with exact inverse semantics

The CMap profiles encode the longest source-defined sequence first:

iex> Iconvex.convert("ffifflfffifl", "UTF-8", "TEX-OT1-CMAP-1.0J")
{:ok, <<0x0E, 0x0F, 0x0B, 0x0C, 0x0D>>}
iex> Iconvex.convert("ffiAfflASS", "UTF-8", "TEX-T1-CMAP-1.0J")
{:ok, <<0x1E, ?A, 0x1F, ?A, 0xDF>>}

These profiles extract Unicode. They do not claim identical semantics for every historical font with the same broad label.

Packed seven-bit math

The byte-form OML and OMS codecs use one logical 7-bit unit per byte. This format works with Iconvex.convert/4. The packed facade emits contiguous units.

alias Iconvex.Bibliographic.Packed
iex> Packed.encode_from_utf8("Γ∆", "OML")
{:ok, <<0::7, 1::7>>}
iex> {:ok, lsb} = Packed.encode_from_utf8("Γ∆", "OML-PACKED-LSB")
iex> lsb
%Iconvex.Packed.LSB{data: <<0x80, 0x00>>, bit_size: 14, unit_bits: 7, bit_order: :lsb}
iex> Packed.decode_to_utf8(lsb, "OML-PACKED-LSB")
{:ok, "Γ∆"}

The fully qualified forms use the OML or OMS canonical name with a packed suffix. The suffix is -PACKED-MSB or -PACKED-LSB. An explicit bit order must agree with the name.

Streams and recovery policies

Every codec implements strict, discard, substitution, direct UTF-8, and chunk callbacks. Stateful MARC-8 works across arbitrary stream boundaries. Longest-match TeX sequences also work across those boundaries.

chunks = [<<0x1B, ?$, ?1, 0x21>>, <<0x30, 0x21>>]
{:ok, stream} = Iconvex.stream(chunks, "MARC-8", "UTF-8")
IO.iodata_to_binary(Enum.to_list(stream))
# => "一"

Canonical names

Many typographic encodings combine a vector, glyph list, extraction policy, and source revision. Short aliases could merge distinct profiles. Canonical names retain the source boundary. The package registers only reviewed and unambiguous aliases.

The package includes the exact runtime and source assets for these profiles. It includes SHA-256 metadata, retained AGL and LPPL terms, and the 12-row manifest.

Tests cover all 256 bytes where applicable and all 128 OML or OMS units. They cover inverse mappings, malformed input, every stream split, and both packed orders. They also cover application restart ownership. Both glyph-vector encoders process all 1,112,064 Unicode scalar values.

See BENCHMARKS.md for reproducible native-path gates and NOTICE for upstream provenance and license boundaries.

Complete codec catalog

The generator builds this table from the release inventories. Do not edit this section by hand. Codec names ignore ASCII letter case. You can use each alias to look up its codec. Aliases do not increase the canonical codec count.

10 canonical codecs · 32 aliases · 42 accepted names.

Registered codec names

Canonical codecAccepted aliasesStateful
ADOBE-POSTSCRIPT-3-ISOLATIN1-AGL-4036A9CAADOBE-POSTSCRIPT-3-ISOLATIN1ENCODING-AGL-4036A9CANo
ANSELANSI-Z39.47
csANSEL
Z39.47
No
CTAN-LY1-TEXNANSI-1.1-AGL-4036A9CACTAN-TEXNANSI-1.1-AGL-4036A9CANo
MARC-8csMARC8
MARC8
MARC_8
Yes
TEX-LIVE-OML-CMMI10-TOUNICODE-2026OML
OML-ENCODING
TEX-MATH-ITALIC
No
TEX-LIVE-OMS-CMSY10-TOUNICODE-2026OMS
OMS-ENCODING
TEX-MATH-SYMBOLS
No
TEX-OT1-CMAP-1.0JTEX-OT1-0-CMAP-1.0JNo
TEX-OT1TT-CMAP-1.0JTEX-OT1TT-0-CMAP-1.0JNo
TEX-T1-CMAP-1.0JT1-CMAP
TEX-T1-0
TEX-T1-CMAP
No
TEX-T1-EC-GLYPH8T
CORK
CORK-ENCODING
CORKENCODING
EC
EC-ENCODING
ECENCODING
T1
TEX-LATIN-1
TEX-T1
TEX256
TEX256.ENC
TEXLATIN1
No

Packed transport profiles

2 base codec profiles · 4 explicit packed names. These profiles change the bit transport only. They do not add registered Unicode mappings.

Base codecUnit bitsStandard orderExplicit packed names
TEX-LIVE-OML-CMMI10-TOUNICODE-20267MSBTEX-LIVE-OML-CMMI10-TOUNICODE-2026-PACKED-MSB
TEX-LIVE-OML-CMMI10-TOUNICODE-2026-PACKED-LSB
TEX-LIVE-OMS-CMSY10-TOUNICODE-20267MSBTEX-LIVE-OMS-CMSY10-TOUNICODE-2026-PACKED-MSB
TEX-LIVE-OMS-CMSY10-TOUNICODE-2026-PACKED-LSB