iso9660: Refactor Open() to ease extensions
diff --git a/src/filo-fs-iso9660.adb b/src/filo-fs-iso9660.adb
index fd12854..ad462f0 100644
--- a/src/filo-fs-iso9660.adb
+++ b/src/filo-fs-iso9660.adb
@@ -160,25 +160,84 @@
    is
       File_Name_Max : constant := 255;
 
-      function Str_Buf_Equal (Str : String; Buf : Buffer_Type) return Boolean
+      procedure Match_ISO_Name
+        (ISO_Name_Length   : in     Natural;
+         Record_Dir_Pos    : in     File_Offset;
+         Success           : in out Boolean)
       with
-         Pre => Str'Length <= Buf'Length
+         Post => State.Static = State.Static'Old
       is
+         function Upper_Case_Equal (Str : String; Buf : Buffer_Type) return Boolean
+         with
+            Pre => Str'Length <= Buf'Length
+         is
+         begin
+            for I in Str'Range loop
+               declare
+                  Chr : constant Unsigned_8 :=
+                     (if 'a' <= Str (I) and Str (I) <= 'z' then
+                        Character'Pos (Str (I)) - Character'Pos ('a') + Character'Pos ('A')
+                      else Character'Pos (Str (I)));
+               begin
+                  if Chr /= Buf (Buf'First + (I - Str'First)) then
+                     return False;
+                  end if;
+               end;
+            end loop;
+            return True;
+         end Upper_Case_Equal;
+
+         Dir_Pos : File_Offset := Record_Dir_Pos;
+         ISO_Name : Buffer_Type (0 .. ISO_Name_Length - 1);
+         Name_Len : Natural;
       begin
