Гараж Delphi




Алгоритмы и функции для эффективной разработки приложений в среде программирования Delphi

Ошибка в модуле idZLibCompressorBase

26.03.2010 от semen

Для обработки gzip/deflate часто используется модуль idZLibCompressorBase. В принципе, модуль неплохо справляется со своими функциями пока не попадутся “криво” сжатые данные. В некоторых случаях может возникнуть бесконечный цикл считывания со всеми вытекающими неприятностями. Вот ошибочный код:

 procedure GotoDataStart;
  var LFlags:byte;
      LExtra:word;
      LNullFindChar:char;
  begin
    AStream.Seek(3,soFromCurrent);
    AStream.Read(LFlags,1);
    AStream.Seek(6,soFromCurrent);
    // at pos 10 now
    if LFlags and $4 = $4 then begin // FEXTRA
      AStream.Read(LExtra, 2);
      AStream.Seek(LExtra, soFromCurrent);
    end;
 
    if LFlags and $8 = $8 then begin // FNAME
      repeat
        AStream.Read(LNullFindChar, 1) 
      until LNullFindChar=#0;
    end;
 
    if LFlags and $10 = $10 then begin // FCOMMENT
      repeat
        AStream.Read(LNullFindChar, 1)
      until LNullFindChar=#0;
    end;
 
    if LFlags and $2 = $2 then begin // FHCRC
      AStream.Seek(2, soFromCurrent); // CRC16
    end;
  end;

В циклах repeat может возникнуть проблема, если нет нулевого символа #0, поэтому необходимо проверять длину прочитанных байт и выходить из цикла, если прочитать не удалось:

procedure GotoDataStart;
  var LFlags:byte;
      LExtra:word;
      LNullFindChar:char;
  begin
    AStream.Seek(3,soFromCurrent);
    AStream.Read(LFlags,1);
    AStream.Seek(6,soFromCurrent);
    // at pos 10 now
 
    if LFlags and $4 = $4 then begin // FEXTRA
      AStream.Read(LExtra, 2);
      AStream.Seek(LExtra, soFromCurrent);
    end;
 
    if LFlags and $8 = $8 then begin // FNAME
      repeat
        if AStream.Read(LNullFindChar, 1) = 0 then break;
      until LNullFindChar=#0;
    end;
 
    if LFlags and $10 = $10 then begin // FCOMMENT
      repeat
        if AStream.Read(LNullFindChar, 1) = 0 then break;
      until LNullFindChar=#0;
    end;
 
    if LFlags and $2 = $2 then begin // FHCRC
      AStream.Seek(2, soFromCurrent); // CRC16
    end;
  end;

Циклическое считывание данных довольно часто применяется, пример показывает возможную ошибку - необходимо проверять количество прочитанных байт!

См. также:
Настоящий iconv для Delphi это возможно!
Обрабатываем HTML
Base64 в Delphi

Рубрики: Модули, Алгоритмы

Оставьте комментарий

Заметьте: комментарии проверяются автором сайта. Нет смысла отправлять комментарий два раза.