private ZipReturn ZipFileReadHeaders() { try { ZipReturn zRet = FindEndOfCentralDirSignature(); if (zRet != ZipReturn.ZipGood) { ZipFileClose(); return(zRet); } ulong endOfCentralDir = (ulong)_zipFs.Position; zRet = EndOfCentralDirRead(); if (zRet != ZipReturn.ZipGood) { ZipFileClose(); return(zRet); } // check if ZIP64 header is required bool zip64Required = (_centralDirStart == 0xffffffff || _centralDirSize == 0xffffffff || _localFilesCount == 0xffff); // check for a ZIP64 header _zipFs.Position = (long)endOfCentralDir - 20; zRet = Zip64EndOfCentralDirectoryLocatorRead(); if (zRet == ZipReturn.ZipGood) { _zipFs.Position = (long)_endOfCentralDir64; zRet = Zip64EndOfCentralDirRead(); if (zRet == ZipReturn.ZipGood) { _zip64 = true; endOfCentralDir = _endOfCentralDir64; } } if (zip64Required && !_zip64) { return(ZipReturn.Zip64EndOfCentralDirError); } offset = (endOfCentralDir - _centralDirSize) - _centralDirStart; _centralDirStart += offset; bool trrntzip = false; // check if the ZIP has a valid TorrentZip file comment if (FileComment.Length == 22) { if (CompressUtils.GetString(FileComment).Substring(0, 14) == "TORRENTZIPPED-") { CrcCalculatorStream crcCs = new(_zipFs, true); byte[] buffer = new byte[_centralDirSize]; _zipFs.Position = (long)_centralDirStart; crcCs.Read(buffer, 0, (int)_centralDirSize); crcCs.Flush(); crcCs.Close(); uint r = (uint)crcCs.Crc; crcCs.Dispose(); string tcrc = CompressUtils.GetString(FileComment).Substring(14, 8); string zcrc = r.ToString("X8"); if (string.Compare(tcrc, zcrc, StringComparison.Ordinal) == 0) { trrntzip = true; } } } if (zip64Required != _zip64) { trrntzip = false; } // now read the central directory _zipFs.Position = (long)_centralDirStart; _localFiles.Clear(); _localFiles.Capacity = (int)_localFilesCount; for (int i = 0; i < _localFilesCount; i++) { ZipLocalFile lc = new(); zRet = lc.CentralDirectoryRead(_zipFs, offset); if (zRet != ZipReturn.ZipGood) { ZipFileClose(); return(zRet); } _zip64 |= lc.GetStatus(LocalFileStatus.Zip64); _localFiles.Add(lc); } for (int i = 0; i < _localFilesCount; i++) { zRet = _localFiles[i].LocalFileHeaderRead(_zipFs); if (zRet != ZipReturn.ZipGood) { ZipFileClose(); return(zRet); } trrntzip &= _localFiles[i].GetStatus(LocalFileStatus.TrrntZip); } // check trrntzip file order if (trrntzip) { for (int i = 0; i < _localFilesCount - 1; i++) { if (CompressUtils.TrrntZipStringCompare(_localFiles[i].Filename, _localFiles[i + 1].Filename) < 0) { continue; } trrntzip = false; break; } } // check trrntzip directories if (trrntzip) { for (int i = 0; i < _localFilesCount - 1; i++) { // see if we found a directory string filename0 = _localFiles[i].Filename; if (filename0.Substring(filename0.Length - 1, 1) != "/") { continue; } // see if the next file is in that directory string filename1 = _localFiles[i + 1].Filename; if (filename1.Length <= filename0.Length) { continue; } if (CompressUtils.TrrntZipStringCompare(filename0, filename1.Substring(0, filename0.Length)) != 0) { continue; } // if we found a file in the directory then we do not need the directory entry trrntzip = false; break; } } if (trrntzip) { ZipStatus |= ZipStatus.TrrntZip; } return(ZipReturn.ZipGood); } catch { ZipFileClose(); return(ZipReturn.ZipErrorReadingFile); } }
internal ZipReturn CentralDirectoryRead(Stream zipFs, ulong offset) { try { using BinaryReader br = new(zipFs, Encoding.UTF8, true); uint thisSignature = br.ReadUInt32(); if (thisSignature != CentralDirectoryHeaderSignature) { return(ZipReturn.ZipCentralDirError); } br.ReadUInt16(); // Version Made By br.ReadUInt16(); // Version Needed To Extract GeneralPurposeBitFlag = br.ReadUInt16(); _compressionMethod = br.ReadUInt16(); ushort lastModFileTime = br.ReadUInt16(); ushort lastModFileDate = br.ReadUInt16(); HeaderLastModified = CompressUtils.UtcTicksFromDosDateTime(lastModFileDate, lastModFileTime); CRC = ReadCRC(br); _compressedSize = br.ReadUInt32(); UncompressedSize = br.ReadUInt32(); ushort fileNameLength = br.ReadUInt16(); ushort extraFieldLength = br.ReadUInt16(); ushort fileCommentLength = br.ReadUInt16(); br.ReadUInt16(); // diskNumberStart br.ReadUInt16(); // internalFileAttributes br.ReadUInt32(); // externalFileAttributes RelativeOffsetOfLocalHeader = br.ReadUInt32(); byte[] bFileName = br.ReadBytes(fileNameLength); Filename = (GeneralPurposeBitFlag & (1 << 11)) == 0 ? CompressUtils.GetString(bFileName) : Encoding.UTF8.GetString(bFileName, 0, fileNameLength); if (extraFieldLength > 0) { byte[] extraField = br.ReadBytes(extraFieldLength); ZipReturn zr = ZipExtraField.ReadExtraField(extraField, bFileName, this, ref _compressedSize, ref RelativeOffsetOfLocalHeader, true); if (zr != ZipReturn.ZipGood) { return(zr); } } RelativeOffsetOfLocalHeader += offset; if (CompressUtils.IsCodePage437(Filename) != ((GeneralPurposeBitFlag & (1 << 11)) == 0)) { SetStatus(LocalFileStatus.TrrntZip, false); } if (fileCommentLength > 0) { byte[] fileComment = br.ReadBytes(fileCommentLength); } if (Filename.Length > 0) { char lastChar = Filename[Filename.Length - 1]; IsDirectory = (lastChar == '/' || lastChar == '\\'); if (IsDirectory && UncompressedSize > 0) { SetStatus(LocalFileStatus.DirectoryLengthError); } } /* * 4.4.5 compression method: (2 bytes) * * 0 - (Supported) The file is stored (no compression) * 1 - (Supported) The file is Shrunk * 2 - (Supported) The file is Reduced with compression factor 1 * 3 - (Supported) The file is Reduced with compression factor 2 * 4 - (Supported) The file is Reduced with compression factor 3 * 5 - (Supported) The file is Reduced with compression factor 4 * 6 - (Supported) The file is Imploded * 7 - Reserved for Tokenizing compression algorithm * 8 - (Supported) The file is Deflated * 9 - (Supported) Enhanced Deflating using Deflate64(tm) * 10 - PKWARE Data Compression Library Imploding (old IBM TERSE) * 11 - Reserved by PKWARE * 12 - (Supported) File is compressed using BZIP2 algorithm * 13 - Reserved by PKWARE * 14 - (Supported) LZMA * 15 - Reserved by PKWARE * 16 - IBM z/OS CMPSC Compression * 17 - Reserved by PKWARE * 18 - File is compressed using IBM TERSE (new) * 19 - IBM LZ77 z Architecture * 20 - deprecated (use method 93 for zstd) * 93 - (Supported, with external DLL) Zstandard (zstd) Compression * 94 - MP3 Compression * 95 - XZ Compression * 96 - JPEG variant * 97 - WavPack compressed data * 98 - (Supported) PPMd version I, Rev 1 * 99 - AE-x encryption marker (see APPENDIX E) */ switch (_compressionMethod) { case 0: // The file is stored (no compression) case 8: // The file is Deflated case 9: // Enhanced Deflating using Deflate64(tm) case 12: // The file is BZIP2 algorithm. case 14: // LZMA return(ZipReturn.ZipGood); case 20: case 93: // Zstandard (zstd) Compression return(ZipReturn.ZipGood); case 98: // PPMd version I, Rev 1 return(ZipReturn.ZipGood); default: return(ZipReturn.ZipUnsupportedCompression); } } catch { return(ZipReturn.ZipCentralDirError); } }
internal ZipReturn LocalFileHeaderRead(Stream zipFs) { try { using (BinaryReader br = new(zipFs, Encoding.UTF8, true)) { SetStatus(LocalFileStatus.TrrntZip); zipFs.Position = (long)RelativeOffsetOfLocalHeader; uint thisSignature = br.ReadUInt32(); if (thisSignature != LocalFileHeaderSignature) { return(ZipReturn.ZipLocalFileHeaderError); } br.ReadUInt16(); // version needed to extract ushort generalPurposeBitFlagLocal = br.ReadUInt16(); if (generalPurposeBitFlagLocal != GeneralPurposeBitFlag) { SetStatus(LocalFileStatus.TrrntZip, false); } ushort tshort = br.ReadUInt16(); if (tshort != _compressionMethod) { return(ZipReturn.ZipLocalFileHeaderError); } ushort lastModFileTime = br.ReadUInt16(); ushort lastModFileDate = br.ReadUInt16(); long tTime = CompressUtils.UtcTicksFromDosDateTime(lastModFileDate, lastModFileTime); if (tTime != HeaderLastModified) { SetStatus(LocalFileStatus.DateTimeMisMatch); SetStatus(LocalFileStatus.TrrntZip, false); } LocalFile localHeader = new(); localHeader.CRC = ReadCRC(br); ulong localHeaderCompressedSize = br.ReadUInt32(); localHeader.UncompressedSize = br.ReadUInt32(); ulong localRelativeOffset = 0; ushort fileNameLength = br.ReadUInt16(); ushort extraFieldLength = br.ReadUInt16(); byte[] bFileName = br.ReadBytes(fileNameLength); localHeader.Filename = (generalPurposeBitFlagLocal & (1 << 11)) == 0 ? CompressUtils.GetString(bFileName) : Encoding.UTF8.GetString(bFileName, 0, fileNameLength); if (extraFieldLength > 0) { byte[] extraField = br.ReadBytes(extraFieldLength); ZipReturn zr = ZipExtraField.ReadExtraField(extraField, bFileName, localHeader, ref localHeaderCompressedSize, ref localRelativeOffset, false); if (zr != ZipReturn.ZipGood) { return(zr); } } if (!CompressUtils.CompareString(Filename, localHeader.Filename)) { SetStatus(LocalFileStatus.TrrntZip, false); if (!CompressUtils.CompareStringSlash(Filename.ToLower(), localHeader.Filename.ToLower())) { SetStatus(LocalFileStatus.FilenameMisMatch); } } _dataLocation = (ulong)zipFs.Position; if ((GeneralPurposeBitFlag & 8) == 8) { SetStatus(LocalFileStatus.TrrntZip, false); zipFs.Position += (long)_compressedSize; localHeader.CRC = ReadCRC(br); if (CompressUtils.ByteArrCompare(localHeader.CRC, new byte[] { 0x08, 0x07, 0x4b, 0x50 })) { localHeader.CRC = ReadCRC(br); } if (GetStatus(LocalFileStatus.Zip64)) { localHeaderCompressedSize = br.ReadUInt64(); localHeader.UncompressedSize = br.ReadUInt64(); } else { localHeaderCompressedSize = br.ReadUInt32(); localHeader.UncompressedSize = br.ReadUInt32(); } } if (CompressUtils.IsCodePage437(Filename) != ((GeneralPurposeBitFlag & (1 << 11)) == 0)) { SetStatus(LocalFileStatus.TrrntZip, false); } if (!CompressUtils.ByteArrCompare(localHeader.CRC, CRC)) { return(ZipReturn.ZipLocalFileHeaderError); } if (localHeaderCompressedSize != _compressedSize) { return(ZipReturn.ZipLocalFileHeaderError); } if (localHeader.UncompressedSize != UncompressedSize) { return(ZipReturn.ZipLocalFileHeaderError); } return(ZipReturn.ZipGood); } } catch { return(ZipReturn.ZipLocalFileHeaderError); } }
internal ZipReturn LocalFileHeaderReadQuick(Stream zipFs) { try { using BinaryReader br = new(zipFs, Encoding.UTF8, true); SetStatus(LocalFileStatus.TrrntZip); zipFs.Position = (long)RelativeOffsetOfLocalHeader; uint thisSignature = br.ReadUInt32(); if (thisSignature != LocalFileHeaderSignature) { return(ZipReturn.ZipLocalFileHeaderError); } br.ReadUInt16(); // version needed to extract GeneralPurposeBitFlag = br.ReadUInt16(); if ((GeneralPurposeBitFlag & 8) == 8) { return(ZipReturn.ZipCannotFastOpen); } _compressionMethod = br.ReadUInt16(); ushort lastModFileTime = br.ReadUInt16(); ushort lastModFileDate = br.ReadUInt16(); HeaderLastModified = CompressUtils.UtcTicksFromDosDateTime(lastModFileDate, lastModFileTime); CRC = ReadCRC(br); _compressedSize = br.ReadUInt32(); UncompressedSize = br.ReadUInt32(); ushort fileNameLength = br.ReadUInt16(); ushort extraFieldLength = br.ReadUInt16(); byte[] bFileName = br.ReadBytes(fileNameLength); Filename = (GeneralPurposeBitFlag & (1 << 11)) == 0 ? CompressUtils.GetString(bFileName) : Encoding.UTF8.GetString(bFileName, 0, fileNameLength); SetStatus(LocalFileStatus.Zip64, false); if (extraFieldLength > 0) { byte[] extraField = br.ReadBytes(extraFieldLength); ulong LocalHeader = 0; ZipReturn zr = ZipExtraField.ReadExtraField(extraField, bFileName, this, ref _compressedSize, ref LocalHeader, false); if (zr != ZipReturn.ZipGood) { return(zr); } } if (CompressUtils.IsCodePage437(Filename) != ((GeneralPurposeBitFlag & (1 << 11)) == 0)) { SetStatus(LocalFileStatus.TrrntZip, false); } _dataLocation = (ulong)zipFs.Position; return(ZipReturn.ZipGood); } catch { return(ZipReturn.ZipLocalFileHeaderError); } }
private static void AddZip(FileInfo f, DatDir thisDir) { Zip zf1 = new Zip(); ZipReturn result = zf1.ZipFileOpen(f.FullName, -1, true); if (result != ZipReturn.ZipGood) { return; } zCount += 1; if ((zf1.ZipStatus & ZipStatus.TrrntZip) == ZipStatus.TrrntZip) { tCount += 1; Console.WriteLine($"{zCount} {tCount} {cCount}"); } else if (zf1.FileComment != null && zf1.FileComment.Length > 0) { string comments = CompressUtils.GetString(zf1.FileComment); if (comments.Length > 13 && comments.Substring(0, 13) == "TORRENTZIPPED") { tCount += 1; } else { cCount += 1; Console.WriteLine(f.FullName + " " + zCount); Console.WriteLine("------------------------"); Console.WriteLine(comments); } Console.WriteLine($"{zCount} {tCount} {cCount}"); } //zf1.ZipStatus = ZipStatus.TrrntZip; //DatDir ZipDir = new DatDir(zf1.ZipStatus == ZipStatus.TrrntZip ? DatFileType.DirTorrentZip : DatFileType.DirRVZip) DatDir ZipDir = new DatDir(DatFileType.UnSet) { Name = Path.GetFileNameWithoutExtension(f.Name), DGame = new DatGame() }; ZipDir.DGame.Description = ZipDir.Name; thisDir.ChildAdd(ZipDir); FileScan fs = new FileScan(); List <FileScan.FileResults> fr = fs.Scan(zf1, !quick, !quick); bool isTorrentZipDate = true; for (int i = 0; i < fr.Count; i++) { LocalFile lf = zf1.GetLocalFile(i); if (fr[i].FileStatus != ZipReturn.ZipGood) { Console.WriteLine("File Error :" + lf.Filename + " : " + fr[i].FileStatus); continue; } DatFile df = new DatFile(DatFileType.UnSet) { Name = lf.Filename, Size = fr[i].Size, CRC = fr[i].CRC, SHA1 = fr[i].SHA1, DateModified = new DateTime(lf.LastModified).ToString("yyyy/MM/dd HH:mm:ss"), //df.MD5 = zf.MD5(i) }; if (lf.LastModified != 629870671200000000) { isTorrentZipDate = false; } ZipDir.ChildAdd(df); } zf1.ZipFileClose(); if (isTorrentZipDate && ZipDir.DatFileType == DatFileType.DirRVZip) { ZipDir.DatFileType = DatFileType.DirTorrentZip; } if (ZipDir.DatFileType == DatFileType.DirTorrentZip) { DatSetCompressionType.SetZip(ZipDir); DatClean.RemoveUnNeededDirectoriesFromZip(ZipDir); } }