/// <summary> /// Reads the uncompressed body of versions equal or above 0x200. /// The body is ZIP (deflate) compressed. /// </summary> /// <param name="binReader"></param> /// <param name="fileCount"></param> /// <param name="skipFiles"></param> /// <returns></returns> private bool ReadFilesVersion2(BinaryReader binReader, int fileCount, bool skipFiles) { int lengthCompressed = binReader.ReadInt32(); int lengthUnCompressed = binReader.ReadInt32(); mFileTableLength = (ulong)lengthUnCompressed; var bufCompressed = new byte[lengthCompressed]; mFiletableUncompressed = new byte[(int)mFileTableLength]; binReader.Read(bufCompressed, 0, lengthCompressed); mFiletableUncompressed = Deflate.Decompress(bufCompressed); /* * if (mFiletableUncompressed.Length != (int)mFileTableLength) { * throw new Exception("Filesize missmatch! Uncompressed Body Size is not equal to Uncompressed Length!"); * } */ // Only read body? if (skipFiles == false) { for (int i = 0, offset = 0; i < fileCount; i++) { var filepath = string.Empty; char c; var itemTableOffset = (uint)offset; while ((c = (char)mFiletableUncompressed[offset++]) != '\0') { filepath += c; } filepath = Tools.UnifyPath(filepath); var item = new RoGrfFileItem { TableOffset = itemTableOffset, Index = Files.Count, Filepath = filepath, Flags = mFiletableUncompressed[offset + 12] }; // File or directory? if (item.IsFile) { item.LengthCompressed = BitConverter.ToUInt32(mFiletableUncompressed, offset); item.LengthCompressedAlign = BitConverter.ToUInt32(mFiletableUncompressed, offset + 4); item.LengthUnCompressed = BitConverter.ToUInt32(mFiletableUncompressed, offset + 8); // Offset is base offset + grf header item.DataOffset = BitConverter.ToUInt32(mFiletableUncompressed, offset + 13) + GrfHeaderLen; // from eAtehna, DES encryption item.Cycle = 1; switch (item.Flags) { case 3: for (var lop = 10; item.LengthCompressed >= lop; lop = lop * 10, item.Cycle++) { } break; case 5: item.Cycle = 0; break; default: item.Cycle = -1; break; } } else { // skip dirs offset += (int)GrfFileLen; continue; } // FIX: Some files in a tested grf are duplicated? // I cant remember grf version or something else.. if (GetFileByHash(item.NameHash) != null) { // Duplicate file, just skip it offset += (int)GrfFileLen; continue; } Files.Add(item.NameHash, item); mStringlist.Add(item.NameHash); mFileDataLength += item.LengthCompressedAlign; offset += (int)GrfFileLen; #if !DISABLE_GRF_EVENTS OnItemAdded(item, i, fileCount); #endif } } return(true); }
/// <summary> /// Writes the grf to the given Filename /// </summary> /// <param name="destinationPath"></param> /// <param name="repack"> </param> /// <returns></returns> public bool WriteGrf(string destinationPath, bool repack) { // Write to temp file string tmpDestinationPath = destinationPath + "tmp"; using (FileStream fs = File.OpenWrite(tmpDestinationPath)) { using (mWriter = new BinaryWriter(fs)) { int iLengthUnCompressed; byte[] fileTableDataCompressed; using (var fileTableStream = new MemoryStream()) { mWriter.Seek((int)GrfHeaderLen, SeekOrigin.Begin); // Write file binary data & temporary write file table int filesWritten; if (repack || AlwaysRepack) { filesWritten = WriteFileData(fileTableStream); } else { filesWritten = WriteFileDataDirty(fileTableStream); } // Save the offset after writing binary data var thisPos = (int)mWriter.BaseStream.Position; // Write grf header mWriter.Seek(0, SeekOrigin.Begin); foreach (var c in MagicHeader) { mWriter.Write((byte)c); // header (15) } foreach (var c in AllowEncrypt) { mWriter.Write((byte)c); // encrypt (15) } mWriter.Write((uint)(thisPos - GrfHeaderLen)); // tableOffset mWriter.Write(mFilecountNumber1); mWriter.Write((uint)(filesWritten + mFilecountNumber1 + 7)); // number2 // Always default version Version = GrfDefaultVersion; mWriter.Write(Version); // GRF Version mWriter.Seek(thisPos, SeekOrigin.Begin); // Compress file table data iLengthUnCompressed = (int)fileTableStream.Length; fileTableDataCompressed = Deflate.Compress(fileTableStream.ToArray(), true); } // Write length and data mWriter.Write(fileTableDataCompressed.Length); // compressed mWriter.Write(iLengthUnCompressed); // uncompressed mWriter.Write(fileTableDataCompressed, 0, fileTableDataCompressed.Length); // data itself } } // If we want to overwrite the previous opened GRF, close it first if (mFilepath == destinationPath) { Flush(); } // Ensure nothing blocks the move File.Delete(destinationPath); // Move it finally File.Move(destinationPath + "tmp", destinationPath); // Fore clean up GC.Collect(); return(true); }
/// <summary> /// Writes the binary data to the stream. /// </summary> /// <param name="grf"></param> /// <param name="writer"></param> internal void WriteToBinaryTable(RoGrfFile grf, BinaryWriter writer) { // Skip deleted files if (IsDeleted) { return; } byte[] buf; // Update new offset DataOffset = (uint)writer.BaseStream.Position; // Either new or changed? if (IsUpdated == false && IsAdded == false) { // Auto-convert to 0x200 compression (deflate) if (grf.Version != 0x200) { // #1: Decompress buf and update length buf = grf.GetFileData(NameHash, true); LengthUnCompressed = (uint)buf.Length; // #2: Compress and update length buf = Deflate.Compress(buf, true); LengthCompressed = (uint)buf.Length; LengthCompressedAlign = (uint)buf.Length; } else { // Get compressed data buf = grf.GetFileData(NameHash, false); } } else { // Added or updated files, load data from origin filepath if (File.Exists(NewFilepath) == false) { throw new Exception("WriteItems(): File of new or updated item not found: " + NewFilepath); } buf = File.ReadAllBytes(NewFilepath); LengthUnCompressed = (uint)buf.Length; buf = Deflate.Compress(buf, true); LengthCompressed = LengthCompressedAlign = (uint)buf.Length; } try { // Check if the buf is compressed if (buf.Length != LengthCompressed && buf.Length != LengthCompressedAlign) { // The buf has to be compressed, so decompress it byte[] bufUncompressed = Deflate.Decompress(buf); // Update length, if decompression seems to be correct if (bufUncompressed.Length == 0 || bufUncompressed.Length != LengthUnCompressed) { // Narf, corrupt file or something like that // Just write it.. //throw new Exception("WriteItems(): Item " + Filepath + ", DataLen missmatch"); } else { // Decompression was succesfull, so update size LengthCompressed = (uint)Deflate.GetCompressedLength(bufUncompressed); } } // Seems like a valid buf, write it writer.Write(buf); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e); } }