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); } }
/* * raw is true if we are just going to copy the raw data stream from the source to the destination zip file * trrntzip is thue if the source zip is a valid trrntzip file * compressionMethod must be set to 8 to make a valid trrntzip file. * * if raw is false then compressionMthod must be 0,8 or 93 (zstd) */ public ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong uncompressedSize, ushort compressionMethod, out Stream stream, TimeStamps timeStamp = null) { stream = null; if (ZipOpen != ZipOpenType.OpenWrite) { return(ZipReturn.ZipWritingToInputFile); } ZipReturn validTrrntzip = ZipReturn.ZipGood; //invalid torrentZip Input If: if (compressionMethod != 8) { validTrrntzip = ZipReturn.ZipTrrntzipIncorrectCompressionUsed; } if (raw && !trrntzip) { validTrrntzip = ZipReturn.ZipTrrntZipIncorrectDataStream; } int localFilesCount = _localFiles.Count; if (localFilesCount > 0) { // check that filenames are in trrntzip order string lastFilename = _localFiles[localFilesCount - 1].Filename; if (CompressUtils.TrrntZipStringCompare(lastFilename, filename) > 0) { validTrrntzip = ZipReturn.ZipTrrntzipIncorrectFileOrder; } // check that no un-needed directory entries are added if (_localFiles[localFilesCount - 1].IsDirectory && filename.Length > lastFilename.Length) { if (CompressUtils.TrrntZipStringCompare(lastFilename, filename.Substring(0, lastFilename.Length)) == 0) { validTrrntzip = ZipReturn.ZipTrrntzipIncorrectDirectoryAddedToZip; } } } // if we are requirering a trrrntzp file and it is not a trrntzip formated supplied stream then error out if (writeZipType == OutputZipType.TrrntZip) { if (validTrrntzip != ZipReturn.ZipGood) { return(validTrrntzip); } } ZipLocalFile lf = new ZipLocalFile(filename, timeStamp); lf.SetStatus(LocalFileStatus.TrrntZip, validTrrntzip == ZipReturn.ZipGood); ZipReturn retVal = lf.LocalFileOpenWriteStream(_zipFs, raw, uncompressedSize, compressionMethod, out stream); if (retVal != ZipReturn.ZipGood) { return(retVal); } if (filename.Length > 0) { lf.IsDirectory = (filename.Substring(filename.Length - 1, 1) == "/"); } _compressionStream = stream; _localFiles.Add(lf); return(ZipReturn.ZipGood); }