<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Karim DRIDI</title>
    <description>The latest articles on DEV Community by Karim DRIDI (@kdridi).</description>
    <link>https://dev.to/kdridi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F114143%2F4fa7a3fe-f590-4c65-a06e-c9434f95cc7d.jpeg</url>
      <title>DEV Community: Karim DRIDI</title>
      <link>https://dev.to/kdridi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kdridi"/>
    <language>en</language>
    <item>
      <title>D’une image nommée .iso à un premier probe en Haskell</title>
      <dc:creator>Karim DRIDI</dc:creator>
      <pubDate>Thu, 03 Sep 2026 00:31:00 +0000</pubDate>
      <link>https://dev.to/kdridi/dune-image-nommee-iso-a-un-premier-probe-en-haskell-41ia</link>
      <guid>https://dev.to/kdridi/dune-image-nommee-iso-a-un-premier-probe-en-haskell-41ia</guid>
      <description>&lt;p&gt;&lt;strong&gt;À propos de cette série.&lt;/strong&gt; Cette série raconte la construction progressive, en Haskell, d’outils consacrés à l’étude et à la transformation des formats binaires employés par les jeux FromSoftware sur PlayStation 3. Elle prend pour premier corpus la version PlayStation 3 originale de &lt;em&gt;Demon’s Souls&lt;/em&gt; et avance par enquêtes reproductibles : observer une structure, établir ce qui est documenté, distinguer les faits des hypothèses, puis implémenter la plus petite capacité nécessaire à l’étape suivante.&lt;/p&gt;




&lt;p&gt;Dans ce premier article, nous allons déterminer ce qu’un fichier nommé &lt;code&gt;image.iso&lt;/code&gt; permet réellement d’affirmer. Nous commencerons par observer ses métadonnées au moyen de lectures précisément bornées, avant de reproduire cette reconnaissance dans un prototype direct écrit en Haskell.&lt;/p&gt;

&lt;p&gt;Le nom &lt;code&gt;image.iso&lt;/code&gt; constitue une hypothèse, non une preuve de format. Une extension est une convention du système de fichiers hôte ; elle ne garantit pas le contenu du fichier. Nous allons donc rechercher une structure définie par ISO 9660, lire plusieurs champs précis, puis reconnaître deux informations supplémentaires : un marqueur Joliet et un enregistrement propre aux disques PlayStation 3.&lt;/p&gt;

&lt;p&gt;Notre périmètre restera strictement en lecture seule. Nous ne monterons pas l’image, ne parcourrons aucun répertoire, n’extrairons rien, ne déchiffrerons rien et n’écrirons aucun octet. À la fin, notre prototype affichera seulement :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ps3.product-id=BLES-00932
iso9660.volume-id=PS3VOLUME
iso9660.logical-block-size=2048
joliet.level=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ces quatre lignes sont un résultat de reconnaissance borné, non un certificat de conformité de l’image entière.&lt;/p&gt;

&lt;h2&gt;
  
  
  De la position logique à l’offset
&lt;/h2&gt;

&lt;p&gt;Un fichier binaire est une suite d’octets. Nous appelons &lt;strong&gt;offset&lt;/strong&gt; la position, comptée depuis zéro, d’un octet dans cette suite.&lt;/p&gt;

&lt;p&gt;ISO 9660 organise les informations qui nous intéressent en secteurs logiques de 2 048 octets. Une &lt;strong&gt;LBA&lt;/strong&gt; (&lt;em&gt;Logical Block Address&lt;/em&gt;, adresse logique de bloc) est le numéro d’un tel secteur : le secteur de LBA 0 commence à l’offset 0, celui de LBA 1 à l’offset 2 048, et ainsi de suite. La formule que nous réutiliserons est :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;offset absolu = LBA × taille du secteur + offset relatif du champ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Selon &lt;a href="https://ecma-international.org/publications-and-standards/standards/ecma-119/" rel="noopener noreferrer"&gt;ECMA-119&lt;/a&gt;, la norme qui décrit ISO 9660, les secteurs de LBA 0 à 15 forment la &lt;em&gt;System Area&lt;/em&gt;, ou zone système. La séquence des descripteurs de volume commence à la LBA 16. &lt;a href="https://wiki.osdev.org/ISO_9660" rel="noopener noreferrer"&gt;La page ISO 9660 d’OSDev&lt;/a&gt; fournit une table pratique pour s’orienter ; ECMA-119 demeure la source normative.&lt;/p&gt;

&lt;p&gt;Nous commençons par deux constantes Shell :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;IMAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;image.iso &lt;span class="c"&gt;# Remplacer au besoin par un chemin absolu vers l’image locale.&lt;/span&gt;
&lt;span class="nv"&gt;SECTOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2048
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Toutes les commandes &lt;code&gt;xxd&lt;/code&gt; de cet article emploient &lt;code&gt;-s&lt;/code&gt; pour fixer l’offset et &lt;code&gt;-l&lt;/code&gt; pour borner la quantité lue. L’option &lt;code&gt;-g 1&lt;/code&gt; sépare les octets à l’affichage. Aucune de ces commandes ne modifie l’image ; nous n’utiliserons notamment jamais &lt;code&gt;xxd -r&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reconnaître le descripteur principal de volume
&lt;/h2&gt;

&lt;p&gt;Un &lt;strong&gt;descripteur de volume&lt;/strong&gt; (&lt;em&gt;Volume Descriptor&lt;/em&gt;) est un secteur de métadonnées. La séquence qui les contient commence à la LBA 16 et doit comprendre au moins un &lt;strong&gt;descripteur principal de volume&lt;/strong&gt; (&lt;em&gt;Primary Volume Descriptor&lt;/em&gt;). Dans notre image, ce descripteur principal est précisément le premier élément de la séquence.&lt;/p&gt;