-         for I in Str'Range loop
-            declare
-               Chr : constant Unsigned_8 :=
-                  (if 'a' <= Str (I) and Str (I) <= 'z' then
-                     Character'Pos (Str (I)) - Character'Pos ('a') + Character'Pos ('A')
-                   else Character'Pos (Str (I)));
-            begin
-               if Chr /= Buf (Buf'First + (I - Str'First)) then
-                  return False;
-               end if;
-            end;
-         end loop;
-         return True;
-      end Str_Buf_Equal;
+         -- Check if length could match.
+         -- First for the weird `.' and `..' encoding,
+         -- then for regular file names + `.' and file version `;1'.
+         if not (ISO_Name_Length = 1 and File_Name'Length <= 2) and
+            ISO_Name_Length not in File_Name'Length .. File_Name'Length + 3
+         then
+            return;
+         end if;
+
+         pragma Warnings
+           (GNATprove, Off, """Dir_Pos"" is set*but not used",
+            Reason => "This is the last part of the record we care about.");
+         Read
+           (State    => State,
+            File_Pos => Dir_Pos,
+            Buf      => ISO_Name,
+            Len      => Name_Len);
+         if Name_Len /= ISO_Name_Length then
+            return;
+         end if;
+         pragma Warnings (GNATprove, On, """Dir_Pos"" is set*but not used");
+
+         if (Name_Len = 1 and ISO_Name (0) = 16#00# and File_Name = ".") or
+            (Name_Len = 1 and ISO_Name (0) = 16#01# and File_Name = "..")
+         then
+            Success := True;
+            return;
+         end if;
+
+         -- Ignore file version `;1'
+         if Name_Len >= File_Name'Length + 2 and
+            ISO_Name (Name_Len - 2) = Character'Pos (';') and
+            ISO_Name (Name_Len - 1) = Character'Pos ('1')
+         then
+            Name_Len := Name_Len - 2;
+         end if;
+
+         -- Ignore trailing `.'
+         if Name_Len >= File_Name'Length + 1 and
+            ISO_Name (Name_Len - 1) = Character'Pos ('.')
+         then
+            Name_Len := Name_Len - 1;
+         end if;
+
+         Success := Name_Len = File_Name'Length and then
+                     Upper_Case_Equal (File_Name, ISO_Name);
+      end Match_ISO_Name;
 
       Found_Inode : Inode_Index;
       Dir_Pos : File_Length;
@@ -222,81 +281,54 @@
            (FSBlock_Index (Dir_Pos mod FSBlock_Size) <= Directory_Record_Offset'Last);
 
          declare
-            Dir_Rec : Directory_Record;
-            Dir_Rec_Name : Buffer_Type (0 .. File_Name_Max - 1);
+            Dir_Rec_Head : Directory_Record;
             Record_Dir_Pos : File_Offset := Dir_Pos;
             Len : Natural;
          begin
             Read
               (State    => State,
                File_Pos => Record_Dir_Pos,
-               Buf      => Dir_Rec,
+               Buf      => Dir_Rec_Head,
                Len      => Len);
-            if Len < Dir_Rec'Length then
+            if Len /= Dir_Rec_Head'Length then
                return;
             end if;
 
-            if File_Name'Length <= Natural (Dir_Rec (32)) and
-               Natural (Dir_Rec (32)) <= File_Name'Length + 3
-            then
-               pragma Warnings
-                 (GNATprove, Off, """Record_Dir_Pos"" is set*but not used",
-                  Reason => "We only care about intermedidate values.");
-               Read
-                 (State    => State,
-                  File_Pos => Record_Dir_Pos,
-                  Buf      => Dir_Rec_Name (0 .. Natural (Dir_Rec (32) - 1)),
-                  Len      => Len);
-               pragma Warnings (GNATprove, On, """Record_Dir_Pos"" is set*but not used");
-
-               if (Len = 1 and Dir_Rec_Name (0) = 16#00# and File_Name = ".") or
-                  (Len = 1 and Dir_Rec_Name (0) = 16#01# and File_Name = "..")
-               then
-                  Success := True;
-               else
-                  -- Remove file version
-                  if Len >= File_Name'Length + 2 and
-                     Dir_Rec_Name (Len - 2) = Character'Pos (';') and
-                     Dir_Rec_Name (Len - 1) = Character'Pos ('1')
-                  then
-                     Len := Len - 2;
-                  end if;
-
-                  -- Remove trailing .
-                  if Len >= File_Name'Length + 1 and
-                     Dir_Rec_Name (Len - 1) = Character'Pos ('.')
-                  then
-                     Len := Len - 1;
-                  end if;
-
-                  Success := Len = File_Name'Length and then
-                              Str_Buf_Equal (File_Name, Dir_Rec_Name);
-               end if;
-               if Success then
-                  Found_Inode :=
-                    (Block => FSBlock (Dir_Pos / FSBlock_Size) + State.Inode.Extents (0).Start,
-                     Offset => FSBlock_Index (Dir_Pos mod FSBlock_Size));
-                  exit;
-               end if;
-            end if;
-
             declare
-               Dir_Rec_Length : constant File_Length := File_Length (Dir_Rec (0));
-               Block_Gap : constant File_Length := FSBlock_Size - (Dir_Pos mod FSBlock_Size);
+               Dir_Rec_Length : constant Natural := Natural (Dir_Rec_Head (0));
+               Dir_Rec_Name_Length : constant Natural := Natural (Dir_Rec_Head (32));
             begin
-               -- End of block?
-               if Dir_Rec_Length = Block_Gap or Dir_Rec_Length = 0 then
-                  if Unsigned_64 (Dir_Pos) >= Unsigned_64 (State.Inode.Size) - Unsigned_64 (Block_Gap) then
+               if Dir_Rec_Length /= 0 then
+
+                  if Unsigned_64 (Dir_Pos) > Unsigned_64 (State.Inode.Size) - Unsigned_64 (Dir_Rec_Length) or
+                     Dir_Rec_Name_Length > Dir_Rec_Length - Dir_Rec_Head'Length
+                  then
                      return;
-                  else
-                     Dir_Pos := Dir_Pos + Block_Gap;
                   end if;
+
+
+                  Match_ISO_Name (Dir_Rec_Name_Length, Record_Dir_Pos, Success);
+
+                  if Success then
+                     Found_Inode :=
+                       (Block => FSBlock (Dir_Pos / FSBlock_Size) + State.Inode.Extents (0).Start,
+                        Offset => FSBlock_Index (Dir_Pos mod FSBlock_Size));
+                     exit;
+                  end if;
+
+                  Dir_Pos := Dir_Pos + File_Length (Dir_Rec_Length);
+
                else
-                  if Unsigned_64 (Dir_Pos) > Unsigned_64 (State.Inode.Size) - Unsigned_64 (Dir_Rec_Length) then
-                     return;
-                  else
-                     Dir_Pos := Dir_Pos + Dir_Rec_Length;
-                  end if;
+                  -- `Dir_Rec_Length = 0` means we have to skip to the next fs block:
+                  declare
+                     Block_Gap : constant File_Length := FSBlock_Size - (Dir_Pos mod FSBlock_Size);
+                  begin
+                     if Unsigned_64 (Dir_Pos) >= Unsigned_64 (State.Inode.Size) - Unsigned_64 (Block_Gap) then
+                        return;
+                     else
+                        Dir_Pos := Dir_Pos + Block_Gap;
+                     end if;
+                  end;
                end if;
             end;
          end;