What is IFF ?
Classes are *simpler* than procedural programming because they allow for *much* easier modifications.
I've never looked at Allegro, so I cannot tell how hard coupling them would be.

Ok, here is my conversion of the unzip.pp straight from Free Pascal RTL.

Note that I did not check it for last-minute syntax errors as my engine is currently in complete disarray (not compiles). Another downside is that I haven't tried it in FPC 3 yet, may require replacement of AnsiString with RawByteString or something.
I tried removing the calls to the API of my engine but I may have missed some

It worked perfectly last year, compiled using FPC 2.6.4. I tested it on .pk3 files from OpenArena and my own .zip files. The average unpacking speed on my laptop was ~30 Mb/sec

http://chentrah.chebmaster.com/downloads/un_unzip.pp

So, what I did? I took the working but horribly outdated (API-wise) code and made it flexible by wrapping it into a class. The most important feature is it takes TStream as the source allowing you to support Unicode paths (if you have custom Unicode-supporting streams), work with your entire zip file loaded into memory (TMemoryStream) and even create support for nested zips with some extra effort.

I left *all* previous code commented out but not deleted, in case I encounter a rare bug resulting from improper conversion (none so far).

Its interface is not super easy to use, but! When you begin using pack files of any format you quickly realize you need a *directory* of files so that newer pack files can overwrite files from older ones and separate files in external folders should take precedence over filen in your pack files. Just like any game out there is programmed to do, from Quake 3 to fallout 4.
I cannot help with that, it's up to you to create directory you need.

What does this class do?
- Lets you iterate over the zip file's directory ti get file list
- Jump to specific file by name (It does iterate over the directory, in fact, but that is fast)
- unpack the next chunk of the currently selected file

To get file unpacked into memory (and you *have* to do that because unpacking is sequential and you applied routine would probably want to seek all over the unpacked file), I use code like this:

Code:
// this is optimized for my engine, lots of overhead due to multi-threaded asset loading
// you may want to use something more elegant than the array of byte
// f_zip is the TUnzip class instance (field of TZipFile)
function TZipFile.ReadFile(fname: TFileNameString): TArrayOfByte;
var
  ufi: unz_file_info;
  fn, comment: AnsiString;
  i, read_how_much: integer;
  err: boolean;
  q: Qword;
begin
[...]
  if not f_unzip.LocateFile(fname)
  then begin
    AddLog(RuEn(
      'Загрузка прервана: файл не найден в контейнере!'#10#13' файл %0'#10#13' контейнер %1',
      'Aborting the load: file not found in the container!'#10#13' file %0'#10#13' container %1'
      ), ['{$MODULE}' + fname, UnmangleFileName('{$MODULE}' + f_name)]);
    Exit(nil);
  end;

  Mother^.Timer.UsecDelta(@q);
  err:= not f_unzip.GetCurrentFileInfo (@ufi, fn, nil, 0, comment);
  if not err then err:= not f_unzip.OpenCurrentFile();
  if not err then begin
    SetLength(Result, ufi.uncompressed_size);
    i:= 0;
    while i < Length(Result) do begin
      read_how_much:= f_unzip.ReadCurrentFile(@Result[i], Length(Result) - i);
      if read_how_much <=0 then begin
        err:= true;
        break;
      end;
      i+= read_how_much;
    end;
  end;
  if err then begin
    AddLog(RuEn(
      'Загрузка прервана: ошибка чтения из контейнера!'#10#13' файл %0'#10#13' контейнер %1',
      'Aborting the load: error reading from the container!'#10#13' file %0'#10#13' container %1'
      ), [fname, UnmangleFileName('{$MODULE}' + f_name)]);
    SetLength(Result, 0);
  end;
  if Mother^.Debug.Verbose then AddLog('      ..unpacked %0 bytes in %1 μs', [Length(Result), round(Mother^.Timer.UsecDelta(@q))]);
end;
and, directory building example:
Code:
function TZipFile.Initialize: boolean; //is ONLY called by threaded tasks from their thread!
var
  ufi: unz_file_info;
  i: integer;
  fn, comment: AnsiString;
begin
  Result:= inherited Initialize;
  if Result and not Assigned(f_unzip) then begin
    if Assigned(f_unzip) then Exit(true);
    try
      if Mother^.Debug.Verbose then AddLog('  Attaching a zlib object to the stream ...');
      f_unzip:= TUnzip.Create(f_stream);
      repeat
        if not f_unzip.GetCurrentFileInfo (@ufi, fn, nil, 0, comment) then break;
        if ufi.uncompressed_size <= 0 then continue; //there are folders and shit
		
		//now there is my engine adding that file to its own directory 
        SetLength(f_list, Length(f_list) + 1);
		with f_list[High(f_list)] do begin
          name:= '{$MODULE}' + fn;
          pak_file:= Self;
          Hash.FileAge:= FileDateToDateTime(ufi.dosDate);
          Hash.NameMd5:= Md5String(name);
          Hash.FileSize:= ufi.uncompressed_size;
          if Mother^.Debug.Verbose then AddLog('    %0 , size=%1, ratio=%2%',
            [name, ufi.uncompressed_size, round (100.0 * ufi.compressed_size / max(1, ufi.uncompressed_size))]);
        end;
      until not f_unzip.GoToNextFile();
      if Mother^.Debug.Verbose then AddLog('  Parsed successfully, found %0 files.', [Length(f_list)]);
    except
      AddLog(RuEn(
        'Не удалось инициализировать распаковщик unzip'#10#13#10#13'%0',
        'Failed to initialize unzip unpacker'#10#13#10#13'%0')
        ,[StopDying()]);
      Result:= false;
    end;
  end;
end;