&lt;p&gt;Tous les descripteurs ISO 9660 commencent par le même en-tête de sept octets. Les offsets de l’article sont comptés depuis zéro ; la colonne « Position ECMA-119 » reprend la numérotation à partir de 1 employée par la norme.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset relatif&lt;/th&gt;
&lt;th&gt;Position ECMA-119&lt;/th&gt;
&lt;th&gt;Taille&lt;/th&gt;
&lt;th&gt;Nom canonique du champ&lt;/th&gt;
&lt;th&gt;Rôle&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nature du descripteur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2 à 6&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Standard Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;identifiant &lt;code&gt;CD001&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;version de la structure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Le descripteur principal occupe exactement 2 048 octets. Sa disposition complète est la suivante. Les champs que notre probe décodera ne sont donc pas les seuls renseignements disponibles dans ce secteur.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset relatif&lt;/th&gt;
&lt;th&gt;Position ECMA-119&lt;/th&gt;
&lt;th&gt;Taille&lt;/th&gt;
&lt;th&gt;Nom canonique du champ&lt;/th&gt;
&lt;th&gt;Encodage ou fonction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 8 bits, valeur 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2 à 6&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Standard Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;CD001&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 8 bits, valeur 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Unused Field&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;octet nul&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;9 à 40&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;&lt;code&gt;System Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;a&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;41 à 72&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;d&lt;/code&gt;, complétés à largeur fixe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;td&gt;73 à 80&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Unused Field&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;octets nuls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;81 à 88&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Space Size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 32 bits both-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;88&lt;/td&gt;
&lt;td&gt;89 à 120&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Unused Field&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;octets nuls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;121 à 124&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Set Size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 16 bits both-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;124&lt;/td&gt;
&lt;td&gt;125 à 128&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Sequence Number&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 16 bits both-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;129 à 132&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Logical Block Size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 16 bits both-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;132&lt;/td&gt;
&lt;td&gt;133 à 140&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Path Table Size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 32 bits both-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;140&lt;/td&gt;
&lt;td&gt;141 à 144&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Location of Occurrence of Type L Path Table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;numéro de bloc, little-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;144&lt;/td&gt;
&lt;td&gt;145 à 148&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Location of Optional Occurrence of Type L Path Table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;numéro de bloc, little-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;148&lt;/td&gt;
&lt;td&gt;149 à 152&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Location of Occurrence of Type M Path Table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;numéro de bloc, big-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;152&lt;/td&gt;
&lt;td&gt;153 à 156&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Location of Optional Occurrence of Type M Path Table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;numéro de bloc, big-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;156&lt;/td&gt;
&lt;td&gt;157 à 190&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Directory Record for Root Directory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;enregistrement du répertoire racine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;190&lt;/td&gt;
&lt;td&gt;191 à 318&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Set Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;d&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;318&lt;/td&gt;
&lt;td&gt;319 à 446&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Publisher Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;a&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;446&lt;/td&gt;
&lt;td&gt;447 à 574&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Data Preparer Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;a&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;574&lt;/td&gt;
&lt;td&gt;575 à 702&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Application Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;a&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;702&lt;/td&gt;
&lt;td&gt;703 à 739&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Copyright File Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;identifiant de fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;739&lt;/td&gt;
&lt;td&gt;740 à 776&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Abstract File Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;identifiant de fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;776&lt;/td&gt;
&lt;td&gt;777 à 813&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Bibliographic File Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;identifiant de fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;813&lt;/td&gt;
&lt;td&gt;814 à 830&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Creation Date and Time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;date et heure décimales&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;830&lt;/td&gt;
&lt;td&gt;831 à 847&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Modification Date and Time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;date et heure décimales&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;847&lt;/td&gt;
&lt;td&gt;848 à 864&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Expiration Date and Time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;date et heure décimales&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;864&lt;/td&gt;
&lt;td&gt;865 à 881&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Effective Date and Time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;date et heure décimales&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;881&lt;/td&gt;
&lt;td&gt;882&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;File Structure Version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 8 bits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;882&lt;/td&gt;
&lt;td&gt;883&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;champ réservé&lt;/td&gt;
&lt;td&gt;octet nul&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;883&lt;/td&gt;
&lt;td&gt;884 à 1395&lt;/td&gt;
&lt;td&gt;512&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Application Use&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;contenu non spécifié par ECMA-119&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1395&lt;/td&gt;
&lt;td&gt;1396 à 2048&lt;/td&gt;
&lt;td&gt;653&lt;/td&gt;
&lt;td&gt;champ réservé&lt;/td&gt;
&lt;td&gt;octets nuls&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Les catégories de caractères &lt;code&gt;a&lt;/code&gt; et &lt;code&gt;d&lt;/code&gt; sont définies par ECMA-119. Elles imposent un répertoire de caractères plus précis que la simple propriété « octet ASCII ». Nous ne décoderons ici que les champs nécessaires au résultat final, mais les offsets du tableau permettent d’examiner les autres sans rechercher de nouveau la disposition générale.&lt;/p&gt;

&lt;p&gt;La LBA 16 commence à :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;16 × 2 048 = 32 768 = 0x8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous lisons donc exactement ses sept premiers octets :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 7 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La sortie observée dans notre image est :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00008000: 01 43 44 30 30 31 01                             .CD001.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous pouvons maintenant situer chaque valeur au lieu de reconnaître seulement une chaîne plausible :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;00008000&lt;/code&gt; est l’offset absolu affiché en hexadécimal ; &lt;code&gt;0x8000&lt;/code&gt; vaut bien 32 768 ;&lt;/li&gt;
&lt;li&gt;le premier octet, &lt;code&gt;01&lt;/code&gt;, est le type du descripteur ; le type 1 désigne le descripteur principal de volume ;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;43 44 30 30 31&lt;/code&gt; est l’encodage ASCII (&lt;em&gt;American Standard Code for Information Interchange&lt;/em&gt;) de l’identifiant standard &lt;code&gt;CD001&lt;/code&gt; ;&lt;/li&gt;
&lt;li&gt;le dernier &lt;code&gt;01&lt;/code&gt; est la version commune du descripteur, ici 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;C’est le &lt;strong&gt;type&lt;/strong&gt;, et non l’octet de version, qui établit la nature principale de ce descripteur. À ce stade, nous avons reconnu un en-tête attendu ; nous n’avons pas validé tout le secteur ni le système de fichiers.&lt;/p&gt;

&lt;p&gt;Si une autre image produit des octets différents, la règle réutilisable n’est pas de rechercher visuellement le mot &lt;code&gt;CD001&lt;/code&gt; n’importe où. Il faut retrouver, à l’offset exact de la LBA 16, le triplet structuré « type 1, identifiant &lt;code&gt;CD001&lt;/code&gt;, version prise en charge ».&lt;/p&gt;

&lt;h3&gt;
  
  
  Le champ &lt;code&gt;Volume Identifier&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Le champ anglais canonique &lt;code&gt;Volume Identifier&lt;/code&gt; désigne l’identifiant textuel du volume. Dans le descripteur principal de volume, il commence à l’offset relatif 40 et occupe 32 octets. Sa position absolue vaut donc :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;16 × 2 048 + 40 = 32 808 = 0x8028
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous lisons les 32 octets, sans davantage :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 32 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous observons :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00008028: 50 53 33 56 4f 4c 55 4d 45 20 20 20 20 20 20 20  PS3VOLUME
00008038: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les octets &lt;code&gt;50 53 33 56 4f 4c 55 4d 45&lt;/code&gt; donnent &lt;code&gt;PS3VOLUME&lt;/code&gt; en ASCII. Les octets &lt;code&gt;20&lt;/code&gt; qui suivent sont des espaces de remplissage jusqu’à la largeur fixe de 32 octets. Pour l’affichage, nous retirerons uniquement ces espaces terminaux. Nous ne supprimerons ni un éventuel espace initial, ni des octets arbitraires qui appartiendraient réellement au champ d’une autre image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Le champ &lt;code&gt;Volume Space Size&lt;/code&gt; et ses deux ordres d’octets
&lt;/h3&gt;

&lt;p&gt;Le champ &lt;code&gt;Volume Space Size&lt;/code&gt;, à l’offset relatif 80, indique un &lt;strong&gt;nombre de blocs logiques&lt;/strong&gt;, pas encore une taille en octets. ECMA-119 l’enregistre deux fois sur quatre octets : d’abord en little-endian, puis en big-endian.&lt;/p&gt;

&lt;p&gt;Ces deux termes décrivent l’ordre des octets d’un entier multioctet. En little-endian, l’octet de poids faible vient en premier ; en big-endian, l’octet de poids fort vient en premier. Nous séparons ici les deux copies afin que leur ordre reste visible :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 4 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 4 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;84&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les sorties observées sont :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00008050: a0 27 43 00                                      .'C.
00008054: 00 43 27 a0                                      .C'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La colonne de droite est seulement une tentative de représentation ASCII par &lt;code&gt;xxd&lt;/code&gt; ; elle n’a aucune signification pour ce champ numérique.&lt;/p&gt;

&lt;p&gt;Pour quatre octets &lt;code&gt;b0 b1 b2 b3&lt;/code&gt;, les formules sont :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;little-endian = b0 + b1×256 + b2×65 536 + b3×16 777 216
big-endian    = b0×16 777 216 + b1×65 536 + b2×256 + b3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Appliquons-les aux octets réellement lus. La copie little-endian donne :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0xa0 + 0x27×0x100 + 0x43×0x10000 + 0x00×0x1000000
= 0x4327a0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La copie big-endian donne directement la même écriture numérique :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00 43 27 a0 = 0x4327a0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or &lt;code&gt;0x4327a0&lt;/code&gt; vaut 4 401 056. Le volume annonce donc 4 401 056 blocs logiques. Sur une autre image, il faut appliquer les mêmes formules à ses propres octets, puis comparer les deux résultats. Un lecteur ne choisit pas la copie qui paraît la plus vraisemblable : leur désaccord constitue une incohérence du champ both-endian.&lt;/p&gt;

&lt;h3&gt;
  
  
  Le champ &lt;code&gt;Logical Block Size&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Il nous manque la taille d’un bloc logique. Le champ &lt;code&gt;Logical Block Size&lt;/code&gt; se trouve à l’offset relatif 128. Il occupe quatre octets : une copie little-endian de deux octets, puis une copie big-endian de deux octets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 2 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 2 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;130&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous observons :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00008080: 00 08                                            ..
