/// <summary> /// Extracts and uncompresses, when neccessary, all the loaded entries in an archive /// to the specified path. Assumes that LoadArchive() has been called first. /// </summary> /// <param name="Path">The path to extract to.</param> public void ExtractFiles(string Path) { BinaryReader Reader = new BinaryReader(File.Open(m_ArchiveName, FileMode.Open)); foreach (DBPFEntry Entry in m_Entries) { Reader.BaseStream.Seek(Entry.FileOffset, SeekOrigin.Begin); if (Entry.Compressed) { Entry.FileData = new byte[Entry.DecompressedSize]; Decompress(Reader, Entry); } } } private void Decompress(BinaryReader Reader, DBPFEntry Entry) { uint CompressedSize = Reader.ReadUInt32(); ushort CompressionID = Reader.ReadUInt16(); Reader.ReadBytes(3); //Uncompressed size of file... int NumPlainChars = 0; int NumCopy = 0; int Offset = 0; string Answer = ""; if (CompressionID == 0xFB10 || CompressionID == 0xFB50) { uint Length = Entry.FileSize; for (; Length > 0;) { //Control character byte CC = Reader.ReadByte(); Length -= 1; if (CC >= 252) //0xFC { NumPlainChars = CC & 0x03; if (NumPlainChars > Length) NumPlainChars = (int)Length; NumCopy = 0; Offset = 0; } else if (CC >= 224) //0xE0 { NumPlainChars = (CC - 0xDF) << 2; NumCopy = 0; Offset = 0; } else if (CC >= 192) //0xC0 { Length -= 3; char Byte1 = Reader.ReadChar(); char Byte2 = Reader.ReadChar(); char Byte3 = Reader.ReadChar(); NumPlainChars = CC & 0x03; NumCopy = ((CC & 0x0C) << 6) + 5 + Byte3; Offset = ((CC & 0x10) << 12 ) + (Byte1 << 8) + Byte2; } else if (CC >= 128) //0x80 { Length -= 2; char Byte1 = Reader.ReadChar(); char Byte2 = Reader.ReadChar(); NumPlainChars = (Byte1 & 0xC0) >> 6; NumCopy = (CC & 0x3F) + 4; Offset = ((Byte1 & 0x3F) << 8) + Byte2; } else { Length -= 1; char Byte1 = Reader.ReadChar(); NumPlainChars = (CC & 0x03); NumCopy = ((CC & 0x1C) >> 2) + 3; Offset = ((CC & 0x60) << 3) + Byte1; } if (NumPlainChars > 0) { string Tmp = new string(Reader.ReadChars(NumPlainChars)); Answer += Tmp; } int FromOffset = Answer.Length - (Offset + 1); for (int i = 0; i < NumCopy; i++) { if(((FromOffset + i) < Answer.Length) && ((FromOffset + i) > 0)) Answer = Answer.Substring(FromOffset + i, 1); } } } else return; }
private byte[] Deflate(DBPFEntry Entry) { Stream S = new InflaterInputStream(new MemoryStream(Entry.FileData), new ICSharpCode.SharpZipLib.Zip.Compression.Inflater(true)); MemoryStream MemStream = new MemoryStream(); int SizeRead = 0; byte[] Buffer = new byte[2048]; while (true) { SizeRead = S.Read(Buffer, 0, 2048); if (SizeRead > 0) MemStream.Write(Buffer, 0, 2048); else break; } return MemStream.ToArray(); }
/// <summary> /// Extracts and uncompresses, when neccessary, all the loaded entries in an archive /// to the specified path. Assumes that LoadArchive() has been called first. /// </summary> /// <param name="Path">The path to extract to.</param> public void ExtractFiles(string Path) { BinaryReader Reader = new BinaryReader(File.Open(m_ArchiveName, FileMode.Open)); for(int i = 0; i < m_Entries.Count; i++) { Reader.BaseStream.Seek(m_Entries[i].FileOffset, SeekOrigin.Begin); if (m_Entries[i].Compressed) { m_Entries[i].FileData = new byte[m_Entries[i].DecompressedSize]; Reader.BaseStream.Seek(m_Entries[i].FileOffset, SeekOrigin.Begin); m_Entries[i].FileData = Reader.ReadBytes((int)m_Entries[i].FileSize); m_Entries[i] = Decompress(new BinaryReader(new MemoryStream(m_Entries[i].FileData)), m_Entries[i]); if (m_Entries[i] != null) { BinaryWriter Writer = new BinaryWriter(File.Create(Path + m_Entries[i].InstanceID.ToString() + "." + m_Entries[i].GetFileExtension())); Writer.Write(m_Entries[i].FileData); Writer.Close(); } } } } private DBPFEntry Decompress(BinaryReader Reader, DBPFEntry Entry) { uint CompressedSize = Reader.ReadUInt32(); ushort CompressionID = Reader.ReadUInt16(); Reader.ReadBytes(3); //Uncompressed size of file... int NumPlainChars = 0; int NumCopy = 0; int Offset = 0; MemoryStream Answer = new MemoryStream(); BinaryWriter Writer = new BinaryWriter(Answer); if (CompressionID == 0xFB10 || CompressionID == 0xFB50) { bool Stop = false; while(!Stop) { //Control character byte CC = Reader.ReadByte(); if (CC >= 252) //0xFC { NumPlainChars = CC & 0x03; if (NumPlainChars > Reader.BaseStream.Length) NumPlainChars = (int)Reader.BaseStream.Length; NumCopy = 0; Offset = 0; Stop = true; } else if (CC >= 224) //0xE0 { NumPlainChars = (CC - 0xDF) << 2; NumCopy = 0; Offset = 0; } else if (CC >= 192) //0xC0 { byte Byte1 = Reader.ReadByte(); byte Byte2 = Reader.ReadByte(); byte Byte3 = Reader.ReadByte(); NumPlainChars = CC & 0x03; NumCopy = ((CC & 0x0C) << 6) + 5 + Byte3; Offset = ((CC & 0x10) << 12 ) + (Byte1 << 8) + Byte2; } else if (CC >= 128) //0x80 { byte Byte1 = Reader.ReadByte(); byte Byte2 = Reader.ReadByte(); NumPlainChars = (Byte1 & 0xC0) >> 6; NumCopy = (CC & 0x3F) + 4; Offset = ((Byte1 & 0x3F) << 8) + Byte2; } else { byte Byte1 = Reader.ReadByte(); NumPlainChars = (CC & 0x03); NumCopy = ((CC & 0x1C) >> 2) + 3; Offset = ((CC & 0x60) << 3) + Byte1; } if (NumPlainChars > 0) Writer.Write(Reader.ReadBytes(NumPlainChars)); long FromOffset = Answer.Length - (Offset + 1); for (int i = 0; i < NumCopy; i++) { //Answer += Answer.Substring(FromOffset + i, 1); Writer.Write(BinarySubstring(Reader, FromOffset + i, 1)); } } Entry.FileData = Answer.ToArray(); Writer.Close(); Reader.Close(); } else return null; return Entry; } private byte[] BinarySubstring(BinaryReader Reader, long Offset, int NumBytes) { long CurrentOffset = Reader.BaseStream.Position; Reader.BaseStream.Seek(Offset, SeekOrigin.End); byte[] Data = Reader.ReadBytes(NumBytes); Reader.BaseStream.Seek(CurrentOffset, SeekOrigin.Begin); return Data; }
Version 3The Sims Online (TSO) introduces a new version of the FAR format. This format is FAR, version 3. This format has not been completely reversed yet, so most of the details below are not set in stone.Header * Signature - An eight byte string, consisting of the characters 'FAR!byAZ' (without quotes). * Version - A byte signifying the version of the archive. Should be 3. * Unknown - Three bytes of 0. * Manifest offset - a 4 byte integer specifying the offset to manifest of the archive (from the beginning of the file), where offsets to every entry are kept.Manifest * Number of files - A 4 byte integer specifying the number of files in the archive. * Manifest Entries - As many manifest entries as stated by the previous integer]Manifest entry * Raw Size - The uncompressed size of the filedata, stored as a UInt32 (4 bytes). * Compressed Size - The compressed size of the file. FAR V. 3 seems to support compression. Will be the same as the first field if the file is not compressed. This seems to be a UInt16 (2 bytes). * Offset - The offset of the filedata in the file. Could possibly be a UInt32, but seems to be a UInt16 (2 bytes). * Unknown - 17 bytes of an unknown purpose. * Filename - A string representing the filename of the file(data). Seems to be null-terminated.