From 2bd42e8c2e82a4aab077e526f615084535246609 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Mon, 18 Apr 2016 11:39:23 +0300 Subject: [PATCH] sfs: using endian-neutral i/o --- src/sfs/sfsPlainFS.pas | 12 ++-- src/sfs/sfsZipFS.pas | 123 +++++++++++++---------------------------- 2 files changed, 43 insertions(+), 92 deletions(-) diff --git a/src/sfs/sfsPlainFS.pas b/src/sfs/sfsPlainFS.pas index e43f367..5666ad2 100644 --- a/src/sfs/sfsPlainFS.pas +++ b/src/sfs/sfsPlainFS.pas @@ -52,8 +52,8 @@ var begin if (fType <> sfspvPAK) and (fType <> sfspvSIN) then raise ESFSError.Create('invalid archive'); fFileStream.Seek(4, soCurrent); // skip signature - fFileStream.ReadBuffer(dofs, 4); - fFileStream.ReadBuffer(dsize, 4); + dofs := readLongWord(fFileStream); + dsize := readLongWord(fFileStream); fFileStream.Position := dofs; if fType = sfspvPAK then esz := 64 else esz := 128; while dsize >= esz do @@ -62,8 +62,8 @@ begin FillChar(name[0], length(name), 0); fFileStream.ReadBuffer(name[0], esz-8); fi.fName := PChar(@name[0]); - fFileStream.ReadBuffer(fi.fOfs, 4); - fFileStream.ReadBuffer(fi.fSize, 4); + fi.fOfs := readLongWord(fFileStream); + fi.fSize := readLongWord(fFileStream); Dec(dsize, esz); end; end; @@ -100,8 +100,8 @@ begin vt := sfspvNone; st.ReadBuffer(sign[0], 4); - st.ReadBuffer(dofs, 4); - st.ReadBuffer(dsize, 4); + dofs := readLongWord(st); + dsize := readLongWord(st); st.Seek(-12, soCurrent); if sign = 'PACK' then begin diff --git a/src/sfs/sfsZipFS.pas b/src/sfs/sfsZipFS.pas index 22235a8..c39eb43 100644 --- a/src/sfs/sfsZipFS.pas +++ b/src/sfs/sfsZipFS.pas @@ -68,6 +68,21 @@ type localExtraSz: Word; end; +procedure readLFH (st: TStream; var hdr: TZLocalFileHeader); +{.$IFDEF ENDIAN_LITTLE} +begin + hdr.version := readByte(st); + hdr.hostOS := readByte(st); + hdr.flags := readWord(st); + hdr.method := readWord(st); + hdr.time := readLongWord(st); + hdr.crc := readLongWord(st); + hdr.packSz := readLongWord(st); + hdr.unpackSz := readLongWord(st); + hdr.fnameSz := readWord(st); + hdr.localExtraSz := readWord(st); +end; + function ZIPCheckMagic (st: TStream): Boolean; var @@ -84,12 +99,11 @@ end; function DFWADCheckMagic (st: TStream): Boolean; var sign: packed array [0..5] of Char; - fcnt: Word; begin result := false; if st.Size < 10 then exit; st.ReadBuffer(sign[0], 6); - st.ReadBuffer(fcnt, 2); + {fcnt :=} readWord(st); st.Seek(-8, soCurrent); //writeln('trying DFWAD... [', sign, ']'); if (sign[0] <> 'D') and (sign[1] <> 'F') and (sign[2] <> 'W') and @@ -164,47 +178,44 @@ procedure TSFSZipVolume.ZIPReadDirectory (); var fi: TSFSZipFileInfo; name: ShortString; - sign, dSign: packed array [0..3] of Char; + sign: packed array [0..3] of Char; lhdr: TZLocalFileHeader; - ignoreFile, skipped: Boolean; - crc, psz, usz: LongWord; - buf: packed array of Byte; - bufPos, bufUsed: Integer; + ignoreFile: Boolean; efid, efsz: Word; izver: Byte; izcrc: LongWord; begin - SetLength(buf, 0); // read local directory repeat fFileStream.ReadBuffer(sign[0], Length(sign)); + // skip data descriptor + if sign = 'PK'#7#8 then + begin + fFileStream.seek(3*4, soCurrent); + continue; + end; + if sign <> 'PK'#3#4 then break; ignoreFile := false; - skipped := false; + + readLFH(fFileStream, lhdr); fi := TSFSZipFileInfo.Create(self); fi.fPackSz := 0; fi.fMethod := 0; - //fi.fOfs := fFileStream.Position; - - fFileStream.ReadBuffer(lhdr, SizeOf(lhdr)); if lhdr.fnameSz > 255 then name[0] := #255 else name[0] := chr(lhdr.fnameSz); fFileStream.ReadBuffer(name[1], Length(name)); fFileStream.Seek(lhdr.fnameSz-Length(name), soCurrent); // rest of the name (if any) fi.fName := utf8to1251(name); - //writeln(Format('0x%08x : %s', [Integer(fi.fOfs), name])); // here we should process extra field: it may contain utf8 filename - //fFileStream.Seek(lhdr.localExtraSz, soCurrent); while lhdr.localExtraSz >= 4 do begin - efid := 0; - efsz := 0; - fFileStream.ReadBuffer(efid, 2); - fFileStream.ReadBuffer(efsz, 2); + efid := readWord(fFileStream); + efsz := readWord(fFileStream); Dec(lhdr.localExtraSz, 4); if efsz > lhdr.localExtraSz then break; // Info-ZIP Unicode Path Extra Field? @@ -254,73 +265,11 @@ begin fi.fPackSz := lhdr.packSz; fi.fMethod := lhdr.method; - if (lhdr.flags and (1 shl 3)) <> 0 then - begin - // it has a descriptor. stupid thing at all... - {$IFDEF SFS_DEBUG_ZIPFS} - WriteLn(ErrOutput, 'descr: $', IntToHex(fFileStream.Position, 8)); - WriteLn(ErrOutput, 'size: ', lhdr.unpackSz); - WriteLn(ErrOutput, 'psize: ', lhdr.packSz); - {$ENDIF} - skipped := true; - - if lhdr.packSz <> 0 then - begin - // some kind of idiot already did our work (maybe paritally) - // trust him (her? %-) - fFileStream.Seek(lhdr.packSz, soCurrent); - end; - - // scan for descriptor - if Length(buf) = 0 then SetLength(buf, 65536); - bufPos := 0; bufUsed := 0; - fFileStream.ReadBuffer(dSign[0], 4); - repeat - if dSign <> 'PK'#7#8 then - begin - // skip one byte - Move(dSign[1], dSign[0], 3); - if bufPos >= bufUsed then - begin - bufPos := 0; - // int64! - if fFileStream.Size-fFileStream.Position > Length(buf) then bufUsed := Length(buf) - else bufUsed := fFileStream.Size-fFileStream.Position; - if bufUsed = 0 then raise ESFSError.Create('invalid ZIP file'); - fFileStream.ReadBuffer(buf[0], bufUsed); - end; - dSign[3] := chr(buf[bufPos]); Inc(bufPos); - Inc(lhdr.packSz); - continue; - end; - // signature found: check if it is a real one - // ???: make stronger check (for the correct following signature)? - // sign, crc, packsize, unpacksize - fFileStream.Seek(-bufUsed+bufPos, soCurrent); bufPos := 0; bufUsed := 0; - fFileStream.ReadBuffer(crc, 4); // crc - fFileStream.ReadBuffer(psz, 4); // packed size - // is size correct? - if psz = lhdr.packSz then - begin - // this is a real description. fuck it off - fFileStream.ReadBuffer(usz, 4); // unpacked size - break; - end; - // this is just a sequence of bytes - fFileStream.Seek(-8, soCurrent); - fFileStream.ReadBuffer(dSign[0], 4); - Inc(lhdr.packSz, 4); - until false; - // store correct values - fi.fSize := usz; - fi.fPackSz := psz; - end; - // skip packed data - if not skipped then fFileStream.Seek(lhdr.packSz, soCurrent); + fFileStream.Seek(lhdr.packSz, soCurrent); if ignoreFile then fi.Free(); until false; - + (* if (sign <> 'PK'#1#2) and (sign <> 'PK'#5#6) then begin {$IFDEF SFS_DEBUG_ZIPFS} @@ -329,6 +278,7 @@ begin {$ENDIF} raise ESFSError.Create('invalid .ZIP archive (no central dir)'); end; + *) end; @@ -337,20 +287,21 @@ procedure TSFSZipVolume.DFWADReadDirectory (); var fcnt: Word; fi: TSFSZipFileInfo; - f, c, fofs, fpksize: Integer; + f, c: Integer; + fofs, fpksize: LongWord; curpath, fname: string; name: packed array [0..15] of Char; begin curpath := ''; fFileStream.Seek(6, soCurrent); // skip signature - fFileStream.ReadBuffer(fcnt, 2); + fcnt := readWord(fFileStream); if fcnt = 0 then exit; // read files for f := 0 to fcnt-1 do begin fFileStream.ReadBuffer(name[0], 16); - fFileStream.ReadBuffer(fofs, 4); - fFileStream.ReadBuffer(fpksize, 4); + fofs := readLongWord(fFileStream); + fpksize := readLongWord(fFileStream); c := 0; fname := ''; while (c < 16) and (name[c] <> #0) do -- 2.29.2