public void DeleteEntry(int Index) { try { FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read); int tocIndex = findTOCIndex(); if (tocIndex == -1) { return; } MemoryStream m = DecompressEntry(tocIndex, fs); fs.Close(); FileEntryStruct e = Files[Index]; string toc = Encoding.UTF8.GetString(m.ToArray(), 0, (int)m.Length); string file = e.FileName + "\r\n"; toc = toc.Replace(file, ""); ReplaceEntry(Encoding.ASCII.GetBytes(toc), tocIndex); List <FileEntryStruct> l = new List <FileEntryStruct>(); l.AddRange(Files); l.RemoveAt(Index); Files = l.ToArray(); Header.FileCount--; ReBuild(); } catch (Exception ex) { Debug.WriteLine("ERROR DELETING ENTRY FROM SFAR TOC\n" + ex.Message); } }
public void DeleteEntries(List <int> Index) { Index.Sort(); Index.Reverse(); FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read); int f = FindTOC(); if (f == -1) { return; } MemoryStream m = DecompressEntry(f, fs); string toc = Encoding.UTF8.GetString(m.ToArray(), 0, (int)m.Length); fs.Close(); for (int i = 0; i < Index.Count; i++) { FileEntryStruct e = Files[Index[i]]; string file = e.FileName + "\r\n"; toc = toc.Replace(file, ""); } ReplaceEntry(Encoding.ASCII.GetBytes(toc), f); List <FileEntryStruct> l = new List <FileEntryStruct>(); l.AddRange(Files); for (int i = 0; i < Index.Count; i++) { l.RemoveAt(Index[i]); Header.FileCount--; } Files = l.ToArray(); ReBuild(); }
public void Serialize(SerializingFile con) { if (con.isLoading) { Header = new HeaderStruct(); } Header.Serialize(con); con.Seek((int)Header.EntryOffset, SeekOrigin.Begin); for (int i = 0; i < Header.FileCount; i++) { //Debug.WriteLine($"Serialize sfar file {i} at 0x{con.Memory.Position:X8}"); var feStruct = new FileEntryStruct(); feStruct.Serialize(con, Header); Files.Add(feStruct); //Debug.WriteLine($"Data offset for {i}: 0x{Files[i].DataOffset:X8} (0x{Files[i].RealDataOffset:X8}), header at 0x{pos:X8}"); } //var ordered = Files.OrderBy(x => x.DataOffset).ToList(); //foreach (var f in ordered) //{ // Debug.WriteLine($"0x{f.DataOffset:X8} (0x{f.RealDataOffset:X8}), header at {f.MyOffset:X8}"); //} //var firstfile = Files.MinBy(x => x.RealDataOffset); if (con.isLoading) { ReadFileNames(); } }
public void DeleteEntry(int Index) { try { FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read); Debug.WriteLine("Searching TOC..."); int f = FindTOC(); if (f == -1) { return; } Debug.WriteLine("Found TOC, deleting line..."); MemoryStream m = DecompressEntry(f, fs); fs.Close(); FileEntryStruct e = Files[Index]; string toc = Encoding.UTF8.GetString(m.ToArray(), 0, (int)m.Length); string file = e.FileName + "\r\n"; toc = toc.Replace(file, ""); Debug.WriteLine("Replacing TOC..."); ReplaceEntry(Encoding.ASCII.GetBytes(toc), f); Debug.WriteLine("Deleting Entry from Filelist..."); List <FileEntryStruct> l = new List <FileEntryStruct>(); l.AddRange(Files); l.RemoveAt(Index); Files.ReplaceAll(l); Header.FileCount--; Debug.WriteLine("Rebuilding..."); ReBuild(); Debug.WriteLine("Done."); } catch (Exception ex) { Debug.WriteLine("ERROR\n" + ex.Message); } }
public MemoryStream DecompressEntry(int Index) { MemoryStream result = new MemoryStream(); FileEntryStruct e = Files[Index]; uint count = 0; byte[] inputBlock; byte[] outputBlock = new byte[Header.MaxBlockSize]; long left = e.RealUncompressedSize; FileStream fs = new FileStream(MyFileName, FileMode.Open, FileAccess.Read); fs.Seek(e.BlockOffsets[0], SeekOrigin.Begin); byte[] buff; if (e.BlockSizeIndex == 0xFFFFFFFF) { buff = new byte[e.RealUncompressedSize]; fs.Read(buff, 0, buff.Length); result.Write(buff, 0, buff.Length); } else { while (left > 0) { uint compressedBlockSize = (uint)e.BlockSizes[count]; if (compressedBlockSize == 0) { compressedBlockSize = Header.MaxBlockSize; } if (compressedBlockSize == Header.MaxBlockSize || compressedBlockSize == left) { buff = new byte[compressedBlockSize]; fs.Read(buff, 0, buff.Length); result.Write(buff, 0, buff.Length); left -= compressedBlockSize; } else { var uncompressedBlockSize = (uint)Math.Min(left, Header.MaxBlockSize); if (compressedBlockSize < 5) { throw new Exception("compressed block size smaller than 5"); } inputBlock = new byte[compressedBlockSize]; fs.Read(inputBlock, 0, (int)compressedBlockSize); uint actualUncompressedBlockSize = uncompressedBlockSize; uint actualCompressedBlockSize = compressedBlockSize; outputBlock = SevenZipHelper.Decompress(inputBlock, (int)actualUncompressedBlockSize); if (outputBlock.Length != actualUncompressedBlockSize) { throw new Exception("Decompression Error"); } result.Write(outputBlock, 0, (int)actualUncompressedBlockSize); left -= uncompressedBlockSize; } count++; } } fs.Close(); return(result); }
public void ReplaceEntry(byte[] FileIN, int Index) { string DLCPath = MyFileName; FileStream fs = new FileStream(DLCPath, FileMode.OpenOrCreate, FileAccess.ReadWrite); fs.Seek(0, SeekOrigin.End); uint offset = (uint)fs.Length; fs.Write(FileIN, 0, FileIN.Length); FileEntryStruct e = Files[Index]; e.BlockSizes = new ushort[0]; e.BlockOffsets = new long[1]; e.BlockOffsets[0] = offset; e.BlockSizeIndex = 0xFFFFFFFF; e.DataOffset = offset; e.UncompressedSize = (uint)FileIN.Length; fs.Seek(e.MyOffset, 0); fs.Write(e.Hash, 0, 16); fs.Write(BitConverter.GetBytes(0xFFFFFFFF), 0, 4); fs.Write(BitConverter.GetBytes(FileIN.Length), 0, 4); fs.WriteByte(e.UncompressedSizeAdder); fs.Write(BitConverter.GetBytes(offset), 0, 4); fs.WriteByte(0); Files[Index] = e; fs.Close(); }
public List <byte[]> GetBlocks(int Index) { List <byte[]> res = new List <byte[]>(); FileEntryStruct e = Files[Index]; uint count = 0; byte[] inputBlock; byte[] outputBlock = new byte[Header.MaxBlockSize]; long left = e.RealUncompressedSize; FileStream fs = new FileStream(MyFileName, FileMode.Open, FileAccess.Read); fs.Seek(e.BlockOffsets[0], SeekOrigin.Begin); byte[] buff; if (e.BlockSizeIndex == 0xFFFFFFFF) { buff = new byte[e.RealUncompressedSize]; fs.Read(buff, 0, buff.Length); res.Add(buff); fs.Close(); return(res); } else { while (left > 0) { uint compressedBlockSize = (uint)e.BlockSizes[count]; if (compressedBlockSize == 0) { compressedBlockSize = Header.MaxBlockSize; } if (compressedBlockSize == Header.MaxBlockSize || compressedBlockSize == left) { buff = new byte[compressedBlockSize]; fs.Read(buff, 0, buff.Length); res.Add(buff); left -= compressedBlockSize; } else { var uncompressedBlockSize = (uint)Math.Min(left, Header.MaxBlockSize); if (compressedBlockSize < 5) { DebugLog.PrintLn("DLCPACKAGE::GETBLOCKS ERROR: compressed block size smaller than 5"); break; } inputBlock = new byte[compressedBlockSize]; fs.Read(inputBlock, 0, (int)compressedBlockSize); res.Add(inputBlock); left -= uncompressedBlockSize; } count++; } } fs.Close(); return(res); }
public void DeleteEntry(List <int> Index) { try { Index.Sort(); Index.Reverse(); FileStream fs = new FileStream(MyFileName, FileMode.Open, FileAccess.Read); //DebugLog.PrintLn("Searching TOC..."); int f = FindTOC(); if (f == -1) { return; } //DebugLog.PrintLn("Found TOC, deleting lines..."); MemoryStream m = DecompressEntry(f, fs); string toc = Encoding.UTF8.GetString(m.ToArray(), 0, (int)m.Length); fs.Close(); for (int i = 0; i < Index.Count; i++) { FileEntryStruct e = Files[Index[i]]; string file = e.FileName + "\r\n"; toc = toc.Replace(file, ""); } //DebugLog.PrintLn("Replacing TOC..."); ReplaceEntry(Encoding.ASCII.GetBytes(toc), f); //DebugLog.PrintLn("Deleting Entry from Filelist..."); List <FileEntryStruct> l = new List <FileEntryStruct>(); l.AddRange(Files); for (int i = 0; i < Index.Count; i++) { l.RemoveAt(Index[i]); Header.FileCount--; } Files = l.ToArray(); //DebugLog.PrintLn("Rebuilding..."); ReBuild(); //DebugLog.PrintLn("Done."); } catch (Exception ex) { //DebugLog.PrintLn("ERROR\n" + ex.Message); } }
/// <summary> /// Appends a file to the index and accompanying data file. /// </summary> /// <param name="directory">The directory that will be stored in the index.</param> /// <param name="fileName">The filename that will be stored in the index.</param> /// <param name="bytesToWrite">Byte array of the file to add.</param> /// <param name="fileTime">File time to set to the file.</param> /// <returns>Returns true if the operation was successful.</returns> public override bool AddFile(String directory, String fileName, byte[] bytesToWrite, DateTime?fileTime = null) { if (bytesToWrite == null || bytesToWrite.Length == 0) { throw new ArgumentNullException("bytesToWrite", "Bytes to write cannot be empty!"); } bool doCompress = NoCompressionExt.All(extentsion => !fileName.EndsWith(extentsion)); if (fileTime == null) { fileTime = DateTime.Now; } FileEntryStruct fileStruct = new FileEntryStruct { StartToken = Token.Info, SizeUncompressed = bytesToWrite.Length, SizeCompressed = doCompress ? 1 : 0, FileTime = fileTime.Value.ToFileTime(), NameHash = Crypt.GetStringSHA1UInt32(fileName), DirectoryHash = Crypt.GetStringSHA1UInt32(directory), First4BytesOfFile = FileTools.ByteArrayToInt32(bytesToWrite, 0), Second4BytesOfFile = FileTools.ByteArrayToInt32(bytesToWrite, 4), EndToken = Token.Info, }; PackFileEntry fileEntry = new FileEntry(fileStruct); fileEntry.Directory = directory; fileEntry.Name = fileName; Files.Add(fileEntry); _AddFileToDat(bytesToWrite, fileEntry); // todo: create new applicable file entry object as well? // todo: remove existing file bytes if applicable... return(true); }
public void ReplaceEntry(byte[] newData, int entryIndex) { FileStream fs = new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite); FileEntryStruct e = Files[entryIndex]; if (e.BlockSizeTableIndex == 0xFFFFFFFF && e.RealUncompressedSize == newData.Length) { //overwrite existing data, but only if already uncompressed! fs.Seek(e.RealDataOffset, SeekOrigin.Begin); } else { // It won't fit. Append it to the end instead fs.Seek(0, SeekOrigin.End); } uint offset = (uint)fs.Position; //append data fs.Write(newData, 0, newData.Length); //uncompressed entry e.BlockSizes = new ushort[0]; e.BlockOffsets = new long[1]; e.BlockOffsets[0] = offset; e.BlockSizeTableIndex = 0xFFFFFFFF; e.DataOffset = offset; e.UncompressedSize = (uint)newData.Length; fs.Seek(e.MyOffset, 0); fs.Write(e.Hash, 0, 16); fs.Write(BitConverter.GetBytes(0xFFFFFFFF), 0, 4); fs.Write(BitConverter.GetBytes(newData.Length), 0, 4); fs.WriteByte(e.UncompressedSizeAdder); fs.Write(BitConverter.GetBytes(offset), 0, 4); fs.WriteByte(0); Files[entryIndex] = e; fs.Close(); }
/// <summary> /// Appends a file to the index and accompanying data file. /// </summary> /// <param name="directory">The directory that will be stored in the index.</param> /// <param name="fileName">The filename that will be stored in the index.</param> /// <param name="bytesToWrite">Byte array of the file to add.</param> /// <param name="fileTime">File time to set to the file.</param> /// <returns>Returns true if the operation was successful.</returns> public override bool AddFile(String directory, String fileName, byte[] bytesToWrite, DateTime ?fileTime = null) { if (bytesToWrite == null || bytesToWrite.Length == 0) throw new ArgumentNullException("bytesToWrite", "Bytes to write cannot be empty!"); bool doCompress = NoCompressionExt.All(extentsion => !fileName.EndsWith(extentsion)); if (fileTime == null) fileTime = DateTime.Now; FileEntryStruct fileStruct = new FileEntryStruct { StartToken = Token.Info, SizeUncompressed = bytesToWrite.Length, SizeCompressed = doCompress ? 1 : 0, FileTime = fileTime.Value.ToFileTime(), NameHash = Crypt.GetStringSHA1UInt32(fileName), DirectoryHash = Crypt.GetStringSHA1UInt32(directory), First4BytesOfFile = FileTools.ByteArrayToInt32(bytesToWrite, 0), Second4BytesOfFile = FileTools.ByteArrayToInt32(bytesToWrite, 4), EndToken = Token.Info, }; PackFileEntry fileEntry = new FileEntry(fileStruct); fileEntry.Directory = directory; fileEntry.Name = fileName; Files.Add(fileEntry); _AddFileToDat(bytesToWrite, fileEntry); // todo: create new applicable file entry object as well? // todo: remove existing file bytes if applicable... return true; }
public void AddFileQuick(string filein, string path) { BitConverter.IsLittleEndian = true; string DLCPath = MyFileName; FileStream fs = new FileStream(DLCPath, FileMode.OpenOrCreate, FileAccess.ReadWrite); byte[] FileIN = File.ReadAllBytes(filein); //Create Entry List<FileEntryStruct> tmp = new List<FileEntryStruct>(Files); FileEntryStruct e = new FileEntryStruct(); e.FileName = path; e.BlockOffsets = new long[0]; e.Hash = ComputeHash(path); e.BlockSizeIndex = 0xFFFFFFFF; e.UncompressedSize = (uint)FileIN.Length; e.UncompressedSizeAdder = 0; tmp.Add(e); e = new FileEntryStruct(); Files = tmp.ToArray(); // //Find TOC DebugOutput.PrintLn("Searching TOC..."); int f = FindTOC(); if (f == -1) return; DebugOutput.PrintLn("Found TOC, adding line..."); MemoryStream m = DecompressEntry(f, fs); // //Update TOC WriteString(m, path); m.WriteByte(0xD); m.WriteByte(0xA); // //Append new FileTable int count = (int)Header.FileCount +1; long oldsize = fs.Length; long offset = oldsize; DebugOutput.PrintLn("File End Offset : 0x" + offset.ToString("X10")); fs.Seek(oldsize, 0); Header.EntryOffset = (uint)offset; for (int i = 0; i < count; i++) { e = Files[i]; fs.Write(e.Hash, 0, 16); fs.Write(BitConverter.GetBytes(e.BlockSizeIndex), 0, 4); fs.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); fs.WriteByte(e.UncompressedSizeAdder); fs.Write(BitConverter.GetBytes(e.DataOffset), 0, 4); fs.WriteByte(e.DataOffsetAdder); } offset += count * 0x1E; DebugOutput.PrintLn("Table End Offset : 0x" + offset.ToString("X10")); Header.BlockTableOffset = (uint)offset; // //Append blocktable for (int i = 0; i < count; i++) { e = Files[i]; if (e.BlockSizeIndex != 0xFFFFFFFF && i != f) foreach(ushort u in e.BlockSizes) fs.Write(BitConverter.GetBytes(u), 0, 2); } offset = fs.Length; DebugOutput.PrintLn("Block Table End Offset : 0x" + offset.ToString("X10")); long dataoffset = offset; fs.Write(FileIN, 0, FileIN.Length); offset += FileIN.Length; DebugOutput.PrintLn("New Data End Offset : 0x" + offset.ToString("X10")); // //Append TOC long tocoffset = offset; fs.Write(m.ToArray(), 0, (int)m.Length); offset = fs.Length; DebugOutput.PrintLn("New TOC Data End Offset : 0x" + offset.ToString("X10")); //update filetable fs.Seek(oldsize, 0); uint blocksizeindex = 0; for (int i = 0; i < count; i++) { e = Files[i]; fs.Write(e.Hash, 0, 16); if (e.BlockSizeIndex == 0xFFFFFFFF || i==f) fs.Write(BitConverter.GetBytes((int)-1), 0, 4); else { fs.Write(BitConverter.GetBytes(blocksizeindex), 0, 4); e.BlockSizeIndex = (uint)blocksizeindex; blocksizeindex += (uint)e.BlockSizes.Length; Files[i] = e; } if (i == f) { fs.Write(BitConverter.GetBytes(m.Length), 0, 4); fs.WriteByte(0); fs.Write(BitConverter.GetBytes(tocoffset), 0, 4); byte b = (byte)((tocoffset & 0xFF00000000) >> 32); fs.WriteByte(b); } else if (i == count - 1) { fs.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); fs.WriteByte(0); fs.Write(BitConverter.GetBytes(dataoffset), 0, 4); byte b = (byte)((dataoffset & 0xFF00000000) >> 32); fs.WriteByte(b); } else { fs.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); fs.WriteByte(e.UncompressedSizeAdder); fs.Write(BitConverter.GetBytes(e.DataOffset), 0, 4); fs.WriteByte(e.DataOffsetAdder); } } //Update Header fs.Seek(0xC, 0); fs.Write(BitConverter.GetBytes(Header.EntryOffset), 0, 4); fs.Write(BitConverter.GetBytes(count), 0, 4); fs.Write(BitConverter.GetBytes(Header.BlockTableOffset), 0, 4); // fs.Close(); }
public void AddFileQuick(string filein, string path) { string DLCPath = FileName; FileStream fs = new FileStream(DLCPath, FileMode.OpenOrCreate, FileAccess.ReadWrite); byte[] FileIN = File.ReadAllBytes(filein); //Create Entry List <FileEntryStruct> tmp = new List <FileEntryStruct>(Files); FileEntryStruct e = new FileEntryStruct(); e.FileName = path; e.BlockOffsets = new long[0]; e.Hash = ComputeHash(path); e.BlockSizeTableIndex = 0xFFFFFFFF; e.UncompressedSize = (uint)FileIN.Length; e.UncompressedSizeAdder = 0; tmp.Add(e); e = new FileEntryStruct(); Files.ReplaceAll(tmp); // //Find TOC Debug.WriteLine("Searching TOC..."); int f = FindTOC(); if (f == -1) { return; } Debug.WriteLine("Found TOC, adding line..."); MemoryStream m = DecompressEntry(f, fs); // //Update TOC WriteString(m, path); m.WriteByte(0xD); m.WriteByte(0xA); // //Append new FileTable int count = (int)Header.FileCount + 1; long oldsize = fs.Length; long offset = oldsize; Debug.WriteLine("File End Offset : 0x" + offset.ToString("X10")); fs.Seek(oldsize, 0); Header.EntryOffset = (uint)offset; for (int i = 0; i < count; i++) { e = Files[i]; fs.Write(e.Hash, 0, 16); fs.Write(BitConverter.GetBytes(e.BlockSizeTableIndex), 0, 4); fs.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); fs.WriteByte(e.UncompressedSizeAdder); fs.Write(BitConverter.GetBytes(e.DataOffset), 0, 4); fs.WriteByte(e.DataOffsetAdder); } offset += count * 0x1E; Debug.WriteLine("Table End Offset : 0x" + offset.ToString("X10")); Header.BlockTableOffset = (uint)offset; // //Append blocktable for (int i = 0; i < count; i++) { e = Files[i]; if (e.BlockSizeTableIndex != 0xFFFFFFFF && i != f) { foreach (ushort u in e.BlockSizes) { fs.Write(BitConverter.GetBytes(u), 0, 2); } } } offset = fs.Length; Debug.WriteLine("Block Table End Offset : 0x" + offset.ToString("X10")); long dataoffset = offset; fs.Write(FileIN, 0, FileIN.Length); offset += FileIN.Length; Debug.WriteLine("New Data End Offset : 0x" + offset.ToString("X10")); // //Append TOC long tocoffset = offset; fs.Write(m.ToArray(), 0, (int)m.Length); offset = fs.Length; Debug.WriteLine("New TOC Data End Offset : 0x" + offset.ToString("X10")); //update filetable fs.Seek(oldsize, 0); uint blocksizeindex = 0; for (int i = 0; i < count; i++) { e = Files[i]; fs.Write(e.Hash, 0, 16); if (e.BlockSizeTableIndex == 0xFFFFFFFF || i == f) { fs.Write(BitConverter.GetBytes(-1), 0, 4); } else { fs.Write(BitConverter.GetBytes(blocksizeindex), 0, 4); e.BlockSizeTableIndex = blocksizeindex; blocksizeindex += (uint)e.BlockSizes.Length; Files[i] = e; } if (i == f) { fs.Write(BitConverter.GetBytes(m.Length), 0, 4); fs.WriteByte(0); fs.Write(BitConverter.GetBytes(tocoffset), 0, 4); byte b = (byte)((tocoffset & 0xFF00000000) >> 32); fs.WriteByte(b); } else if (i == count - 1) { fs.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); fs.WriteByte(0); fs.Write(BitConverter.GetBytes(dataoffset), 0, 4); byte b = (byte)((dataoffset & 0xFF00000000) >> 32); fs.WriteByte(b); } else { fs.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); fs.WriteByte(e.UncompressedSizeAdder); fs.Write(BitConverter.GetBytes(e.DataOffset), 0, 4); fs.WriteByte(e.DataOffsetAdder); } } //Update Header fs.Seek(0xC, 0); fs.Write(BitConverter.GetBytes(Header.EntryOffset), 0, 4); fs.Write(BitConverter.GetBytes(count), 0, 4); fs.Write(BitConverter.GetBytes(Header.BlockTableOffset), 0, 4); // fs.Close(); }
public MemoryStream DecompressEntry(FileEntryStruct e) { //Debug.WriteLine("Decompressing " + e.FileName); MemoryStream result = new MemoryStream(); uint count = 0; byte[] inputBlock; long left = e.RealUncompressedSize; FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read); fs.Seek(e.BlockOffsets[0], SeekOrigin.Begin); byte[] buff; if (e.BlockSizeTableIndex == 0xFFFFFFFF) { buff = new byte[e.RealUncompressedSize]; fs.Read(buff, 0, buff.Length); result.Write(buff, 0, buff.Length); } else { while (left > 0) { uint compressedBlockSize = e.BlockSizes[count]; if (compressedBlockSize == 0) { compressedBlockSize = Header.MaxBlockSize; } if (compressedBlockSize == Header.MaxBlockSize || compressedBlockSize == left) { //uncompressed? buff = new byte[compressedBlockSize]; fs.Read(buff, 0, buff.Length); result.Write(buff, 0, buff.Length); left -= compressedBlockSize; } else { var uncompressedBlockSize = (uint)Math.Min(left, Header.MaxBlockSize); if (compressedBlockSize < 5) { throw new Exception("compressed block size smaller than 5"); } inputBlock = new byte[compressedBlockSize]; //Debug.WriteLine($"Decompressing at 0x{fs.Position:X8}"); fs.Read(inputBlock, 0, (int)compressedBlockSize); uint actualUncompressedBlockSize = uncompressedBlockSize; if (Header.CompressionScheme == "amzl" /* PC */ || Header.CompressionScheme == "lzma" /* PS3 (it doesn't appear to actually be LZMA!), WiiU */) { //if (Header.CompressionScheme == "lzma") //{ //PS3 - This doesn't work. I'm not sure what kind of LZMA this uses but it has seemingly no header //var attachedHeader = new byte[inputBlock.Length + 5]; //attachedHeader[0] = 0x5D; ////attachedHeader[1] = (byte) (Header.Version >> 24); ////attachedHeader[2] = (byte)(Header.Version >> 16); ////attachedHeader[3] = (byte)(Header.Version >> 8); ////attachedHeader[4] = (byte) Header.Version; //attachedHeader[1] = (byte)Header.Version; //attachedHeader[2] = (byte)(Header.Version >> 8); //attachedHeader[3] = (byte)(Header.Version >> 16); //attachedHeader[4] = (byte)(Header.Version >> 24); //Buffer.BlockCopy(inputBlock,0,attachedHeader,5, inputBlock.Length); //inputBlock = attachedHeader; //} var outputBlock = LZMA.Decompress(inputBlock, actualUncompressedBlockSize); if (outputBlock.Length != actualUncompressedBlockSize) { throw new Exception("SFAR LZMA Decompression Error"); } result.Write(outputBlock, 0, (int)actualUncompressedBlockSize); left -= uncompressedBlockSize; //continue; } if (Header.CompressionScheme == "lzx") //Xbox { var outputBlock = new byte[actualUncompressedBlockSize]; var decompResult = LZX.Decompress(inputBlock, (uint)inputBlock.Length, outputBlock); if (decompResult != 0) { throw new Exception("SFAR LZX Decompression Error"); } result.Write(outputBlock, 0, (int)actualUncompressedBlockSize); left -= uncompressedBlockSize; } } count++; } } fs.Close(); result.Position = 0; return(result); }
public void ReBuild() { string path = Path.Combine(Path.GetDirectoryName(FileName), Path.GetFileNameWithoutExtension(FileName) + ".tmp"); FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write); Debug.WriteLine("Creating Header Dummy..."); for (int i = 0; i < 8; i++) { fs.Write(BitConverter.GetBytes(0), 0, 4); } Header.EntryOffset = 0x20; Debug.WriteLine("Creating File Table..."); for (int i = 0; i < Header.FileCount; i++) { FileEntryStruct e = Files[i]; fs.Write(e.Hash, 0, 16); fs.Write(BitConverter.GetBytes(e.BlockSizeTableIndex), 0, 4); fs.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); fs.WriteByte(e.UncompressedSizeAdder); fs.Write(BitConverter.GetBytes(e.DataOffset), 0, 4); fs.WriteByte(e.DataOffsetAdder); } Header.BlockTableOffset = (uint)fs.Position; Debug.WriteLine("Creating Block Table..."); for (int i = 0; i < Header.FileCount; i++) { if (Files[i].BlockSizeTableIndex != 0xFFFFFFFF) { foreach (ushort u in Files[i].BlockSizes) { fs.Write(BitConverter.GetBytes(u), 0, 2); } } } Header.DataOffset = (uint)fs.Position; Debug.WriteLine("Appending Files..."); uint pos = (uint)fs.Position; for (int i = 0; i < Header.FileCount; i++) { List <byte[]> blocks = GetBlocks(i); FileEntryStruct e = Files[i]; Debug.WriteLine("Rebuilding \"" + e.FileName + "\" (" + (i + 1) + "/" + Header.FileCount + ") " + BytesToString(e.UncompressedSize) + " ..."); e.DataOffset = pos; e.DataOffsetAdder = 0; for (int j = 0; j < blocks.Count; j++) { MemoryStream m = new MemoryStream(blocks[j]); fs.Write(m.ToArray(), 0, (int)m.Length); pos += (uint)m.Length; } Files[i] = e; } Debug.WriteLine("Updating FileTable..."); fs.Seek(0x20, 0); pos = (uint)fs.Position; uint blocksizeindex = 0; for (int i = 0; i < Header.FileCount; i++) { FileEntryStruct e = Files[i]; fs.Write(e.Hash, 0, 16); if (e.BlockSizeTableIndex != 0xFFFFFFFF) { fs.Write(BitConverter.GetBytes(blocksizeindex), 0, 4); e.BlockSizeTableIndex = blocksizeindex; blocksizeindex += (uint)e.BlockSizes.Length; } else { fs.Write(BitConverter.GetBytes(0xFFFFFFFF), 0, 4); } fs.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); fs.WriteByte(e.UncompressedSizeAdder); fs.Write(BitConverter.GetBytes(e.DataOffset), 0, 4); fs.WriteByte(e.DataOffsetAdder); e.MyOffset = pos; Files[i] = e; pos += 0x1E; } fs.Seek(0, 0); Debug.WriteLine("Rebuilding Header..."); //magic fs.Write(BitConverter.GetBytes(0x53464152), 0, 4); fs.Write(BitConverter.GetBytes(Header.Version), 0, 4); fs.Write(BitConverter.GetBytes(Header.DataOffset), 0, 4); fs.Write(BitConverter.GetBytes(Header.EntryOffset), 0, 4); fs.Write(BitConverter.GetBytes(Header.FileCount), 0, 4); fs.Write(BitConverter.GetBytes(Header.BlockTableOffset), 0, 4); fs.Write(BitConverter.GetBytes(Header.MaxBlockSize), 0, 4); foreach (char c in Header.CompressionScheme) { fs.WriteByte((byte)c); } fs.Close(); File.Delete(FileName); File.Move(path, FileName); }
public MemoryStream DecompressEntry(int index, FileStream fs) { FileEntryStruct e = Files[index]; //MemoryStream result = new MemoryStream((int)e.RealUncompressedSize); MemoryStream result = MixinHandler.MixinMemoryStreamManager.GetStream(); uint count = 0; byte[] inputBlock; byte[] outputBlock = new byte[Header.MaxBlockSize]; long left = e.RealUncompressedSize; fs.Seek(e.BlockOffsets[0], SeekOrigin.Begin); byte[] buff; if (e.BlockSizeIndex == 0xFFFFFFFF) { buff = new byte[e.RealUncompressedSize]; fs.Read(buff, 0, buff.Length); result.Write(buff, 0, buff.Length); } else { //Compressed while (left > 0) { uint compressedBlockSize = e.BlockSizes[count]; if (compressedBlockSize == 0) { compressedBlockSize = Header.MaxBlockSize; } if (compressedBlockSize == Header.MaxBlockSize || compressedBlockSize == left) { buff = new byte[compressedBlockSize]; fs.Read(buff, 0, buff.Length); result.Write(buff, 0, buff.Length); left -= compressedBlockSize; } else { var uncompressedBlockSize = (uint)Math.Min(left, Header.MaxBlockSize); if (compressedBlockSize < 5) { throw new Exception("compressed block size smaller than 5"); } inputBlock = new byte[compressedBlockSize]; fs.Read(inputBlock, 0, (int)compressedBlockSize); uint actualUncompressedBlockSize = uncompressedBlockSize; uint actualCompressedBlockSize = compressedBlockSize; outputBlock = SevenZipHelper.LZMA.Decompress(inputBlock, actualUncompressedBlockSize); if (outputBlock.Length != actualUncompressedBlockSize) { throw new Exception("Decompression Error"); } result.Write(outputBlock, 0, (int)actualUncompressedBlockSize); left -= uncompressedBlockSize; } count++; } } return(result); }
public FileEntry(FileEntryStruct fileEntryStruct) { _fileEntryStruct = fileEntryStruct; }
public MemoryStream DecompressEntry(int Index, FileStream fs) { MemoryStream result = new MemoryStream(); FileEntryStruct e = Files[Index]; uint count = 0; byte[] inputBlock; byte[] outputBlock = new byte[Header.MaxBlockSize]; long left = e.RealUncompressedSize; fs.Seek(e.BlockOffsets[0], SeekOrigin.Begin); byte[] buff; if (e.BlockSizeIndex == 0xFFFFFFFF) { buff = new byte[e.RealUncompressedSize]; fs.Read(buff, 0, buff.Length); result.Write(buff, 0, buff.Length); } else { while (left > 0) { uint compressedBlockSize = (uint)e.BlockSizes[count]; if (compressedBlockSize == 0) { compressedBlockSize = Header.MaxBlockSize; } if (compressedBlockSize == Header.MaxBlockSize || compressedBlockSize == left) { buff = new byte[compressedBlockSize]; fs.Read(buff, 0, buff.Length); result.Write(buff, 0, buff.Length); left -= compressedBlockSize; } else { var uncompressedBlockSize = (uint)Math.Min(left, Header.MaxBlockSize); if (compressedBlockSize < 5) { DebugLog.PrintLn("DLCPACKAGE::DECOMPRESSENTRY ERROR:compressed block size smaller than 5"); break; } inputBlock = new byte[compressedBlockSize]; fs.Read(inputBlock, 0, (int)compressedBlockSize); uint actualUncompressedBlockSize = uncompressedBlockSize; uint actualCompressedBlockSize = compressedBlockSize; outputBlock = SevenZipHelper.Decompress(inputBlock, (int)actualUncompressedBlockSize); if (outputBlock.Length != actualUncompressedBlockSize) { DebugLog.PrintLn("DLCPACKAGE::DECOMPRESSENTRY ERROR:Decompression Error"); break; } result.Write(outputBlock, 0, (int)actualUncompressedBlockSize); left -= uncompressedBlockSize; } count++; } } fs.Close(); return(result); }
public void AddFileQuick(string onDiskNewFile, string inArchivePath) { byte[] newFileBytes; if (Path.GetExtension(onDiskNewFile).ToLower() == @".pcc" && FileName.EndsWith(@"Patch_001.sfar", StringComparison.InvariantCultureIgnoreCase)) { //Use the decompressed bytes - SFARs can't store compressed packages apparently! var package = MEPackageHandler.OpenMEPackage(onDiskNewFile); newFileBytes = package.saveToStream().ToArray(); } else { newFileBytes = File.ReadAllBytes(onDiskNewFile); } FileStream sfarStream = new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite); //Create Entry List <FileEntryStruct> tmp = new List <FileEntryStruct>(Files); FileEntryStruct e = new FileEntryStruct(); e.FileName = inArchivePath; e.BlockOffsets = new long[0]; e.Hash = ComputeHash(inArchivePath); e.BlockSizeIndex = 0xFFFFFFFF; e.UncompressedSize = (uint)newFileBytes.Length; e.UncompressedSizeAdder = 0; tmp.Add(e); Files = tmp.ToArray(); // //Find TOC int f = findTOCIndex(); if (f == -1) { return; } MemoryStream tocMemory = DecompressEntry(f, sfarStream); // //No idea what most of the rest of this stuff is so i probably shouldn't change it //Update TOC tocMemory.WriteStringASCII(inArchivePath); tocMemory.WriteByte(0xD); tocMemory.WriteByte(0xA); // //Append new FileTable int count = (int)Header.FileCount + 1; long oldsize = sfarStream.Length; long offset = oldsize; //Debug.WriteLine("File End Offset : 0x" + offset.ToString("X10")); sfarStream.Seek(oldsize, 0); Header.EntryOffset = (uint)offset; for (int i = 0; i < count; i++) { e = Files[i]; sfarStream.Write(e.Hash, 0, 16); sfarStream.Write(BitConverter.GetBytes(e.BlockSizeIndex), 0, 4); sfarStream.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); sfarStream.WriteByte(e.UncompressedSizeAdder); sfarStream.Write(BitConverter.GetBytes(e.DataOffset), 0, 4); sfarStream.WriteByte(e.DataOffsetAdder); } offset += count * 0x1E; //Debug.WriteLine("Table End Offset : 0x" + offset.ToString("X10")); Header.BlockTableOffset = (uint)offset; // //Append blocktable for (int i = 0; i < count; i++) { e = Files[i]; if (e.BlockSizeIndex != 0xFFFFFFFF && i != f) { foreach (ushort u in e.BlockSizes) { sfarStream.Write(BitConverter.GetBytes(u), 0, 2); } } } offset = sfarStream.Length; //Debug.WriteLine("Block Table End Offset : 0x" + offset.ToString("X10")); long dataoffset = offset; sfarStream.Write(newFileBytes, 0, newFileBytes.Length); offset += newFileBytes.Length; //Debug.WriteLine("New Data End Offset : 0x" + offset.ToString("X10")); // //Append TOC long tocoffset = offset; sfarStream.Write(tocMemory.ToArray(), 0, (int)tocMemory.Length); offset = sfarStream.Length; //Debug.WriteLine("New TOC Data End Offset : 0x" + offset.ToString("X10")); //update filetable sfarStream.Seek(oldsize, 0); uint blocksizeindex = 0; for (int i = 0; i < count; i++) { e = Files[i]; sfarStream.Write(e.Hash, 0, 16); if (e.BlockSizeIndex == 0xFFFFFFFF || i == f) { sfarStream.Write(BitConverter.GetBytes(-1), 0, 4); } else { sfarStream.Write(BitConverter.GetBytes(blocksizeindex), 0, 4); e.BlockSizeIndex = blocksizeindex; blocksizeindex += (uint)e.BlockSizes.Length; Files[i] = e; } if (i == f) { sfarStream.Write(BitConverter.GetBytes(tocMemory.Length), 0, 4); sfarStream.WriteByte(0); sfarStream.Write(BitConverter.GetBytes(tocoffset), 0, 4); byte b = (byte)((tocoffset & 0xFF00000000) >> 32); sfarStream.WriteByte(b); } else if (i == count - 1) { sfarStream.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); sfarStream.WriteByte(0); sfarStream.Write(BitConverter.GetBytes(dataoffset), 0, 4); byte b = (byte)((dataoffset & 0xFF00000000) >> 32); sfarStream.WriteByte(b); } else { sfarStream.Write(BitConverter.GetBytes(e.UncompressedSize), 0, 4); sfarStream.WriteByte(e.UncompressedSizeAdder); sfarStream.Write(BitConverter.GetBytes(e.DataOffset), 0, 4); sfarStream.WriteByte(e.DataOffsetAdder); } } //Update Header sfarStream.Seek(0xC, 0); sfarStream.Write(BitConverter.GetBytes(Header.EntryOffset), 0, 4); sfarStream.Write(BitConverter.GetBytes(count), 0, 4); sfarStream.Write(BitConverter.GetBytes(Header.BlockTableOffset), 0, 4); // sfarStream.Close(); }