00008082: 08 00                                            ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour deux octets &lt;code&gt;b0 b1&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;little-endian = b0 + b1×256
big-endian    = b0×256 + b1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La première copie, &lt;code&gt;00 08&lt;/code&gt;, vaut donc &lt;code&gt;0x00 + 0x08×0x100 = 0x0800&lt;/code&gt;. La seconde, &lt;code&gt;08 00&lt;/code&gt;, vaut également &lt;code&gt;0x0800&lt;/code&gt;. En décimal, &lt;code&gt;0x0800&lt;/code&gt; vaut 2 048 octets par bloc logique.&lt;/p&gt;

&lt;p&gt;Nous pouvons désormais reconstruire la taille annoncée de l’espace du volume :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4 401 056 × 2 048 = 9 013 362 688 octets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comparons cette valeur à la longueur du fichier hôte, toujours sans le modifier :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La sortie observée est :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-rw-r--r--@ 1 kdridi  staff  9013362688 Sep  2 02:02 image.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour cet échantillon, la longueur du fichier est exactement égale à l’espace annoncé. C’est un contrôle de cohérence utile, pas une égalité universelle : un conteneur peut ajouter du remplissage ou des données après le volume. Dans le modèle direct que nous utilisons ici, un fichier plus court que l’espace annoncé serait en revanche insuffisant pour contenir ce volume.&lt;/p&gt;

&lt;p&gt;Le résultat dépasse 4 Gio (gibioctets). Notre code Haskell devra donc convertir les deux facteurs vers un entier suffisamment large avant de les multiplier ; un entier limité à 32 bits ne convient pas à ce calcul.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parcourir la séquence des descripteurs ISO 9660
&lt;/h2&gt;

&lt;p&gt;Le secteur de LBA 16 n’est que le début d’une séquence. ISO 9660 autorise d’autres descripteurs dans les secteurs suivants et marque la fin de l’ensemble par un &lt;strong&gt;terminateur de séquence de descripteurs de volume&lt;/strong&gt; (&lt;em&gt;Volume Descriptor Set Terminator&lt;/em&gt;) de type 255.&lt;/p&gt;

&lt;p&gt;Le premier octet de l’en-tête commun détermine la nature de chaque secteur de métadonnées :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Valeur du type&lt;/th&gt;
&lt;th&gt;Nom canonique&lt;/th&gt;
&lt;th&gt;Fonction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Boot Record&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;informations destinées à un système d’amorçage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Primary Volume Descriptor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;description principale du volume et d’une arborescence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Supplementary Volume Descriptor&lt;/code&gt; ou &lt;code&gt;Enhanced Volume Descriptor&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;description d’une arborescence supplémentaire ; la version distingue les deux formes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Partition Descriptor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;description d’une partition du volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 à 254&lt;/td&gt;
&lt;td&gt;réservé&lt;/td&gt;
&lt;td&gt;aucune interprétation normalisée ici&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;255&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Set Terminator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;fin de la séquence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Le terminateur possède lui-même une disposition complète particulièrement simple :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset relatif&lt;/th&gt;
&lt;th&gt;Taille&lt;/th&gt;
&lt;th&gt;Nom canonique du champ&lt;/th&gt;
&lt;th&gt;Valeur&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;255&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Standard Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CD001&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;2 041&lt;/td&gt;
&lt;td&gt;champ réservé&lt;/td&gt;
&lt;td&gt;octets nuls&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Puisque les descripteurs occupent chacun un secteur et sont contigus à partir de la LBA 16, les sept octets que nous lirons à chaque itération se répartissent toujours ainsi :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset absolu pour la LBA &lt;code&gt;n&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;Taille&lt;/th&gt;
&lt;th&gt;Champ lu&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;n × 2 048 + 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Type&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;n × 2 048 + 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Standard Identifier&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;n × 2 048 + 6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Version&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Pour explorer ce qui suit, nous regardons volontairement au-delà de la future condition d’arrêt :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;n &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;17 25&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;do
    &lt;/span&gt;xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 7 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La sortie observée est :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00008800: 02 43 44 30 30 31 01                             .CD001.
00009000: ff 43 44 30 30 31 01                             .CD001.
00009800: 00 42 45 41 30 31 01                             .BEA01.
0000a000: 00 4e 53 52 30 33 01                             .NSR03.
0000a800: 00 54 45 41 30 31 01                             .TEA01.
0000b000: 00 00 00 00 00 00 00                             .......
0000b800: 00 00 00 00 00 00 00                             .......
0000c000: 00 00 00 00 00 00 00                             .......
0000c800: 00 00 00 00 00 00 00                             .......
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En réunissant l’en-tête déjà lu à la LBA 16 et les deux premiers résultats de cette boucle, nous obtenons la séquence ISO 9660 suivante :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;LBA&lt;/th&gt;
&lt;th&gt;Offset absolu&lt;/th&gt;
&lt;th&gt;Sept premiers octets&lt;/th&gt;
&lt;th&gt;Interprétation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x8000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;01 43 44 30 30 31 01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;descripteur principal, &lt;code&gt;CD001&lt;/code&gt;, version 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x8800&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;02 43 44 30 30 31 01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;descripteur supplémentaire, &lt;code&gt;CD001&lt;/code&gt;, version 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x9000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ff 43 44 30 30 31 01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;terminateur, &lt;code&gt;CD001&lt;/code&gt;, version 1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;À la LBA 17, &lt;code&gt;02 CD001 01&lt;/code&gt; est l’en-tête d’un &lt;strong&gt;descripteur supplémentaire de volume&lt;/strong&gt; (&lt;em&gt;Supplementary Volume Descriptor&lt;/em&gt;). À la LBA 18, &lt;code&gt;ff CD001 01&lt;/code&gt; est le terminateur. La séquence ISO 9660 de notre image comprend donc, dans l’ordre observé, le descripteur principal à la LBA 16, un descripteur supplémentaire à la LBA 17 et le terminateur à la LBA 18.&lt;/p&gt;

&lt;p&gt;La distinction entre exploration et lecture structurée est essentielle. La boucle Shell continue jusqu’à la LBA 25 pour découvrir les données voisines. Un scanner ISO 9660, lui, doit commencer à la LBA 16, avancer secteur par secteur, contrôler l’identifiant et la version, puis s’arrêter immédiatement au type 255. Il lui faut aussi une borne défensive : une image mal formée ne doit pas provoquer une lecture indéfinie si le terminateur manque.&lt;/p&gt;

&lt;h2&gt;
  
  
  Du descripteur supplémentaire au profil Joliet
&lt;/h2&gt;

