{"id":1465,"date":"2023-10-20T23:32:29","date_gmt":"2023-10-20T22:32:29","guid":{"rendered":"https:\/\/exponentialdecay.co.uk\/blog\/?p=1465"},"modified":"2025-12-01T16:59:54","modified_gmt":"2025-12-01T16:59:54","slug":"shattering-the-eyeglass","status":"publish","type":"post","link":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/","title":{"rendered":"Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass&#8217; contents"},"content":{"rendered":"<p>In my post from 2012: <a href=\"https:\/\/exponentialdecay.co.uk\/blog\/genesis-of-a-file-format\/\" target=\"_blank\" rel=\"noopener\">Genesis of a File Format<\/a>, I created a new file format &#8211; the <a href=\"https:\/\/www.wikidata.org\/entity\/Q105858419\" target=\"_blank\" rel=\"noopener\"><em>Eyeglass<\/em> file format<\/a>. The format provides a mechanism to persist information about a patient&#8217;s eye health following a checkup at an opticians. Today in 2023 we can use the format to understand how to make use of <a href=\"https:\/\/kaitai.io\/\" target=\"_blank\" rel=\"noopener\">Kaitai Structs<\/a> for understanding file formats.<\/p>\n<p>Given the disclaimer that I am not actually an optician and that the format is purely illustrative, let&#8217;s look at the eyeglass again below.<\/p>\n<p><!--more--><\/p>\n<p>A recent post on <a href=\"https:\/\/digipres.club\/@BertrandCaron\/111193219799287896\" target=\"_blank\" rel=\"noopener\">digipres.club<\/a> prompted me to revisit this work, starting with refactoring the original <a href=\"https:\/\/github.com\/ross-spencer\/eyeglass\" target=\"_blank\" rel=\"noopener\">GitHub repository<\/a> and leading to this blog post where I thought it might be an interesting idea to break down the binary format that is output by the tool.<\/p>\n<p>Thus, <a href=\"https:\/\/exponentialdecay.co.uk\/blog\/genesis-of-a-file-format\/\" target=\"_blank\" rel=\"noopener\">in the first blog<\/a> we create the binary format from a specification. In this blog we try and understand the format from the binary itself &#8211; more akin to a transfer and digital preservation workflow in an archival institution.<\/p>\n<h2>Breaking down the eyeglass<\/h2>\n<p>The binary file output in the eyeglass project looks as follows (<code>xxd<\/code> allows me to pretty print the hex (hexadecimal)):<\/p>\n<pre>xxd -g1 prescription-sample-1.0-be.eygl<\/pre>\n<pre>00000000: bb 0d 0a 65 79 65 67 6c 61 73 73 1a 0a ab 01 01 ...eyeglass.....\r\n00000010: 32 30 31 32 2d 31 31 2d 30 38 54 31 32 3a 33 37 2012-11-08T12:37\r\n00000020: 3a 35 30 00 00 00 00 00 00 00 00 00 00 00 00 00 :50.............\r\n00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000070: 00 00 00 00 00 00 00 00 00 00 00 c0 56 66 66 3f ............Vff?\r\n00000080: 00 00 00 be 80 00 00 bf 80 00 00 00 00 00 82 00 ................\r\n00000090: 00 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 ..P.............\r\n000000a0: 00 00 00 3f 28 f5 c3 3f 00 00 00 00 00 00 0c 00 ...?(..?........\r\n000000b0: 00 00 0c 44 69 73 74 61 6e 63 65 20 61 6e 64 20 ...Distance and\r\n000000c0: 43 6c 6f 73 65 20 57 6f 72 6b 2e 00 00 00 00 00 Close Work......\r\n000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50 ...............P\r\n00000140: 61 74 69 65 6e 74 27 73 20 65 79 65 73 69 67 68 atient's eyesigh\r\n00000150: 74 20 6e 65 65 64 73 20 63 6f 72 72 65 63 74 69 t needs correcti\r\n00000160: 6f 6e 2e 20 48 69 73 74 6f 72 79 20 6f 66 20 64 on. History of d\r\n00000170: 69 61 62 65 74 65 73 20 69 6e 20 66 61 6d 69 6c iabetes in famil\r\n00000180: 79 20 62 75 74 20 69 6e 64 69 63 61 74 6f 72 73 y but indicators\r\n00000190: 20 66 6f 75 6e 64 2e 20 53 74 61 6e 64 61 72 64 found. Standard\r\n000001a0: 20 63 68 65 63 6b 75 70 20 69 6e 74 65 72 76 61 checkup interva\r\n000001b0: 6c 20 72 65 63 6f 6d 6d 65 6e 64 65 64 2e 00 00 l recommended...\r\n000001c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n000001d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n000001f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\r\n00000230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f 80 ..............?.\r\n00000240: 00 00 bb 65 6f 66 ...eof\r\n<\/pre>\n<p>The specification was first described as follows:<\/p>\n<div>\n<pre>Eyeglass Format Specification 1.0\r\n---\r\nMagic number - 14 bytes - String\r\nVersion - 1 bytes - Unsigned Char\r\nBig-endian - 1 byte - Bool\r\nDate\/time - 19 bytes - String #YYYY-MM-DDTHH:MM:SS\r\nExpansion room - 88 bytes - Undefined\r\nSphere - 8 bytes - R: Float L: Float\r\nCylinder - 8 bytes - R: Float L: Float\r\nAxis - 8 bytes - R: Integer L: Integer\r\nPrism - 8 bytes - R: Float L: Float\r\nBase - 8 bytes - R: Float L: Float\r\nDistance acuity - 8 bytes - R: Float L: Float\r\nNear acuity - 8 bytes - R: Integer L: Integer\r\nPurpose - 140 bytes - String\r\nObservation - 255 bytes - String\r\nNext checkup - 4 bytes - Float\r\nEnd of file - 4 bytes - String\r\n<\/pre>\n<\/div>\n<div>Between the binary object and this specification we have the two lenses through which we see file formats in digital preservation.<\/div>\n<div><\/div>\n<div>Reading the original blog is a good idea for background, but a summary is that a file format is persisted by writing sequences of bytes to disk. The sequences are bounded by the the data type and respective data length that they represent (a boolean is one byte, a float is 4-bytes, and so on &#8212; their own specifications are dictated by the software encoding them, e.g. a 16-bit software vs. 32-bit software, golang vs. rust) &#8211; in total, the eyeglass format is written to disk taking up 582 bytes. If we draw the boundaries between the different data types described in the specification it looks as follows:<\/div>\n<p><a href=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/boundaries.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1477\" src=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/boundaries.png\" alt=\"\" width=\"1000\" height=\"993\" srcset=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/boundaries.png 1000w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/boundaries-300x298.png 300w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/boundaries-150x150.png 150w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/boundaries-768x763.png 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><\/p>\n<p>The different data types and their lengths are like fields, each field can be interpreted in some way that may be useful to the original rendering application, and of course to the digital preservation researcher trying to gleam information from a file format.<\/p>\n<p>But what does that meaning look like?<\/p>\n<h2>Manual decoding of the eyeglass<\/h2>\n<p>Lets take a small number of the fields in the eyeglass format and take a look.<\/p>\n<h3>Date\/time<\/h3>\n<p>Date\/time is the date and time that the file was written. It&#8217;s a plain old string and uses the ISO standard date format. In hexadecimal it looks as follows:<\/p>\n<pre>32 30 31 32 2d 31 31 2d 30 38 54 31 32 3a 33 37 3a 35 30<\/pre>\n<p>Which renders as: <em>2012-11-08T12:37:50<\/em><\/p>\n<p>When we talk about endianness shortly, this field, as a string, like other string fields in this format doesn&#8217;t change.<\/p>\n<h3>Big-endian<\/h3>\n<p>The big-endian field was intended to be a flag that tells the reader of the format if they are looking at a big-endian version, or a little-endian version. This tells the reader how to interpret the values.<\/p>\n<p>In hex we simply have a one-byte &#8220;boolean&#8221; reading as:<\/p>\n<pre>01<\/pre>\n<p>This should evaluate as &#8220;1&#8221; or &#8220;true&#8221; and tells us that we do need to interpret this file&#8217;s contents as big-endian.<\/p>\n<h3>Sphere<\/h3>\n<p>Sphere is documented as containing two values, one for the right eye, and one for the left. The value are floating point numbers. In hexadecimal we have:<\/p>\n<pre>c0 56 66 66 3f 00 00 00<\/pre>\n<p>The two values: &#8220;c0 56 66 66&#8221; and &#8220;3f 00 00 00&#8221;<\/p>\n<p>The easiest way to understand what these values are, knowing that they are floating point numbers is to use an online hexadecimal converter, e.g. <a href=\"https:\/\/www.scadacore.com\/tools\/programming-calculators\/online-hex-converter\/\" target=\"_blank\" rel=\"noopener\">online-hex-converter<\/a>.<\/p>\n<p>We know it is a big-endian number, we can look up the corresponding fields after data entry:<\/p>\n<p><a href=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-sphere.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1491\" src=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-sphere.png\" alt=\"\" width=\"1112\" height=\"832\" srcset=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-sphere.png 1112w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-sphere-300x224.png 300w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-sphere-1024x766.png 1024w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-sphere-768x575.png 768w\" sizes=\"auto, (max-width: 1112px) 100vw, 1112px\" \/><\/a><\/p>\n<p>The interpretation &#8220;Float &#8211; Big Endian (ABCD)&#8221; provides the two results we expect here: -3.35; and 0.5 respectively.<\/p>\n<p>You can get a feel for the issues that might arise interpreting these values without knowing the correct endianness by looking at some of the other results in this hexadecimal converter tool.<\/p>\n<h3>Near acuity<\/h3>\n<p>Near acuity contains two values which in the specification are two integers, each four bytes: &#8220;00 00 00 0c&#8221; and &#8220;00 00 00 0c&#8221;. Knowing these are integers makes\u00a0 their interpretation a bit easier, we can type these into a search engine as follows:<\/p>\n<p>&#8220;0x0000000c in decimal&#8221; <em>(the &#8220;0x&#8221; denotes <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hexadecimal\" target=\"_blank\" rel=\"noopener\">hexadecimal<\/a> or base-16)<\/em><\/p>\n<p>A result of 12 will be returned. 0x0c is simply 12 in hex. In big-endian this is an easy conversion no matter how many hex values are here.<\/p>\n<p>In the hexadecimal converter we can confirm our result:<\/p>\n<p><a href=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-acuity.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1492\" src=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-acuity.png\" alt=\"\" width=\"1081\" height=\"964\" srcset=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-acuity.png 1081w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-acuity-300x268.png 300w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-acuity-1024x913.png 1024w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/byte-interpretation-acuity-768x685.png 768w\" sizes=\"auto, (max-width: 1081px) 100vw, 1081px\" \/><\/a><\/p>\n<h2>Endianness in a file format<\/h2>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Endianness\" target=\"_blank\" rel=\"noopener\">Endianness<\/a> changes layout of the bytes and thus how they need to be interpreted. There&#8217;s not a huge visual difference between the big-endian version of the eyeglass format and the little-endian version, but the differences are big enough to change the meaning we try to extract from the file.<\/p>\n<p>We can see the fields that have been changed in one rendering of the big-endian file vs. the little-endian one using <a href=\"https:\/\/github.com\/8051Enthusiast\/biodiff\/\" target=\"_blank\" rel=\"noopener\">biodiff<\/a> (click on the image below if you need to see it better).<\/p>\n<p><a href=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/biodiff.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1482\" src=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/biodiff.png\" alt=\"\" width=\"1424\" height=\"725\" srcset=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/biodiff.png 1424w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/biodiff-300x153.png 300w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/biodiff-1024x521.png 1024w, https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/biodiff-768x391.png 768w\" sizes=\"auto, (max-width: 1424px) 100vw, 1424px\" \/><\/a><\/p>\n<h3>Interpreting the fields in little endian<\/h3>\n<p>Taking the example fields from before we can see the differences, and how they look.<\/p>\n<table>\n<tbody>\n<tr>\n<th>Field<\/th>\n<th>Big-endian<\/th>\n<th>Little-endian<\/th>\n<th>Value<\/th>\n<\/tr>\n<tr>\n<td>Date\/time<\/td>\n<td>32 30 31 32 2d 31 31 2d 30 38 54 31 32 3a 33 37 3a 35 30<\/td>\n<td>32 30 31 32 2d 31 31 2d 30 38 54 31 32 3a 33 37 3a 35 30<\/td>\n<td>2012-11-08T12:37:50;<\/td>\n<\/tr>\n<tr>\n<td>Big-endian<\/td>\n<td>01<\/td>\n<td>00<\/td>\n<td>1=True; 0=False;<\/td>\n<\/tr>\n<tr>\n<td>Sphere<\/td>\n<td>c0 56 66 66; 3f 00 00 00<\/td>\n<td>66 66 56 c0; 00 00 00 3f<\/td>\n<td>R:-3.35; L:0.50;<\/td>\n<\/tr>\n<tr>\n<td>Near acuity<\/td>\n<td>00 00 00 0c; 00 00 00 0c<\/td>\n<td>0c 00 00 00; 0c 00 00 00<\/td>\n<td>R:12; L:12;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Let us take the value for near acuity here: &#8220;0c 00 00 00&#8221;. It is reversed compared to the big-endian version &#8211; but if we ask a search engine for &#8220;0x0c000000 in decimal&#8221; we will return &#8220;201326592&#8221; which is definitely not the right value! We need to know that little-endian puts the least significant byte at the first memory address (which equates to an earlier position in a file), and in hexadecimal, like decimal, least significant values are the 1s and the 10s. To interpret this value correctly we need to reverse the bytes, so 0x0000000c like we had in big-endian.<\/p>\n<h2>Kaitai<\/h2>\n<p>Kaitai is an example of tooling we can adopt in our work to automatically parse the structures of a binary format.<\/p>\n<p><a href=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/kaitai-eyeglass-navigation.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1489\" src=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/kaitai-eyeglass-navigation.gif\" alt=\"\" width=\"1502\" height=\"955\" \/><\/a><\/p>\n<p>The animated graphic here shows how kaitai parses the eyeglass format and recognizes the data type boundaries (fields) we&#8217;ve been discussing in the examples above.<\/p>\n<p><a href=\"https:\/\/doc.kaitai.io\/user_guide.html#_introduction\" target=\"_blank\" rel=\"noopener\">Kaitai<\/a> is described as a domain specific language concerned with the parsing of arbitrary binary formats.<\/p>\n<p>Further, in their introductory text:<\/p>\n<blockquote><p>Parsing binary formats is hard, and there\u2019s a reason for that: such formats were designed to be machine-readable, not human-readable. Even when one\u2019s working with a clean, well-documented format, there are multiple pitfalls that await the developer: endianness issues, in-memory structure alignment, variable size structures, conditional fields, repetitions, fields that depend on other fields previously read, etc, etc, to name a few.<\/p>\n<p>Kaitai Struct tries to isolate the developer from all these details and allow them to focus on the things that matter: the data structure itself, not particular ways to read or write it.<\/p><\/blockquote>\n<h3>Parsing eyeglass in Kaitai<\/h3>\n<p>We know how the eyeglass file format is structured. We helpfully (!) have a list of the data-types and sizes and what those mean. We can translate those in to the &#8220;ksy&#8221; <a href=\"https:\/\/en.wikipedia.org\/wiki\/YAML\" target=\"_blank\" rel=\"noopener\">YAML<\/a> &#8220;<a href=\"https:\/\/doc.kaitai.io\/user_guide.html#_kaitai_struct_language\" target=\"_blank\" rel=\"noopener\">kaitai struct language<\/a>&#8221; format consumed by kaitai to allow kaitai conformant tools to parse the binary format and to identify the field boundaries and attach meaning to those.<\/p>\n<p>Given the right instructions kaitai is clever enough to understand how to interpret endianness and the values within certain fields. The format incorporates metadata in the form of a header, and additional documentation strings that can also be used by kaitai tools to output more information to the user.<\/p>\n<p>A small snippet from the kaitai structs created for the eyeglass format:<\/p>\n<pre>meta:\r\n  id: eyeglass_format\r\n  file-extension: eygl\r\n  xref:\r\n    wikidata: Q105858419\r\n  endian: be\r\n  tags:\r\n    - digipres\r\n  license: CC-BY-SA\r\ndoc: |\r\n  The eyeglass format...\r\nseq:\r\n  - id: magic\r\n    size: 14\r\n    type: str\r\n    encoding: utf8\r\n  - id: version\r\n    size: 1\r\n  - id: endianness\r\n    type: s1\r\n  - id: datetime\r\n    size: 19\r\n    type: str\r\n    doc: \"the date this file was created\"\r\n    encoding: utf8<\/pre>\n<p>Field types can be defined as well as field lengths.<\/p>\n<p>In the snippet above we have strings (str); signed 1-byte integers (s1); and encodings (utf-8). If a field wasn&#8217;t known but a field length could be determined then size would be enough to start to parse the data and kaitai&#8217;s tooling can start to guess at the values to help with reverse engineering efforts.<\/p>\n<p>We can parse the format with kaitai using the tool <a href=\"https:\/\/github.com\/kaitai-io\/kaitai_struct_visualizer\" target=\"_blank\" rel=\"noopener\">kaitai-struct-visualizer<\/a>.<\/p>\n<p>and the command:<\/p>\n<ul>\n<li>\n<pre>ksv &lt;eygl-file&gt; eyeglass_big_endian.ksy<\/pre>\n<\/li>\n<\/ul>\n<p>The result of parsing looks as follows:<\/p>\n<pre>[-] [root]\r\n  [.] magic = \"\\xBB\\r\\neyeglass\\u001A\\n\\xAB\"\r\n  [.] version = 01\r\n  [.] endianness = 1\r\n  [.] datetime = \"2012-11-08T12:37:50\"\r\n  [.] format_expansion_room = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \u2026\r\n  [-] sphere_right_left (2 = 0x2 entries)\r\n    [.] 0 = -3.3499999046325684\r\n    [.] 1 = 0.5\r\n  [-] cylinder_right_left (2 = 0x2 entries)\r\n    [.] 0 = -0.25\r\n    [.] 1 = -1.0\r\n  [-] axis_right_left (2 = 0x2 entries)\r\n    [.] 0 = 130\r\n    [.] 1 = 80\r\n  [-] prism_right_left (2 = 0x2 entries)\r\n    [.] 0 = 0.0\r\n    [.] 1 = 0.0\r\n  [-] base_right_left (2 = 0x2 entries)\r\n    [.] 0 = 0.0\r\n    [.] 1 = 0.0\r\n  [-] distance_acuity_right_left (2 = 0x2 entries)\r\n    [.] 0 = 0.6600000262260437\r\n    [.] 1 = 0.5\r\n  [-] near_acuity_right_left (2 = 0x2 entries)\r\n    [.] 0 = 12\r\n    [.] 1 = 12\r\n  [.] purpose = \"Distance and Close Work.\r\n  [.] observation = \"Patient's eyesight needs correction. History of diabetes in family\r\n[.] next_checkup_years = 1.0\r\n[.] eof = \"\\xBBeof\"<\/pre>\n<p>The kaitai structs for the eyeglass format are available in GitHub:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/ross-spencer\/eyeglass\/blob\/71dbd324ae621f135d95f48d9515fcedc2c79790\/kaitai\/eyeglass_big_endian.ksy\" target=\"_blank\" rel=\"noopener\">eyeglass big endian<\/a>.<\/li>\n<li><a href=\"https:\/\/github.com\/ross-spencer\/eyeglass\/blob\/71dbd324ae621f135d95f48d9515fcedc2c79790\/kaitai\/eyeglass_little_endian.ksy\" target=\"_blank\" rel=\"noopener\">eyeglass little endian<\/a>.<\/li>\n<\/ul>\n<p>With sample files:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/ross-spencer\/eyeglass\/blob\/71dbd324ae621f135d95f48d9515fcedc2c79790\/prescription-sample-1.0-be.eygl\" target=\"_blank\" rel=\"noopener\">Eyeglass sample, bug endian<\/a>.<\/li>\n<li><a href=\"https:\/\/github.com\/ross-spencer\/eyeglass\/blob\/71dbd324ae621f135d95f48d9515fcedc2c79790\/prescription-sample-1.0-le.eygl\" target=\"_blank\" rel=\"noopener\">Eyeglass sample, little endian<\/a>.<\/li>\n<\/ul>\n<p>And they can be used immediately with tools such as the online kaitai IDE (integrated development environment).<\/p>\n<p><a href=\"https:\/\/ide.kaitai.io\/\" target=\"_blank\" rel=\"noopener\">Kaitai IDE online<\/a>.<\/p>\n<h3>How we can use kaitai iteratively in digital preservation<\/h3>\n<p>The skills required to interpret file formats through kaitai are similar to those required for file format signature development. As signature developers and digital preservationists start to understand new file formats (or old as yet undocumented ones) as they go through their daily work reverse engineering or finding snippets of file format specifications they can build kaitai struct definitions piece by piece with the data that is immediately known to them, and slowly add to them over time as new fields are understood. As these definitions are generated and shared we may collectively get a better understanding of the files through a lens such as that presented here in this second eyeglass blog today.<\/p>\n<h4>Steps to take<\/h4>\n<ul>\n<li>Document the field boundaries of the header that you can identify, e.g. the first field you can document might be the magic number and its size.<\/li>\n<li>Try to identify header fields one-by-one and name those and provide their byte-sizes.<\/li>\n<li>Mark unknown fields with a suitable name, and document how many bytes they use.<\/li>\n<\/ul>\n<h4>Questions<\/h4>\n<p>Kaitai does support some complicated use-cases such as fields positioned based on variable offsets but it doesn&#8217;t seem to offer much help for documenting the unknowns, or matching based on incomplete information such as the space between a header and fields at the end of a stream. Also, it isn&#8217;t clear to me that Kaitai supports relative positioning, e.g. relative from end of file. So I would like to understand that more.<\/p>\n<p>Kaitai&#8217;s purpose goes beyond documenting file format structures and its tooling provides the ability to output working source code for parsing file formats; this could be an exciting prospect for the field, but it also means the tooling might not be a perfect fit for digital preservation. The eyeglass example is a simple one after all, but I will be interested to read about other experiments in this area.<\/p>\n<h2>Further reading<\/h2>\n<p>I have discussed collecting community built knowledge bases for file format signatures <a href=\"https:\/\/openpreservation.org\/blogs\/proposal-github-to-enable-a-federated-approach-to-distributing-and-utilising-custom-droid-signatures\/?page=3&amp;q=33\" target=\"_blank\" rel=\"noopener\">previously<\/a>, perhaps we can do something for kaitai struct definitions? (NB. check out the <a href=\"https:\/\/github.com\/digital-preservation\/PRONOM_Research\" target=\"_blank\" rel=\"noopener\">PRONOM Research repository<\/a> that the PRONOM team established that achieves something similar for PRONOM file format work)<\/p>\n<p>Check out the <a href=\"https:\/\/github.com\/kaitai-io\/awesome-kaitai\" target=\"_blank\" rel=\"noopener\">awesome-kaitai<\/a> list for more guides around the definitions and how to use them.<\/p>\n<p><a href=\"https:\/\/github.com\/wader\/fq\" target=\"_blank\" rel=\"noopener\">fq<\/a> (jq for file formats) is another promising tool for this sort of effort that others should take a look at.<\/p>\n<p>The Eyeglass file format has its own <a href=\"https:\/\/www.wikidata.org\/entity\/Q105858419\" target=\"_blank\" rel=\"noopener\">Wikidata entry<\/a> which is pretty cool (thank you to the editors who put that up!). It can also be found on the ArchiveTeam <a href=\"http:\/\/fileformats.archiveteam.org\/wiki\/Eyeglass_file_format_(Ross_Spencer)\" target=\"_blank\" rel=\"noopener\">Just Solve It Wiki<\/a> (thank you Dan for that as well).<\/p>\n<h2>Prologue: ksdump<\/h2>\n<p><em>5 November, 2023<\/em><\/p>\n<p>Mattias Wadman pointed out on <a href=\"https:\/\/fosstodon.org\/@wader\/111284703538214904\" target=\"_blank\" rel=\"noopener\">Mastodon<\/a> that ksdump can be used to output YAML or JSON &#8212; as Mattias realized, this was actually difficult for me to get hold off for this blog as I had found a workaround using the kaitai visualizer output.<\/p>\n<p>ksdump works well, see the little endian JSON output below:<\/p>\n<pre>{\r\n\u00a0 \u00a0\"axis_right_left\": [\r\n\u00a0 \u00a0 \u00a0 130,\r\n\u00a0 \u00a0 \u00a0 80\r\n\u00a0 \u00a0],\r\n\u00a0 \u00a0\"base_right_left\": [\r\n\u00a0 \u00a0 \u00a0 0.0,\r\n\u00a0 \u00a0 \u00a0 0.0\r\n\u00a0 \u00a0],\r\n\u00a0 \u00a0\"cylinder_right_left\": [\r\n\u00a0 \u00a0 \u00a0 -0.25,\r\n\u00a0 \u00a0 \u00a0 -1.0\r\n\u00a0 \u00a0],\r\n\u00a0 \u00a0\"datetime\": \"2012-11-08T12:37:50\",\r\n\u00a0 \u00a0\"distance_acuity_right_left\": [\r\n\u00a0 \u00a0 \u00a0 0.6600000262260437,\r\n\u00a0 \u00a0 \u00a0 0.5\r\n\u00a0 \u00a0],\r\n\u00a0 \u00a0\"endianness\": 0,\r\n\u00a0 \u00a0\"eof\": {\r\n\u00a0 \u00a0 \u00a0 \"eof_1\": \"BB\",\r\n\u00a0 \u00a0 \u00a0 \"eof_2\": \"eof\"\r\n\u00a0 \u00a0},\r\n\u00a0 \u00a0\"format_expansion_room\": \"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\",\r\n\u00a0 \u00a0\"magic\": {\r\n\u00a0 \u00a0 \u00a0 \"magic_1\": \"BB 0D 0A\",\r\n\u00a0 \u00a0 \u00a0 \"magic_2\": \"eyeglass\",\r\n\u00a0 \u00a0 \u00a0 \"magic_3\": \"1A 0A AB\"\r\n\u00a0 \u00a0},\r\n\u00a0 \u00a0\"near_acuity_right_left\": [\r\n\u00a0 \u00a0 \u00a0 12,\r\n\u00a0 \u00a0 \u00a0 12\r\n\u00a0 \u00a0],\r\n\u00a0 \u00a0\"next_checkup_years\": 1.0,\r\n\u00a0 \u00a0\"observation\": \"Patient's eyesight needs correction. History of diabetes in family but indicators found. Standard checkup interval recommended.\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\",\r\n\u00a0 \u00a0\"prism_right_left\": [\r\n\u00a0 \u00a0 \u00a0 0.0,\r\n\u00a0 \u00a0 \u00a0 0.0\r\n\u00a0 \u00a0],\r\n\u00a0 \u00a0\"purpose\": \"Distance and Close Work.\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\",\r\n\u00a0 \u00a0\"sphere_right_left\": [\r\n\u00a0 \u00a0 \u00a0 -3.3499999046325684,\r\n\u00a0 \u00a0 \u00a0 0.5\r\n\u00a0 \u00a0],\r\n\u00a0 \u00a0\"version\": \"01\"\r\n}\r\n<\/pre>\n<p>This could be very powerful paired with tools such as JQ. It could also be parsed into technical metadata and committed into a digital repository system.<\/p>\n<h3>A little more on debugging<\/h3>\n<p>ksdump provided me with another layer of debugging for the definition I wrote as I asked the tool to parse the format and the structural data.<\/p>\n<p>I received an error when trying to output the JSON (or YAML) because I had incorrectly defined the beginning and end of file (BOF and EOF) sequences as UTF-8 encoded string types.<\/p>\n<pre class=\"notranslate\" lang=\"text\"><code class=\"notranslate\">ksdump prescription-sample-1.0-le.eygl kaitai\/eyeglass_little_endian.ksy \r\nCompilation OK\r\n... processing kaitai\/eyeglass_little_endian.ksy 0\r\n...... loading eyeglass_format.rb\r\nClasses loaded OK, main class = EyeglassFormat\r\n\/usr\/lib\/ruby\/3.0.0\/psych\/visitors\/yaml_tree.rb:268:in `visit_String': invalid byte sequence in UTF-8 (ArgumentError)\r\n\t   from \/usr\/lib\/ruby\/3.0.0\/psych\/visitors\/yaml_tree.rb:136:in `accept'\r\n\t   from \/usr\/lib\/ruby\/3.0.0\/psych\/visitors\/yaml_tree.rb:330:in `block in visit_Hash'\r\n\t   from \/usr\/lib\/ruby\/3.0.0\/psych\/visitors\/yaml_tree.rb:328:in `each'\r\n\t   from \/usr\/lib\/ruby\/3.0.0\/psych\/visitors\/yaml_tree.rb:328:in `visit_Hash'\r\n\t   from \/usr\/lib\/ruby\/3.0.0\/psych\/visitors\/yaml_tree.rb:136:in `accept'\r\n\t   from \/usr\/lib\/ruby\/3.0.0\/psych\/visitors\/yaml_tree.rb:118:in `push'\r\n\t   from \/usr\/lib\/ruby\/3.0.0\/psych.rb:513:in `dump'\r\n\t   from \/usr\/lib\/ruby\/3.0.0\/psych\/core_ext.rb:13:in `to_yaml'\r\n\t   from \/var\/lib\/gems\/3.0.0\/gems\/kaitai-struct-visualizer-0.7\/bin\/ksdump:122:in `&lt;top (required)&gt;'\r\n\t   from \/usr\/local\/bin\/ksdump:25:in `load'\r\n\t   from \/usr\/local\/bin\/ksdump:25:in `&lt;main&gt;'<\/code><\/pre>\n<p>The two fields in the specification are meant to encode some binary data as well as some plain-text information. Mikhail of the Kaitai project was super helpful pinpointing what I did wrong here and I understand the difficulty of writing arbitrary binary strings in text based formats such as either YAML or JSON from other projects.<\/p>\n<p>I changed the structure of the objects to use custom types for the BOF (magic number) and EOF. The structure gives me more granularity to annotate the binary and plain-text data accordingly.<\/p>\n<p>Read more about the error on <a href=\"https:\/\/github.com\/kaitai-io\/kaitai_struct_visualizer\/issues\/61\" target=\"_blank\" rel=\"noopener\">GitHub<\/a> and take a look at how this now manifests in the ksy definition for eyeglass <a href=\"https:\/\/github.com\/ross-spencer\/eyeglass\/commit\/7491c31b28fb9240471a544ad74121e22d77b4e7\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_1465\" class=\"pvc_stats total_only  \" data-element-id=\"1465\" style=\"\"><i class=\"pvc-stats-icon small\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>In my post from 2012: <a href=\"https:\/\/exponentialdecay.co.uk\/blog\/genesis-of-a-file-format\/\" target=\"_blank\" rel=\"noopener\">Genesis of a File Format<\/a>, I created a new file format &#8211; the <a href=\"https:\/\/www.wikidata.org\/entity\/Q105858419\" target=\"_blank\" rel=\"noopener\"><em>Eyeglass<\/em> file format<\/a>. The format provides a mechanism to persist information about a patient&#8217;s eye health following a checkup at an opticians. Today in 2023 we can use the format to understand how to make use of <a href=\"https:\/\/kaitai.io\/\" target=\"_blank\" rel=\"noopener\">Kaitai Structs<\/a> for understanding file formats.<\/p>\n<p>Given the disclaimer that I am not actually an optician and that the format is purely illustrative, let&#8217;s look at the eyeglass again below.<\/p>\n<div class=\"link-more\"><a href=\"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &ldquo;Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass&#8217; contents&rdquo;<\/span>&hellip;<\/a><\/div>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_1465\" class=\"pvc_stats total_only  \" data-element-id=\"1465\" style=\"\"><i class=\"pvc-stats-icon small\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"author":1,"featured_media":1494,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":3,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"federated","footnotes":""},"categories":[114,3,20],"tags":[61,96,147,115,71,29,372,17,190,16,373],"class_list":["post-1465","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-digital-literacy","category-digital-preservation","category-just-code","tag-code","tag-coding","tag-digipres","tag-digital-literacy","tag-digital-preservation","tag-file-format","tag-file-format-analysis","tag-file-formats","tag-kaitai","tag-pronom","tag-yyyy","entry"],"a3_pvc":{"activated":true,"total_views":522,"today_views":0},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass&#039; contents - ross spencer :: exponentialdecay.digipres :: blog<\/title>\n<meta name=\"description\" content=\"Revisiting the Eyeglass format to introduce Kaitai Structs for the understanding of file formats in digital preservation.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass&#039; contents - ross spencer :: exponentialdecay.digipres :: blog\" \/>\n<meta property=\"og:description\" content=\"Revisiting the Eyeglass format to introduce Kaitai Structs for the understanding of file formats in digital preservation.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/\" \/>\n<meta property=\"og:site_name\" content=\"ross spencer :: exponentialdecay.digipres :: blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-10-20T22:32:29+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-12-01T16:59:54+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/kaitai-blog-header.jpeg\" \/>\n\t<meta property=\"og:image:width\" content=\"1850\" \/>\n\t<meta property=\"og:image:height\" content=\"944\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Ross Spencer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@beet_keeper\" \/>\n<meta name=\"twitter:site\" content=\"@beet_keeper\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ross Spencer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/\"},\"author\":{\"name\":\"Ross Spencer\",\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/#\\\/schema\\\/person\\\/4cae0a954400f42b9c1b70c699837716\"},\"headline\":\"Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass&#8217; contents\",\"datePublished\":\"2023-10-20T22:32:29+00:00\",\"dateModified\":\"2025-12-01T16:59:54+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/\"},\"wordCount\":2130,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/#\\\/schema\\\/person\\\/4cae0a954400f42b9c1b70c699837716\"},\"image\":{\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/kaitai-blog-header.jpeg\",\"keywords\":[\"Code\",\"Coding\",\"digipres\",\"digital literacy\",\"Digital Preservation\",\"File Format\",\"File Format Analysis\",\"File Formats\",\"kaitai\",\"PRONOM\",\"YYYY\"],\"articleSection\":[\"Digital Literacy\",\"Digital Preservation\",\"Just Code\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/\",\"url\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/\",\"name\":\"Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass' contents - ross spencer :: exponentialdecay.digipres :: blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/kaitai-blog-header.jpeg\",\"datePublished\":\"2023-10-20T22:32:29+00:00\",\"dateModified\":\"2025-12-01T16:59:54+00:00\",\"description\":\"Revisiting the Eyeglass format to introduce Kaitai Structs for the understanding of file formats in digital preservation.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/#primaryimage\",\"url\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/kaitai-blog-header.jpeg\",\"contentUrl\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/kaitai-blog-header.jpeg\",\"width\":1850,\"height\":944},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/shattering-the-eyeglass\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass&#8217; contents\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/\",\"name\":\"ross spencer :: exponentialdecay.digipres :: blog\",\"description\":\"Digital preservation analyst, researcher, and software developer\",\"publisher\":{\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/#\\\/schema\\\/person\\\/4cae0a954400f42b9c1b70c699837716\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/#\\\/schema\\\/person\\\/4cae0a954400f42b9c1b70c699837716\",\"name\":\"Ross Spencer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/avatar-scaled.png\",\"url\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/avatar-scaled.png\",\"contentUrl\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/avatar-scaled.png\",\"width\":2560,\"height\":2560,\"caption\":\"Ross Spencer\"},\"logo\":{\"@id\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/avatar-scaled.png\"},\"description\":\"Digital preservation domain expert and full-stack software developer.\",\"sameAs\":[\"http:\\\/\\\/www.exponentialdecay.co.uk\\\/blog\",\"https:\\\/\\\/www.instagram.com\\\/b33tk33p3r\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/in\\\/ross-spencer-b6b9b758\\\/\",\"https:\\\/\\\/x.com\\\/beet_keeper\"],\"url\":\"https:\\\/\\\/exponentialdecay.co.uk\\\/blog\\\/author\\\/exponentialdecay\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass' contents - ross spencer :: exponentialdecay.digipres :: blog","description":"Revisiting the Eyeglass format to introduce Kaitai Structs for the understanding of file formats in digital preservation.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/","og_locale":"en_US","og_type":"article","og_title":"Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass' contents - ross spencer :: exponentialdecay.digipres :: blog","og_description":"Revisiting the Eyeglass format to introduce Kaitai Structs for the understanding of file formats in digital preservation.","og_url":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/","og_site_name":"ross spencer :: exponentialdecay.digipres :: blog","article_published_time":"2023-10-20T22:32:29+00:00","article_modified_time":"2025-12-01T16:59:54+00:00","og_image":[{"width":1850,"height":944,"url":"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/kaitai-blog-header.jpeg","type":"image\/jpeg"}],"author":"Ross Spencer","twitter_card":"summary_large_image","twitter_creator":"@beet_keeper","twitter_site":"@beet_keeper","twitter_misc":{"Written by":"Ross Spencer","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/#article","isPartOf":{"@id":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/"},"author":{"name":"Ross Spencer","@id":"https:\/\/exponentialdecay.co.uk\/blog\/#\/schema\/person\/4cae0a954400f42b9c1b70c699837716"},"headline":"Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass&#8217; contents","datePublished":"2023-10-20T22:32:29+00:00","dateModified":"2025-12-01T16:59:54+00:00","mainEntityOfPage":{"@id":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/"},"wordCount":2130,"commentCount":2,"publisher":{"@id":"https:\/\/exponentialdecay.co.uk\/blog\/#\/schema\/person\/4cae0a954400f42b9c1b70c699837716"},"image":{"@id":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/#primaryimage"},"thumbnailUrl":"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/kaitai-blog-header.jpeg","keywords":["Code","Coding","digipres","digital literacy","Digital Preservation","File Format","File Format Analysis","File Formats","kaitai","PRONOM","YYYY"],"articleSection":["Digital Literacy","Digital Preservation","Just Code"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/","url":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/","name":"Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass' contents - ross spencer :: exponentialdecay.digipres :: blog","isPartOf":{"@id":"https:\/\/exponentialdecay.co.uk\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/#primaryimage"},"image":{"@id":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/#primaryimage"},"thumbnailUrl":"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/kaitai-blog-header.jpeg","datePublished":"2023-10-20T22:32:29+00:00","dateModified":"2025-12-01T16:59:54+00:00","description":"Revisiting the Eyeglass format to introduce Kaitai Structs for the understanding of file formats in digital preservation.","breadcrumb":{"@id":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/#primaryimage","url":"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/kaitai-blog-header.jpeg","contentUrl":"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2023\/10\/kaitai-blog-header.jpeg","width":1850,"height":944},{"@type":"BreadcrumbList","@id":"https:\/\/exponentialdecay.co.uk\/blog\/shattering-the-eyeglass\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/exponentialdecay.co.uk\/blog\/"},{"@type":"ListItem","position":2,"name":"Shattering the eyeglass: Using Kaitai Structs to dissect the eyeglass&#8217; contents"}]},{"@type":"WebSite","@id":"https:\/\/exponentialdecay.co.uk\/blog\/#website","url":"https:\/\/exponentialdecay.co.uk\/blog\/","name":"ross spencer :: exponentialdecay.digipres :: blog","description":"Digital preservation analyst, researcher, and software developer","publisher":{"@id":"https:\/\/exponentialdecay.co.uk\/blog\/#\/schema\/person\/4cae0a954400f42b9c1b70c699837716"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/exponentialdecay.co.uk\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/exponentialdecay.co.uk\/blog\/#\/schema\/person\/4cae0a954400f42b9c1b70c699837716","name":"Ross Spencer","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2025\/06\/avatar-scaled.png","url":"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2025\/06\/avatar-scaled.png","contentUrl":"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2025\/06\/avatar-scaled.png","width":2560,"height":2560,"caption":"Ross Spencer"},"logo":{"@id":"https:\/\/exponentialdecay.co.uk\/blog\/wp-content\/uploads\/2025\/06\/avatar-scaled.png"},"description":"Digital preservation domain expert and full-stack software developer.","sameAs":["http:\/\/www.exponentialdecay.co.uk\/blog","https:\/\/www.instagram.com\/b33tk33p3r\/","https:\/\/www.linkedin.com\/in\/ross-spencer-b6b9b758\/","https:\/\/x.com\/beet_keeper"],"url":"https:\/\/exponentialdecay.co.uk\/blog\/author\/exponentialdecay\/"}]}},"views":3860,"_links":{"self":[{"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/posts\/1465","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=1465"}],"version-history":[{"count":42,"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/posts\/1465\/revisions"}],"predecessor-version":[{"id":2562,"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/posts\/1465\/revisions\/2562"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/media\/1494"}],"wp:attachment":[{"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=1465"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=1465"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/exponentialdecay.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=1465"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}