&lt;p&gt;Le type 2 ne signifie pas à lui seul « Joliet ». ECMA-119 définit un descripteur supplémentaire générique. La version 1 désigne le descripteur supplémentaire étudié ici ; la version 2 désigne un descripteur amélioré (&lt;em&gt;Enhanced Volume Descriptor&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Le descripteur supplémentaire conserve l’essentiel de la disposition du descripteur principal, mais ajoute les informations nécessaires à l’interprétation de ses champs textuels. Voici sa structure complète :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset relatif&lt;/th&gt;
&lt;th&gt;Taille&lt;/th&gt;
&lt;th&gt;Nom canonique du champ&lt;/th&gt;
&lt;th&gt;Différence ou fonction principale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;valeur 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Standard Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;CD001&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Descriptor Version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1 pour la forme supplémentaire, 2 pour la forme améliorée&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Flags&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;propriétés des séquences d’échappement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;&lt;code&gt;System Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères interprétés selon la forme du descripteur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;d1&lt;/code&gt; dans la forme supplémentaire&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Unused Field&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;octets nuls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Space Size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 32 bits both-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;88&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Escape Sequences&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;désignation des jeux de caractères&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Set Size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 16 bits both-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;124&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Sequence Number&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 16 bits both-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Logical Block Size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 16 bits both-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;132&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Path Table Size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 32 bits both-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;140&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Location of Occurrence of Type L Path Table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;numéro de bloc, little-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;144&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Location of Optional Occurrence of Type L Path Table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;numéro de bloc, little-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;148&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Location of Occurrence of Type M Path Table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;numéro de bloc, big-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;152&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Location of Optional Occurrence of Type M Path Table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;numéro de bloc, big-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;156&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Directory Record for Root Directory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;enregistrement du répertoire racine de cette arborescence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;190&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Set Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;d1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;318&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Publisher Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;a1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;446&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Data Preparer Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;a1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;574&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Application Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;caractères &lt;code&gt;a1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;702&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Copyright File Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;identifiant de fichier en caractères &lt;code&gt;d1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;739&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Abstract File Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;identifiant de fichier en caractères &lt;code&gt;d1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;776&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Bibliographic File Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;identifiant de fichier en caractères &lt;code&gt;d1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;813&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Creation Date and Time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;date et heure décimales&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;830&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Modification Date and Time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;date et heure décimales&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;847&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Expiration Date and Time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;date et heure décimales&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;864&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Volume Effective Date and Time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;date et heure décimales&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;881&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;File Structure Version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;entier 8 bits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;882&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;champ réservé&lt;/td&gt;
&lt;td&gt;octet nul&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;883&lt;/td&gt;
&lt;td&gt;512&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Application Use&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;contenu non spécifié par ECMA-119&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1395&lt;/td&gt;
&lt;td&gt;653&lt;/td&gt;
&lt;td&gt;champ réservé&lt;/td&gt;
&lt;td&gt;octets nuls&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;La section 8.5.6 d’ECMA-119 place donc le champ &lt;code&gt;Escape Sequences&lt;/code&gt; à l’offset relatif 88, sur 32 &lt;strong&gt;octets&lt;/strong&gt;. Ce champ sert à désigner des jeux de caractères ; il ne contient pas nécessairement le nom d’une extension.&lt;/p&gt;

&lt;p&gt;La spécification historique &lt;a href="https://nick-black.com/dankwiki/images/7/73/Microsoft_Joliet_Spec.pdf" rel="noopener noreferrer"&gt;Microsoft Joliet&lt;/a&gt; utilise précisément ce mécanisme pour décrire un ensemble de fichiers dont les noms emploient UCS-2. &lt;strong&gt;UCS-2&lt;/strong&gt; (&lt;em&gt;Universal Character Set, 2-byte form&lt;/em&gt;) est un codage historique fondé sur des unités de code de 16 bits. Nous devons donc examiner le champ avant de classifier le descripteur.&lt;/p&gt;

&lt;p&gt;Son offset absolu est :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;17 × 2 048 + 88 = 34 904 = 0x8858
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cette arithmétique permet notamment d’éviter une erreur de transcription entre les offsets relatifs 87 et 88. Lisons le champ complet :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 32 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;88&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous observons :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00008858: 25 2f 40 00 00 00 00 00 00 00 00 00 00 00 00 00  %/@.............
00008868: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les trois premiers octets, &lt;code&gt;25 2f 40&lt;/code&gt;, représentent &lt;code&gt;%/@&lt;/code&gt; en ASCII ; les 29 octets suivants sont nuls.&lt;/p&gt;

&lt;p&gt;La chaîne documentaire qui donne son sens à cette observation mérite d’être conservée. ISO 2022 définit un mécanisme de désignation des jeux de caractères. ISO 2375 en organise l’enregistrement, et le registre ISO-IR associe des séquences complètes à trois niveaux d’UCS-2 :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Registre&lt;/th&gt;
&lt;th&gt;Jeu de caractères&lt;/th&gt;
&lt;th&gt;Séquence complète enregistrée&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://web.archive.org/web/20201001033018id_/https://www.itscj.ipsj.or.jp/iso-ir/162.pdf" rel="noopener noreferrer"&gt;ISO-IR 162&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;UCS-2 niveau 1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ESC 25 2F 40&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://web.archive.org/web/20201001053549id_/https://www.itscj.ipsj.or.jp/iso-ir/174.pdf" rel="noopener noreferrer"&gt;ISO-IR 174&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;UCS-2 niveau 2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ESC 25 2F 43&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://web.archive.org/web/20201001050724id_/https://www.itscj.ipsj.or.jp/iso-ir/176.pdf" rel="noopener noreferrer"&gt;ISO-IR 176&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;UCS-2 niveau 3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ESC 25 2F 45&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;ESC&lt;/code&gt; désigne ici l’octet de contrôle d’échappement. Ces enregistrements datent de 1992 et 1993, avant la publication de Joliet en 1995. Le champ du descripteur supplémentaire contient les trois octets qui suivent &lt;code&gt;ESC&lt;/code&gt; ; Microsoft n’a donc pas inventé une étiquette privée appelée « Joliet », mais a sélectionné des identifiants de jeux de caractères déjà enregistrés.&lt;/p&gt;

&lt;p&gt;La spécification Joliet associe ces valeurs aux niveaux suivants :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Valeur dans le champ&lt;/th&gt;
&lt;th&gt;Niveau Joliet&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%/@&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%/C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%/E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Dans notre image, &lt;code&gt;%/@&lt;/code&gt; constitue donc un marqueur Joliet de niveau 1. Cette conclusion reste étroite : le marqueur indique comment interpréter le descripteur et l’arborescence qui lui est associée, mais il ne prouve pas que cette arborescence entière respecte Joliet. Il faudrait la parcourir et la valider pour l’affirmer, ce que nous ne ferons pas dans cet article.&lt;/p&gt;

&lt;p&gt;Un lecteur général devrait également définir une politique pour d’autres séquences enregistrées. Notre probe reconnaîtra seulement &lt;code&gt;%/@&lt;/code&gt;, &lt;code&gt;%/C&lt;/code&gt; et &lt;code&gt;%/E&lt;/code&gt;. Une autre valeur restera le champ d’un descripteur supplémentaire reconnu, avec un jeu de caractères non pris en charge ; elle ne sera ni devinée ni silencieusement reclassée.&lt;/p&gt;

&lt;h3&gt;
  
  
  Les descripteurs de reconnaissance voisins
&lt;/h3&gt;

&lt;p&gt;La boucle exploratoire précédente a aussi montré des secteurs dont l’en-tête de sept octets ressemble extérieurement à celui d’ISO 9660, mais relève d’une autre norme. ECMA-167 décrit chaque descripteur de reconnaissance sur un secteur entier selon cette disposition générale :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset relatif&lt;/th&gt;
&lt;th&gt;Taille&lt;/th&gt;
&lt;th&gt;Nom canonique du champ&lt;/th&gt;
&lt;th&gt;Fonction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Structure Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;type de structure ECMA-167&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Standard Identifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;identifiant tel que &lt;code&gt;BEA01&lt;/code&gt;, &lt;code&gt;NSR03&lt;/code&gt; ou &lt;code&gt;TEA01&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Structure Version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;version de la structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;2 041&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Structure Data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;contenu propre au type de descripteur&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Dans notre image, les sept premiers octets donnent :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LBA 19 : 00 42 45 41 30 31 01  → BEA01
LBA 20 : 00 4e 53 52 30 33 01  → NSR03
LBA 21 : 00 54 45 41 30 31 01  → TEA01
LBA 22 : 00 00 00 00 00 00 00  → secteur non reconnu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ces identifiants ne prolongent pas la séquence ISO 9660, terminée à la LBA 18. Ils appartiennent aux descripteurs de reconnaissance définis par &lt;a href="https://dev.ecma-international.org/publications-and-standards/standards/ecma-167/" rel="noopener noreferrer"&gt;ECMA-167&lt;/a&gt;. Leur premier octet est un type de structure ECMA-167, non un type de descripteur ISO 9660, même si les deux en-têtes observés occupent sept octets.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BEA01&lt;/code&gt; ouvre une &lt;em&gt;Extended Area&lt;/em&gt; et &lt;code&gt;TEA01&lt;/code&gt; la ferme. ECMA-167 précise que la &lt;em&gt;Volume Recognition Sequence&lt;/em&gt; se termine au premier secteur qui n’est pas un descripteur valide ; dans cet échantillon, c’est le secteur nul de LBA 22. La forme &lt;code&gt;BEA01&lt;/code&gt; → &lt;code&gt;NSR03&lt;/code&gt; → &lt;code&gt;TEA01&lt;/code&gt; est compatible avec le motif de reconnaissance demandé par UDF (&lt;em&gt;Universal Disk Format&lt;/em&gt;) 2.50, mais &lt;code&gt;NSR03&lt;/code&gt; ne détermine pas à lui seul une révision UDF exacte et ne valide aucun système de fichiers UDF.&lt;/p&gt;

&lt;p&gt;Cette observation n’aide pas à produire nos quatre lignes. Nous n’implémenterons donc aucun parseur UDF dans ce probe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Revenir à la zone système : les indices PlayStation 3
&lt;/h2&gt;

&lt;p&gt;Les seize premiers secteurs sont réservés par ISO 9660 à la zone système, mais ECMA-119 ne définit pas la disposition PlayStation 3 que nous y observons. Aucune spécification publique Sony normative de ces champs n’a été identifiée. Leur interprétation repose sur la convergence d’implémentations indépendantes — notamment &lt;a href="https://github.com/RPCS3/rpcs3/blob/677e13da42a36dc16eef090cc2a7d4d22e48aa5a/rpcs3/Loader/ISO.cpp" rel="noopener noreferrer"&gt;RPCS3&lt;/a&gt;, &lt;a href="https://github.com/13xforever/ps3-disc-dumper/blob/0fc0c8658d83517d8b96efc47ec364b51c76b7b2/IrdLibraryClient/IrdFormat/IsoHeaderParser.cs" rel="noopener noreferrer"&gt;PS3 Disc Dumper&lt;/a&gt; et &lt;a href="https://github.com/aldostools/ps3netsrv/blob/4e2fba86e92f6d59884f0dba29ebc3b4c4ce2e5c/include/VIsoFile.h" rel="noopener noreferrer"&gt;ps3netsrv&lt;/a&gt; — ainsi que sur l’observation de notre image. Ce sont des preuves d’implémentation non normatives, pas une norme Sony.&lt;/p&gt;

&lt;p&gt;Les 512 premiers octets du secteur 1 suivent la disposition observée et corroborée ci-dessous. Le reste de ce secteur est nul dans notre image ; cette dernière propriété reste une observation locale.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset relatif&lt;/th&gt;
&lt;th&gt;Taille&lt;/th&gt;
&lt;th&gt;Contenu ou fonction&lt;/th&gt;
&lt;th&gt;Statut dans cet article&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0x010&lt;/code&gt; (16)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PlayStation3&lt;/code&gt; suivi de quatre octets nuls&lt;/td&gt;
&lt;td&gt;reconnu par le probe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x010&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0x020&lt;/code&gt; (32)&lt;/td&gt;
&lt;td&gt;identifiant produit complété par des espaces&lt;/td&gt;
&lt;td&gt;reconnu par le probe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x030&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0x010&lt;/code&gt; (16)&lt;/td&gt;
&lt;td&gt;octets nuls&lt;/td&gt;
&lt;td&gt;observé, non utilisé&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x040&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0x1b0&lt;/code&gt; (432)&lt;/td&gt;
&lt;td&gt;informations de disque dont la sémantique n’est pas établie ici&lt;/td&gt;
&lt;td&gt;opaque&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x1f0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0x010&lt;/code&gt; (16)&lt;/td&gt;
&lt;td&gt;valeur opaque décrite comme un hachage par &lt;code&gt;ps3netsrv&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;opaque&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x200&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0x600&lt;/code&gt; (1 536)&lt;/td&gt;
&lt;td&gt;fin du secteur, nulle dans l’image étudiée&lt;/td&gt;
&lt;td&gt;observation locale&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Le marqueur de plateforme
&lt;/h3&gt;

&lt;p&gt;À la LBA 1, nous lisons d’abord un champ de 16 octets :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 16 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La sortie réelle est :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00000800: 50 6c 61 79 53 74 61 74 69 6f 6e 33 00 00 00 00  PlayStation3....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les douze premiers octets codent &lt;code&gt;PlayStation3&lt;/code&gt; en ASCII ; quatre octets nuls complètent le champ. Nous parlons d’un champ de 16 octets, non d’un texte arbitraire de 16 caractères.&lt;/p&gt;

&lt;h3&gt;
  
  
  L’identifiant produit
&lt;/h3&gt;

&lt;p&gt;Le champ adjacent commence 16 octets plus loin et en occupe 32 :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 32 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous observons :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00000810: 42 4c 45 53 2d 30 30 39 33 32 20 20 20 20 20 20  BLES-00932
00000820: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les dix premiers octets donnent &lt;code&gt;BLES-00932&lt;/code&gt; ; vingt-deux espaces complètent le champ. Notre reconnaissance minimale exigera le marqueur &lt;code&gt;PlayStation3&lt;/code&gt; complet, puis retirera seulement les espaces terminaux de l’identifiant produit. Cette combinaison suffit à la ligne que nous voulons rapporter, mais ne valide pas toutes les structures propres à un disque PlayStation 3.&lt;/p&gt;

&lt;h3&gt;
  
  
  La table de plages du secteur 0
&lt;/h3&gt;

&lt;p&gt;Le début du secteur 0 contient une autre structure corroborée par les implémentations citées. Avant de lire ses valeurs, nous pouvons en représenter la disposition générale :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset relatif&lt;/th&gt;
&lt;th&gt;Taille&lt;/th&gt;
&lt;th&gt;Contenu ou fonction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;nombre d’enregistrements, entier non signé 32 bits big-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x004&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;champ réservé, attendu à zéro&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x008 + 8 × i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;LBA de début incluse de l’enregistrement &lt;code&gt;i&lt;/code&gt;, big-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x00c + 8 × i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;LBA de fin incluse de l’enregistrement &lt;code&gt;i&lt;/code&gt;, big-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;0x008 + 8 × count&lt;/code&gt; à &lt;code&gt;0x7ff&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;variable&lt;/td&gt;
&lt;td&gt;reste du secteur, hors de la table décrite&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Les quatre premiers octets forment donc le compteur ; les quatre suivants sont réservés et attendus à zéro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 4 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 4 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les sorties observées sont :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00000000: 00 00 00 03                                      ....
00000004: 00 00 00 00                                      ....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;00 00 00 03&lt;/code&gt;, lu en big-endian, vaut 3 : trois enregistrements suivent. Ce nombre n’est pas le nombre de blocs du volume ; ce dernier reste &lt;code&gt;0x004327a0&lt;/code&gt;. Chaque enregistrement occupe huit octets et contient deux entiers big-endian de 32 bits : une LBA de début et une LBA de fin &lt;strong&gt;incluse&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;n &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;0 2&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Plage &lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"LBA start: "&lt;/span&gt;
    xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 4 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"LBA stop : "&lt;/span&gt;
    xxd &lt;span class="nt"&gt;-g&lt;/span&gt; 1 &lt;span class="nt"&gt;-l&lt;/span&gt; 4 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; SECTOR &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous obtenons :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plage 1
LBA start: 00000008: 00 00 00 00                                      ....
LBA stop : 0000000c: 00 00 45 bf                                      ..E.

Plage 2
LBA start: 00000010: 00 01 04 00                                      ....
LBA stop : 00000014: 00 01 08 ff                                      ....

Plage 3
LBA start: 00000018: 00 41 27 80                                      .A'.
LBA stop : 0000001c: 00 43 27 9f                                      .C'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La formule big-endian donnée plus haut s’applique à chaque groupe de quatre octets. Par exemple, &lt;code&gt;00 01 04 00&lt;/code&gt; devient &lt;code&gt;0x00010400&lt;/code&gt;. Puisque les bornes sont inclusives, la longueur d’une plage est &lt;code&gt;fin - début + 1&lt;/code&gt;. Les trois &lt;strong&gt;plages non protégées&lt;/strong&gt; observées sont donc :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plage&lt;/th&gt;
&lt;th&gt;Début inclus&lt;/th&gt;
&lt;th&gt;Fin incluse&lt;/th&gt;
&lt;th&gt;Longueur en secteurs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x00000000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x000045bf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x000045c0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x00010400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x000108ff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x00000500&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x00412780&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x0043279f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x00020020&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Elles sont non inversées, strictement ordonnées, sans chevauchement et contenues dans le volume. Comme &lt;code&gt;Volume Space Size&lt;/code&gt; est un &lt;strong&gt;compte&lt;/strong&gt; de &lt;code&gt;0x004327a0&lt;/code&gt; blocs, les LBA valides vont de zéro à &lt;code&gt;0x0043279f&lt;/code&gt; ; la dernière borne incluse vaut exactement &lt;code&gt;0x004327a0 - 1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Les intervalles complémentaires entre ces plages sont les &lt;strong&gt;intervalles protégés dérivés&lt;/strong&gt; :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Intervalle&lt;/th&gt;
&lt;th&gt;Début inclus&lt;/th&gt;
&lt;th&gt;Fin incluse&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x000045c0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x000103ff&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x00010900&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x0041277f&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Cette dérivation décrit la carte de protection prévue pour le disque original. Elle ne permet pas de conclure que les octets de l’image locale sont actuellement chiffrés ou déjà déchiffrés. Comme notre probe ne rapporte aucune plage et n’effectue aucun déchiffrement, cette table reste une observation et n’entre pas dans le code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproduire les lectures directement dans GHCi
&lt;/h2&gt;

&lt;p&gt;Nous avons maintenant une suite précise de règles à transcrire. &lt;strong&gt;GHCi&lt;/strong&gt; est l’interpréteur interactif de Glasgow Haskell Compiler : il permet de saisir des définitions Haskell et d’en voir immédiatement le résultat. Nous allons y construire un prototype direct, sans infrastructure générale de décodage binaire.&lt;/p&gt;

&lt;p&gt;Depuis le même terminal, nous rendons le chemin accessible au processus, puis lançons GHCi avec le paquet &lt;code&gt;bytestring&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;IMAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IMAGE&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.iso&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
ghci &lt;span class="nt"&gt;-package&lt;/span&gt; bytestring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;L’invite ressemble à :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ghci&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Un &lt;code&gt;ByteString&lt;/code&gt; est une suite compacte d’octets. Nous utiliserons sa variante stricte parce que chacune de nos lectures est petite et bornée. Les interfaces employées sont documentées dans &lt;a href="https://hackage.haskell.org/package/base/docs/System-IO.html" rel="noopener noreferrer"&gt;&lt;code&gt;System.IO&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://hackage.haskell.org/package/bytestring/docs/Data-ByteString.html" rel="noopener noreferrer"&gt;&lt;code&gt;Data.ByteString&lt;/code&gt;&lt;/a&gt; et &lt;a href="https://hackage.haskell.org/package/base/docs/Data-Word.html" rel="noopener noreferrer"&gt;&lt;code&gt;Data.Word&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Saisie multiligne dans GHCi.&lt;/strong&gt; Les blocs qui suivent sont présentés comme du code Haskell ordinaire, sans commandes propres à l’interpréteur. Pour saisir une définition multiligne directement dans GHCi, commencez par entrer &lt;code&gt;:{&lt;/code&gt; sur une ligne isolée, saisissez ou collez la définition, puis terminez par &lt;code&gt;:}&lt;/code&gt;, également sur une ligne isolée. Ces deux commandes sont volontairement omises des blocs afin de ne pas les confondre avec la syntaxe du langage Haskell.&lt;/p&gt;

&lt;h3&gt;
  
  
  Octets bruts, puis décodage endian
&lt;/h3&gt;

&lt;p&gt;Commençons par les imports communs :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Control.Monad&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;unless&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;when&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Bits&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Bits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;shiftL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.|.&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Data.ByteString&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;BS&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Data.ByteString.Char8&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;BSC&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Word&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Word8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Word16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Word32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;System.Environment&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getEnv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;IOMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ReadMode&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;SeekMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;AbsoluteSeek&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;hFileSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;hSeek&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;withBinaryFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Avant toute entrée-sortie, reprenons quatre octets synthétiques. Leur type ne leur attribue encore ni signification ni ordre :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rawBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x03&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt; &lt;span class="n"&gt;rawBytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GHCi affiche :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0,0,0,3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;L’endianness n’est pas une propriété du &lt;code&gt;ByteString&lt;/code&gt; ni un mode de lecture du fichier. C’est une règle du champ que nous sommes en train de décoder. Nous définissons deux transformations privées :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;decodeBE&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Bits&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Num&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;decodeBE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldl'&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shiftL&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;.|.&lt;/span&gt; &lt;span class="n"&gt;fromIntegral&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="n"&gt;decodeLE&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Bits&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Num&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;decodeLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldr'&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shiftL&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;.|.&lt;/span&gt; &lt;span class="n"&gt;fromIntegral&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La même suite brute donne des valeurs différentes selon l’interprétation :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;decodeBE&lt;/span&gt; &lt;span class="n"&gt;rawBytes&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Word32&lt;/span&gt;
&lt;span class="n"&gt;decodeLE&lt;/span&gt; &lt;span class="n"&gt;rawBytes&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Word32&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Résultat :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3
50331648
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;50331648&lt;/code&gt; vaut &lt;code&gt;0x03000000&lt;/code&gt;. Le format, et non une préférence du programmeur, détermine quel décodeur convient. Ces fonctions n’imposent pas elles-mêmes une largeur ; dans ce prototype, cette garantie appartient à la frontière de lecture qui les précède.&lt;/p&gt;

&lt;h3&gt;
  
  
  Une lecture exacte et bornée
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;BS.hGet&lt;/code&gt; peut renvoyer moins d’octets que demandé si la fin du fichier survient. Nous devons contrôler la longueur avant tout &lt;code&gt;BS.index&lt;/code&gt; ou décodage. Les offsets restent des &lt;code&gt;Integer&lt;/code&gt;, afin de ne pas limiter artificiellement l’adressage aux fichiers de moins de 4 Gio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;sectorSize&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Integer&lt;/span&gt;
&lt;span class="n"&gt;sectorSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;

&lt;span class="n"&gt;readExactlyAt&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Handle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Integer&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt;
&lt;span class="n"&gt;readExactlyAt&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ioError&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userError&lt;/span&gt; &lt;span class="s"&gt;"negative read offset"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ioError&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userError&lt;/span&gt; &lt;span class="s"&gt;"negative read width"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;hSeek&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="kt"&gt;AbsoluteSeek&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;
        &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hGet&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;
        &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;
            &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;
            &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="n"&gt;ioError&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userError&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"short read at offset "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;
                        &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;": expected "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;
                        &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;" bytes, got "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ReadMode&lt;/code&gt; exprime l’intention de lecture seule. &lt;code&gt;withBinaryFile&lt;/code&gt; referme le handle même si une exception survient. Vérifions cette frontière avec les sept octets déjà observés :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;imageFile&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;getEnv&lt;/span&gt; &lt;span class="s"&gt;"IMAGE"&lt;/span&gt;

&lt;span class="n"&gt;headerBytes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;withBinaryFile&lt;/span&gt; &lt;span class="n"&gt;imageFile&lt;/span&gt; &lt;span class="kt"&gt;ReadMode&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;readExactlyAt&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sectorSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;

&lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="n"&gt;headerBytes&lt;/span&gt;
&lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt; &lt;span class="n"&gt;headerBytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous retrouvons :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;7
[1,67,68,48,48,49,1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les décimaux &lt;code&gt;67 68 48 48 49&lt;/code&gt; sont les codes ASCII de &lt;code&gt;CD001&lt;/code&gt;. Si GHCi affiche parfois un &lt;code&gt;ByteString&lt;/code&gt; textuel sous la forme &lt;code&gt;"\SOHCD001\SOH"&lt;/code&gt;, &lt;code&gt;SOH&lt;/code&gt; n’est pas un octet ajouté : c’est le nom d’affichage du caractère de contrôle &lt;code&gt;0x01&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Décoder les champs utiles du descripteur principal
&lt;/h3&gt;

&lt;p&gt;Nous donnons maintenant un type aux trois composants de l’en-tête, puis un type aux trois informations ISO que notre lecture conservera :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;DescriptorHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DescriptorHeader&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;headerType&lt;/span&gt;       &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Word8&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headerIdentifier&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headerVersion&lt;/span&gt;    &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Word8&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;IsoInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;IsoInfo&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;isoVolumeIdentifier&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isoVolumeSpaceSize&lt;/span&gt;  &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Word32&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isoLogicalBlockSize&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Word16&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;decodeDescriptorHeader&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;DescriptorHeader&lt;/span&gt;
&lt;span class="n"&gt;decodeDescriptorHeader&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;DescriptorHeader&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;headerType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headerIdentifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headerVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;decodeDescriptorHeader&lt;/code&gt; emploie &lt;code&gt;BS.index&lt;/code&gt;, qui serait partiel sur une entrée trop courte. Il reste privé et ne reçoit ici que des données dont la largeur a déjà été vérifiée par &lt;code&gt;readExactlyAt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La fonction suivante lit exactement le secteur de 2 048 octets à la LBA 16, contrôle son en-tête, découpe les trois champs, décode séparément les deux copies numériques et vérifie leur égalité. Pour le contrôle de cohérence avec le fichier hôte, elle refuse seulement une longueur insuffisante ; elle accepte d’éventuelles données terminales.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;readPrimaryVolumeDescriptor&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Handle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="kt"&gt;IsoInfo&lt;/span&gt;
&lt;span class="n"&gt;readPrimaryVolumeDescriptor&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;descriptor&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;readExactlyAt&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sectorSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;
    &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decodeDescriptorHeader&lt;/span&gt; &lt;span class="n"&gt;descriptor&lt;/span&gt;

    &lt;span class="n"&gt;unless&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerType&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;headerIdentifier&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;BSC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="s"&gt;"CD001"&lt;/span&gt;
            &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;headerVersion&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioError&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userError&lt;/span&gt; &lt;span class="s"&gt;"no supported Primary Volume Descriptor at LBA 16"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;volumeField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="n"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;spaceField&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="n"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;blockField&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt; &lt;span class="n"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spaceLEBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spaceBEBytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitAt&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="n"&gt;spaceField&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blockLEBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blockBEBytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitAt&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;blockField&lt;/span&gt;

        &lt;span class="n"&gt;spaceLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decodeLE&lt;/span&gt; &lt;span class="n"&gt;spaceLEBytes&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Word32&lt;/span&gt;
        &lt;span class="n"&gt;spaceBE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decodeBE&lt;/span&gt; &lt;span class="n"&gt;spaceBEBytes&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Word32&lt;/span&gt;
        &lt;span class="n"&gt;blockLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decodeLE&lt;/span&gt; &lt;span class="n"&gt;blockLEBytes&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Word16&lt;/span&gt;
        &lt;span class="n"&gt;blockBE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decodeBE&lt;/span&gt; &lt;span class="n"&gt;blockBEBytes&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Word16&lt;/span&gt;

    &lt;span class="n"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spaceLE&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;spaceBE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioError&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userError&lt;/span&gt; &lt;span class="s"&gt;"inconsistent Volume Space Size copies"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blockLE&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;blockBE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioError&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userError&lt;/span&gt; &lt;span class="s"&gt;"inconsistent Logical Block Size copies"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blockLE&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioError&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userError&lt;/span&gt; &lt;span class="s"&gt;"zero Logical Block Size"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;hostSize&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;hFileSize&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;
    &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;declaredSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;toInteger&lt;/span&gt; &lt;span class="n"&gt;spaceLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;toInteger&lt;/span&gt; &lt;span class="n"&gt;blockLE&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hostSize&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;declaredSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioError&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userError&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"truncated image: declared "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="n"&gt;declaredSize&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;" bytes, host file has "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="n"&gt;hostSize&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="n"&gt;pure&lt;/span&gt;
        &lt;span class="kt"&gt;IsoInfo&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;isoVolumeIdentifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BSC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dropWhileEnd&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;volumeField&lt;/span&gt;
            &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isoVolumeSpaceSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spaceLE&lt;/span&gt;
            &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isoLogicalBlockSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;blockLE&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exécutons ce bloc sur l’image :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;isoInfo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;withBinaryFile&lt;/span&gt; &lt;span class="n"&gt;imageFile&lt;/span&gt; &lt;span class="kt"&gt;ReadMode&lt;/span&gt; &lt;span class="n"&gt;readPrimaryVolumeDescriptor&lt;/span&gt;
&lt;span class="n"&gt;isoInfo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La sortie importante rassemble les valeurs reconstruites dans le Shell :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IsoInfo {isoVolumeIdentifier = "PS3VOLUME", isoVolumeSpaceSize = 4401056, isoLogicalBlockSize = 2048}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ce résultat signifie que les contrôles explicitement codés ont réussi. Il ne prétend pas valider les nombreux champs du descripteur que nous n’avons pas lus.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parcourir directement et sans débordement la séquence ISO 9660
&lt;/h3&gt;

&lt;p&gt;Nous généralisons maintenant la lecture des sept octets d’en-tête à une LBA quelconque. Le scanner part de 16, exige &lt;code&gt;CD001&lt;/code&gt; et la version 1 à chaque étape, inclut le terminateur dans son résultat et s’y arrête. La limite de 64 descripteurs est un choix défensif du probe : elle transforme l’absence de terminateur proche en erreur au lieu de poursuivre sans borne.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;readDescriptorHeader&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Handle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Integer&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="kt"&gt;DescriptorHeader&lt;/span&gt;
&lt;span class="n"&gt;readDescriptorHeader&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="n"&gt;lba&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;decodeDescriptorHeader&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;readExactlyAt&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lba&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sectorSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;

&lt;span class="n"&gt;scanIsoSequence&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Handle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;DescriptorHeader&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;scanIsoSequence&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;
  &lt;span class="kr"&gt;where&lt;/span&gt;
    &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="n"&gt;lba&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="n"&gt;accumulated&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="n"&gt;ioError&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userError&lt;/span&gt; &lt;span class="s"&gt;"ISO descriptor scan limit reached"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
            &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;readDescriptorHeader&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="n"&gt;lba&lt;/span&gt;
            &lt;span class="n"&gt;unless&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerIdentifier&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;BSC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="s"&gt;"CD001"&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;headerVersion&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioError&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userError&lt;/span&gt;
                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid ISO descriptor header at LBA "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="n"&gt;lba&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

            &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;located&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lba&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;headerType&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;
                &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;located&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;accumulated&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lba&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;located&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;accumulated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous n’avons plus à connaître d’avance le nombre de descripteurs :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;descriptors&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;withBinaryFile&lt;/span&gt; &lt;span class="n"&gt;imageFile&lt;/span&gt; &lt;span class="kt"&gt;ReadMode&lt;/span&gt; &lt;span class="n"&gt;scanIsoSequence&lt;/span&gt;
&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lba&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lba&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headerType&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;descriptors&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous obtenons :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[(16,1),(17,2),(18,255)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Le secteur 19 n’est jamais consommé par ce scanner ISO 9660. C’est exactement la différence observée entre la boucle Shell exploratoire et la règle du format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Examiner tous les descripteurs supplémentaires et classifier Joliet
&lt;/h3&gt;

&lt;p&gt;ECMA-119 autorise zéro ou plusieurs descripteurs supplémentaires. Sélectionner seulement le premier serait donc une hypothèse injustifiée. Nous lisons le champ &lt;code&gt;Escape Sequences&lt;/code&gt; complet de chacun d’eux et conservons aussi les valeurs que notre petit probe ne sait pas classifier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel1&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel2&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel3&lt;/span&gt;
    &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;SupplementaryFinding&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;JolietFinding&lt;/span&gt; &lt;span class="kt"&gt;Integer&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;UnsupportedCharacterSet&lt;/span&gt; &lt;span class="kt"&gt;Integer&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt;
    &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;classifySupplementary&lt;/span&gt;
    &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Integer&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;SupplementaryFinding&lt;/span&gt;
&lt;span class="n"&gt;classifySupplementary&lt;/span&gt; &lt;span class="n"&gt;lba&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;
        &lt;span class="n"&gt;zeroPadding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;level&lt;/span&gt;
            &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;BSC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="s"&gt;"%/@"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel1&lt;/span&gt;
            &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;BSC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="s"&gt;"%/C"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel2&lt;/span&gt;
            &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;BSC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="s"&gt;"%/E"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel3&lt;/span&gt;
            &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt;                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt;
    &lt;span class="kr"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zeroPadding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;jolietLevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;JolietFinding&lt;/span&gt; &lt;span class="n"&gt;lba&lt;/span&gt; &lt;span class="n"&gt;jolietLevel&lt;/span&gt;
        &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;UnsupportedCharacterSet&lt;/span&gt; &lt;span class="n"&gt;lba&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;

&lt;span class="n"&gt;readSupplementaryFindings&lt;/span&gt;
    &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Handle&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;DescriptorHeader&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;SupplementaryFinding&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;readSupplementaryFindings&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="n"&gt;allDescriptors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;mapM&lt;/span&gt; &lt;span class="n"&gt;readOne&lt;/span&gt; &lt;span class="n"&gt;supplementaryLbas&lt;/span&gt;
  &lt;span class="kr"&gt;where&lt;/span&gt;
    &lt;span class="n"&gt;supplementaryLbas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;lba&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lba&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;allDescriptors&lt;/span&gt;
        &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headerType&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;readOne&lt;/span&gt; &lt;span class="n"&gt;lba&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;readExactlyAt&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lba&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sectorSize&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;
        &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classifySupplementary&lt;/span&gt; &lt;span class="n"&gt;lba&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Appliquons cette lecture à tous les candidats trouvés :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;supplementaryFindings&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;withBinaryFile&lt;/span&gt; &lt;span class="n"&gt;imageFile&lt;/span&gt; &lt;span class="kt"&gt;ReadMode&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;readSupplementaryFindings&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="n"&gt;descriptors&lt;/span&gt;

&lt;span class="n"&gt;supplementaryFindings&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La sortie situe le résultat autant qu’elle le classe :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JolietFinding 17 JolietLevel1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Le constructeur &lt;code&gt;UnsupportedCharacterSet&lt;/code&gt; évite de transformer une séquence inconnue en absence de descripteur. Quant à &lt;code&gt;JolietFinding&lt;/code&gt;, il atteste seulement le marqueur, jamais la conformité de l’arborescence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reconnaître le minimum propre à la PlayStation 3
&lt;/h3&gt;

&lt;p&gt;Pour produire l’identifiant produit, 48 octets suffisent : le champ marqueur de 16 octets, puis le champ produit de 32 octets. Nous ne faisons pas dépendre cette reconnaissance de la table de plages, dont notre sortie n’a pas besoin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;readPs3ProductId&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Handle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;readPs3ProductId&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;readExactlyAt&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="n"&gt;sectorSize&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;
    &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;marker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;
        &lt;span class="n"&gt;productField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;
        &lt;span class="n"&gt;expectedMarker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="kt"&gt;BSC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="s"&gt;"PlayStation3"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replicate&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="n"&gt;pure&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;marker&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;expectedMarker&lt;/span&gt;
            &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BSC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dropWhileEnd&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;productField&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exécutons-la :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;ps3ProductId&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;withBinaryFile&lt;/span&gt; &lt;span class="n"&gt;imageFile&lt;/span&gt; &lt;span class="kt"&gt;ReadMode&lt;/span&gt; &lt;span class="n"&gt;readPs3ProductId&lt;/span&gt;
&lt;span class="n"&gt;ps3ProductId&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous retrouvons :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Just "BLES-00932"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Nothing&lt;/code&gt; signifierait seulement que ce marqueur d’implémentation n’a pas été reconnu. Cela ne suffirait pas à classifier universellement l’entrée comme « non-PlayStation 3 ».&lt;/p&gt;

&lt;h3&gt;
  
  
  Agréger les observations et les rendre dans un ordre stable
&lt;/h3&gt;

&lt;p&gt;Il reste à ouvrir l’image une fois, à effectuer les lectures précédentes par offsets absolus, puis à construire les lignes reconnues. La structure finale conserve les descripteurs supplémentaires non pris en charge, même si le rendu demandé n’émet que les niveaux Joliet reconnus.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;ProbeResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ProbeResult&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;resultPs3ProductId&lt;/span&gt;       &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;BS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultIso9660&lt;/span&gt;            &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;IsoInfo&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultSupplementary&lt;/span&gt;      &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;SupplementaryFinding&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;probe&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="kt"&gt;ProbeResult&lt;/span&gt;
&lt;span class="n"&gt;probe&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;withBinaryFile&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;ReadMode&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;isoDescriptors&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;scanIsoSequence&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;
        &lt;span class="n"&gt;recognizedIso&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;readPrimaryVolumeDescriptor&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;
        &lt;span class="n"&gt;supplementary&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;
            &lt;span class="n"&gt;readSupplementaryFindings&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="n"&gt;isoDescriptors&lt;/span&gt;
        &lt;span class="n"&gt;productId&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;readPs3ProductId&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;
        &lt;span class="n"&gt;pure&lt;/span&gt;
            &lt;span class="kt"&gt;ProbeResult&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;resultPs3ProductId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;
                &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultIso9660&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recognizedIso&lt;/span&gt;
                &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultSupplementary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;supplementary&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;renderJolietLevel&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="n"&gt;renderJolietLevel&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;
&lt;span class="n"&gt;renderJolietLevel&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2"&lt;/span&gt;
&lt;span class="n"&gt;renderJolietLevel&lt;/span&gt; &lt;span class="kt"&gt;JolietLevel3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"3"&lt;/span&gt;

&lt;span class="n"&gt;renderProbeResult&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;ProbeResult&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;renderProbeResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;maybe&lt;/span&gt;
        &lt;span class="kt"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;productId&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ps3.product-id="&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BSC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultPs3ProductId&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;"iso9660.volume-id="&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BSC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isoVolumeIdentifier&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultIso9660&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
       &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"iso9660.logical-block-size="&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isoLogicalBlockSize&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultIso9660&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
       &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;"joliet.level="&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;renderJolietLevel&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;
       &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;JolietFinding&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;resultSupplementary&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
       &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lançons enfin le probe et son rendu :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;probe&lt;/span&gt; &lt;span class="n"&gt;imageFile&lt;/span&gt;
&lt;span class="n"&gt;mapM_&lt;/span&gt; &lt;span class="n"&gt;putStrLn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderProbeResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La sortie est exactement :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ps3.product-id=BLES-00932
iso9660.volume-id=PS3VOLUME
iso9660.logical-block-size=2048
joliet.level=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  La portée exacte de ces quatre lignes
&lt;/h2&gt;

&lt;p&gt;La première ligne repose sur un marqueur et une disposition de champs corroborés par plusieurs implémentations PlayStation 3 non normatives. Les deuxième et troisième lignes proviennent de champs précis du descripteur principal de volume ISO 9660, après contrôle de l’en-tête, des deux copies endian et de la taille minimale du fichier. La quatrième rapporte un marqueur Joliet de niveau 1 trouvé dans l’unique descripteur supplémentaire observé, après parcours borné de toute la séquence ISO 9660.&lt;/p&gt;

&lt;p&gt;Elles ne prouvent ni la conformité complète à ISO 9660 ou Joliet, ni la validité des répertoires et des noms UCS-2, ni une révision UDF, ni l’état de chiffrement de l’image. Elles n’autorisent encore aucun parcours de répertoire, aucune extraction, aucun déchiffrement et aucune écriture. Elles disent seulement que quatre informations ont été reconnues selon les règles et les limites que nous avons rendues explicites.&lt;/p&gt;

&lt;p&gt;Notre code direct révèle enfin une répétition concrète : plusieurs lectures fixes reviennent à combiner un offset, une largeur et une opération de décodage, puis à interpréter le résultat. Un deuxième article pourra partir de cette duplication observée — non d’une abstraction décidée à l’avance — pour étudier comment décrire ces opérations et leur donner plusieurs interprétations plus générales.&lt;/p&gt;

</description>
      <category>haskell</category>
      <category>modding</category>
      <category>reverseengineering</category>
      <category>french</category>
    </item>
  </channel>
</rss>
