public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); _values = new QbKey[base.ItemCount]; uint crc; string debug; for (int i = 0; i < base.ItemCount; i++) { crc = br.ReadUInt32(base.Root.PakFormat.EndianType); debug = this.Root.LookupDebugName(crc); if (debug.Length != 0) { _values[i] = QbKey.Create(crc, debug); } else { _values[i] = QbKey.Create(crc); } } base.ConstructEnd(br); }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); QbItemBase qib; QbItemType headerType; uint headerValue; for (int i = 0; i < base.ItemCount; i++) { if (base.StreamPos(br) != base.Pointers[i]) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[i])); } headerValue = br.ReadUInt32(this.Root.PakFormat.EndianType); headerType = this.Root.PakFormat.GetQbItemType(headerValue); switch (headerType) { case QbItemType.StructHeader: qib = new QbItemStruct(this.Root); break; default: throw new ApplicationException(string.Format("Location 0x{0}: Not a struct header type 0x{1}", (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'), headerValue.ToString("X").PadLeft(8, '0'))); } qib.Construct(br, headerType); AddItem(qib); } base.ConstructEnd(br); }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); _unknown = br.ReadUInt32(base.Root.PakFormat.EndianType); uint decompressedSize = br.ReadUInt32(base.Root.PakFormat.EndianType); uint compressedSize = br.ReadUInt32(base.Root.PakFormat.EndianType); // Get script data Lzss lz = new Lzss(); _scriptData = br.ReadBytes((int)compressedSize); if (compressedSize < decompressedSize) { _scriptData = lz.Decompress(_scriptData); } if (_scriptData.Length != decompressedSize) { throw new ApplicationException(string.Format("Location 0x{0}: Script decompressed to {1} bytes not {2}", (base.StreamPos(br) - compressedSize).ToString("X").PadLeft(8, '0'), _scriptData.Length.ToString(), decompressedSize.ToString())); } // Padding... if ((base.StreamPos(br) % 4) != 0) { br.BaseStream.Seek(4 - (base.StreamPos(br) % 4), SeekOrigin.Current); } base.ConstructEnd(br); }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); QbItemBase qib; QbItemType floatsType; uint floatsValue; bool is3d; for (int i = 0; i < base.ItemCount; i++) { if (base.StreamPos(br) != base.Pointers[i]) //pointer test throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[i])); floatsValue = br.ReadUInt32(this.Root.PakFormat.EndianType); floatsType = this.Root.PakFormat.GetQbItemType(floatsValue); is3d = (type == QbItemType.SectionFloatsX3 || type == QbItemType.StructItemFloatsX3 || type == QbItemType.ArrayFloatsX3); switch (floatsType) { case QbItemType.Floats: qib = new QbItemFloats(this.Root, is3d); break; default: throw new ApplicationException(string.Format("Location 0x{0}: Not a float type 0x{1}", (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'), floatsValue.ToString("X").PadLeft(8, '0'))); } qib.Construct(br, floatsType); AddItem(qib); base.ConstructEnd(br); } }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); QbItemBase qib = null; QbItemType arrayType; uint arrayValue; for (int i = 0; i < base.ItemCount; i++) { arrayValue = br.ReadUInt32(this.Root.PakFormat.EndianType); arrayType = this.Root.PakFormat.GetQbItemType(arrayValue); switch (arrayType) { case QbItemType.Floats: qib = new QbItemFloats(this.Root); break; case QbItemType.ArrayStruct: qib = new QbItemStructArray(this.Root); break; case QbItemType.ArrayFloat: qib = new QbItemFloat(this.Root); break; case QbItemType.ArrayString: case QbItemType.ArrayStringW: qib = new QbItemString(this.Root); break; case QbItemType.ArrayFloatsX2: case QbItemType.ArrayFloatsX3: qib = new QbItemFloatsArray(this.Root); break; case QbItemType.ArrayStringPointer: case QbItemType.ArrayInteger: qib = new QbItemInteger(this.Root); break; case QbItemType.ArrayArray: qib = new QbItemArray(this.Root); break; case QbItemType.ArrayQbKey: case QbItemType.ArrayQbKeyString: case QbItemType.ArrayQbKeyStringQs: //GH:GH qib = new QbItemQbKey(this.Root); break; case QbItemType.StructHeader: qib = new QbItemStruct(this.Root); break; default: throw new ApplicationException(string.Format("Location 0x{0}: Unknown array type 0x{1}", (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'), arrayValue.ToString("X").PadLeft(8, '0'))); } qib.Construct(br, arrayType); AddItem(qib); } base.ConstructEnd(br); }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); this.Values = new uint[base.ItemCount]; for (int i = 0; i < base.ItemCount; i++) _values[i] = br.ReadUInt32(base.Root.PakFormat.EndianType); base.ConstructEnd(br); }
/// <summary> /// Pass null for br if the data was passed as a byte array in the constructor /// </summary> /// <param name="br"></param> /// <param name="type"></param> public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x????????", this.GetType().ToString())); if (br != null) { base.Construct(br, type); //base.Position = (uint)base.StreamPos(br); _unknownData = br.ReadBytes(_length); base.ConstructEnd(br); } }
/// <summary> /// Call after derived class has read its data in Construct() /// </summary> /// <param name="br"></param> public virtual void ConstructEnd(BinaryEndianReader br) { #region switch switch (_qbFormat) { case QbFormat.SectionValue: //Simple section type: // ItemId, FileId, Value, Reserved _reserved = br.ReadUInt32(this.Root.PakFormat.EndianType); _length += (1 * 4); break; case QbFormat.StructItemPointer: if (_nextItemPointer != 0 && this.StreamPos(br) != _nextItemPointer) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _nextItemPointer)); } break; case QbFormat.StructItemValue: //Simple struct type: // ItemId, Value (4 byte), NextItemPointer _nextItemPointer = br.ReadUInt32(this.Root.PakFormat.EndianType); _length += (1 * 4); if (_nextItemPointer != 0 && this.StreamPos(br) != _nextItemPointer) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _nextItemPointer)); } break; case QbFormat.ArrayPointer: //Complex array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) for (int i = 0; i < _items.Count; i++) //_items.Count is 0 for strings (it checks it's own) { if (_pointers[i] != _items[i].Position) { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, _items[i].Position, _pointers[i])); } } break; default: break; } #endregion setChildMode(); //_itemCount = (uint)this.CalcItemCount(); }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); this.Values = new int[base.ItemCount]; for (int i = 0; i < base.ItemCount; i++) { _values[i] = br.ReadInt32(base.Root.PakFormat.EndianType); } base.ConstructEnd(br); }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); _values[0] = br.ReadSingle(base.Root.PakFormat.EndianType); _values[1] = br.ReadSingle(base.Root.PakFormat.EndianType); if (_values.Length > 2) { _values[2] = br.ReadSingle(base.Root.PakFormat.EndianType); } base.ConstructEnd(br); }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); QbItemBase qib; QbItemType floatsType; uint floatsValue; bool is3d; for (int i = 0; i < base.ItemCount; i++) { if (base.StreamPos(br) != base.Pointers[i]) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[i])); } floatsValue = br.ReadUInt32(this.Root.PakFormat.EndianType); floatsType = this.Root.PakFormat.GetQbItemType(floatsValue); is3d = (type == QbItemType.SectionFloatsX3 || type == QbItemType.StructItemFloatsX3 || type == QbItemType.ArrayFloatsX3); switch (floatsType) { case QbItemType.Floats: qib = new QbItemFloats(this.Root, is3d); break; default: throw new ApplicationException(string.Format("Location 0x{0}: Not a float type 0x{1}", (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'), floatsValue.ToString("X").PadLeft(8, '0'))); } qib.Construct(br, floatsType); AddItem(qib); base.ConstructEnd(br); } }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); _values = new QbKey[base.ItemCount]; uint crc; string debug; for (int i = 0; i < base.ItemCount; i++) { crc = br.ReadUInt32(base.Root.PakFormat.EndianType); debug = this.Root.LookupDebugName(crc); if (debug.Length != 0) _values[i] = QbKey.Create(crc, debug); else _values[i] = QbKey.Create(crc); } base.ConstructEnd(br); }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); uint pointer; if (type != QbItemType.StructHeader) { _headerValue = br.ReadUInt32(base.Root.PakFormat.EndianType); } else { _headerValue = base.Root.PakFormat.GetQbItemValue(type, this.Root); } _headerType = base.Root.PakFormat.GetQbItemType(_headerValue); QbItemBase qib = null; QbItemType structType; uint structValue; if (_headerType == QbItemType.StructHeader) { pointer = br.ReadUInt32(base.Root.PakFormat.EndianType); //Should be the current stream position after reading _iniNextItemPointer = pointer; if (pointer != 0 && base.StreamPos(br) != pointer) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), pointer)); } while (pointer != 0) { structValue = br.ReadUInt32(this.Root.PakFormat.EndianType); structType = this.Root.PakFormat.GetQbItemType(structValue); switch (structType) { case QbItemType.StructItemStruct: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemStruct(this.Root); break; case QbItemType.StructItemStringPointer: case QbItemType.StructItemInteger: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemInteger(this.Root); break; case QbItemType.StructItemQbKeyString: case QbItemType.StructItemQbKeyStringQs: case QbItemType.StructItemQbKey: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemQbKey(this.Root); break; case QbItemType.StructItemString: case QbItemType.StructItemStringW: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemString(this.Root); break; case QbItemType.StructItemFloat: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemFloat(this.Root); break; case QbItemType.StructItemFloatsX2: case QbItemType.StructItemFloatsX3: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemFloatsArray(this.Root); break; case QbItemType.StructItemArray: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemArray(this.Root); break; //Convert array types to structitems to fit in with this parser (if QbFile.HasStructItems is false then internal type will be swapped back to array) case QbItemType.ArrayStruct: structType = QbItemType.StructItemStruct; qib = new QbItemArray(this.Root); break; case QbItemType.ArrayInteger: structType = QbItemType.StructItemInteger; qib = new QbItemInteger(this.Root); break; case QbItemType.ArrayQbKeyString: structType = QbItemType.StructItemQbKeyString; qib = new QbItemQbKey(this.Root); break; case QbItemType.ArrayStringPointer: structType = QbItemType.StructItemStringPointer; qib = new QbItemInteger(this.Root); break; case QbItemType.ArrayQbKeyStringQs: structType = QbItemType.StructItemQbKeyStringQs; qib = new QbItemQbKey(this.Root); break; case QbItemType.ArrayQbKey: structType = QbItemType.StructItemQbKey; qib = new QbItemQbKey(this.Root); break; case QbItemType.ArrayString: structType = QbItemType.StructItemString; qib = new QbItemString(this.Root); break; case QbItemType.ArrayStringW: structType = QbItemType.StructItemStringW; qib = new QbItemString(this.Root); break; case QbItemType.ArrayFloat: structType = QbItemType.StructItemFloat; qib = new QbItemFloat(this.Root); break; case QbItemType.ArrayFloatsX2: structType = QbItemType.StructItemFloatsX2; qib = new QbItemFloatsArray(this.Root); break; case QbItemType.ArrayFloatsX3: structType = QbItemType.StructItemFloatsX3; qib = new QbItemFloatsArray(this.Root); break; case QbItemType.ArrayArray: structType = QbItemType.StructItemArray; qib = new QbItemArray(this.Root); break; default: qib = null; break; } if (qib != null) { if (this.Root.PakFormat.StructItemChildrenType == StructItemChildrenType.NotSet) //will have been set to structItem if qib is not null) { this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.ArrayItems; } qib.Construct(br, structType); AddItem(qib); pointer = qib.NextItemPointer; } else { throw new ApplicationException(string.Format("Location 0x{0}: Unknown item type 0x{1} in struct ", (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'), structValue.ToString("X").PadLeft(8, '0'))); } } } else { throw new ApplicationException(string.Format("Location 0x{0}: Struct without header type", (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); } base.ConstructEnd(br); }
private void parsePak(PakFormat pakFormat, bool debugFile) { _debugFile = debugFile; _pakFormat = pakFormat; _pakFilename = (!_debugFile ? _pakFormat.FullPakFilename : _pakFormat.FullDebugFilename); Dictionary<uint, PakDbgQbKey> qbKeyFilenames = new Dictionary<uint, PakDbgQbKey>(); //if PC or xbox then we need to look up the filename from the debug file //create a PakEditor and load the debug pak, then load all internal debug files, add the first line to our filenames dictionary if (!debugFile) // && (_pakFormat.PakFormatType == PakFormatType.PC || _pakFormat.PakFormatType == PakFormatType.XBox)) { try { _pakFormat.Decompress(); _pakFilename = _pakFormat.FullPakFilename; } catch (Exception ex) { throw new Exception("Decompression Error", ex); } if (_pakFormat.DebugFileExists) { string debugFileContents; string filename; uint crc; PakEditor pakDebug = new PakEditor(new PakFormat(_pakFormat.FullDebugFilename, "", _pakFormat.FullDebugFilename, _pakFormat.PakFormatType), true); foreach (PakHeaderItem dphi in pakDebug.Headers.Values) { debugFileContents = string.Empty; filename = string.Empty; crc = 0; if (dphi.FullFilenameQbKey != 0) crc = dphi.FullFilenameQbKey; else if (dphi.PakFullFileNameQbKey != 0) crc = dphi.PakFullFileNameQbKey; else if (dphi.NameOnlyCrc != 0) crc = dphi.NameOnlyCrc; if (crc != 0) { filename = crc.ToString("X").PadLeft(8, '0'); if (pakDebug.Headers.ContainsKey(filename.ToLower())) { debugFileContents = pakDebug.ExtractFileToString(filename); if (debugFileContents.Length != 0) addDebugFilename(debugFileContents, qbKeyFilenames, crc); } } } } } long minOffset = uint.MaxValue; long maxOffset = 0; _pakHeaders = new Dictionary<string, PakHeaderItem>(); using (Stream st = File.Open(_pakFilename, FileMode.Open, FileAccess.Read)) { _pakFileLength = st.Length; using (BinaryEndianReader br = new BinaryEndianReader(st)) { PakHeaderItem phi = null; QbKey lastQbKey = QbKey.Create("last"); QbKey dotLastQbKey = QbKey.Create(".last"); do { phi = new PakHeaderItem(); phi.HeaderStart = (uint)st.Position; phi.IsStoredInPak = true; phi.FileType = QbKey.Create(br.ReadUInt32(_pakFormat.EndianType)); //if the entry has the file type of last then we're done if (phi.FileType == lastQbKey || phi.FileType == dotLastQbKey) break; phi.FileOffset = br.ReadUInt32(_pakFormat.EndianType); phi.FileLength = br.ReadUInt32(_pakFormat.EndianType); phi.PakFullFileNameQbKey = br.ReadUInt32(_pakFormat.EndianType); phi.FullFilenameQbKey = br.ReadUInt32(_pakFormat.EndianType); phi.NameOnlyCrc = br.ReadUInt32(_pakFormat.EndianType); phi.Unknown = br.ReadUInt32(_pakFormat.EndianType); phi.Flags = (PakHeaderFlags)br.ReadUInt32(_pakFormat.EndianType); if ((phi.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) { uint crc = 0; //get any Crc if (phi.FullFilenameQbKey != 0) crc = phi.FullFilenameQbKey; else if (phi.PakFullFileNameQbKey != 0) crc = phi.PakFullFileNameQbKey; else if (phi.NameOnlyCrc != 0) crc = phi.NameOnlyCrc; if (!debugFile) { uint crc2 = 0; //get a crc that exists in the debug names if (qbKeyFilenames.ContainsKey(phi.FullFilenameQbKey)) crc2 = phi.FullFilenameQbKey; else if (qbKeyFilenames.ContainsKey(phi.PakFullFileNameQbKey)) crc2 = phi.PakFullFileNameQbKey; else if (qbKeyFilenames.ContainsKey(phi.NameOnlyCrc)) crc2 = phi.NameOnlyCrc; //if 0 then get any crc if (crc2 != 0) { phi.Filename = qbKeyFilenames[crc2].Filename; phi.DebugQbKey = qbKeyFilenames[crc2].DebugQbKey; crc = crc2; } } if (phi.Filename == null) { if (crc != 0) phi.Filename = crc.ToString("X").PadLeft(8, '0'); else phi.Filename = string.Format("Unknown={0}", phi.HeaderStart.ToString("X").PadLeft(8, '0')); } } else phi.Filename = UTF8Encoding.UTF8.GetString(br.ReadBytes(PakHeaderItem.FileNameMaxLength)).TrimEnd(new char[] { '\0' }); try { _pakHeaders.Add(phi.Filename.ToLower(), phi); } catch (Exception ex) { throw new ApplicationException(string.Format("Error adding '{0}' to headers: {1}", phi.Filename, ex.Message)); } if (phi.HeaderStart + phi.FileOffset < minOffset) minOffset = phi.HeaderStart + phi.FileOffset; if (phi.HeaderStart + phi.FileOffset > maxOffset) maxOffset = phi.HeaderStart + phi.FileOffset; } while (1 == 1); //minOffset > fs.Position + 0x100); //drop out if we reach the data //this is a simple hack/fix to cater for padding on PAK files, //it relies on the data starting at the top of the PAB file (which it always does, currently) _requiresPab = maxOffset >= st.Length; if (!debugFile) //only when loading pak _pakFormat.PakPabMinDataOffset = minOffset; //remember this value //detect GH5 PAB files if (_requiresPab) { foreach (PakHeaderItem ph in _pakHeaders.Values) ph.FileOffset += (uint)(_pakFileLength - _pakFormat.PakPabMinDataOffset) - (_pakFormat.PakPabMinDataOffset == 0 ? ph.HeaderStart : 0); //gh5 doesn't hold the offset in relation to the data. minOffset = _pakFileLength; } } } _qbFilenames = new string[_pakHeaders.Count]; int i = 0; foreach (PakHeaderItem hi in _pakHeaders.Values) _qbFilenames[i++] = hi.Filename; StructItemChildrenType s; if (!debugFile) s = this.StructItemChildrenType; //auto detect the structitemchildren type }
private void parse() { _datItems.Clear(); using (FileStream fs = File.OpenRead(_datFilename)) { using (BinaryEndianReader br = new BinaryEndianReader(fs)) { uint files = br.ReadUInt32(_endianType); _headerFileSize = br.ReadUInt32(_endianType); QbKey songQk; for (int i = 0; i < files; i++) { songQk = QbKey.Create(br.ReadUInt32(_endianType)); _datItems.Add(songQk.Crc, new DatItem(songQk, br.ReadUInt32(_endianType), br.ReadUInt32(_endianType), br.ReadBytes(8))); } } } }
public static void CreatePreview(int offset, int length, int fade, float volume, bool volumeApplied, string dstFilename, params AudioFile[] srcFilenames) { if (srcFilenames == null || srcFilenames.Length == 0 || (srcFilenames.Length == 1 && (srcFilenames[0] == null || srcFilenames[0].Name.Length == 0))) return; FileHelper.Delete(dstFilename); WavSingleChunkHeader[] whi = new WavSingleChunkHeader[srcFilenames.Length]; BinaryEndianReader[] br = new BinaryEndianReader[srcFilenames.Length]; float[] vols = new float[srcFilenames.Length]; int outWav = 0; //use this input wav as the format for the output wav int maxLen = 0; for (int c = 0; c < srcFilenames.Length; c++) { br[c] = new BinaryEndianReader(File.OpenRead(srcFilenames[c].Name)); whi[c] = ParseWavSingleChunkHeader(br[c].BaseStream); if (!volumeApplied) vols[c] = srcFilenames[c].Volume / 100F; //get percentage else vols[c] = 1; //100% //move to the correct point in each wav uint wOffset = (uint)(whi[c].AvgBytesPerSec * ((float)offset / 1000)); wOffset -= wOffset % whi[c].BlockAlign; br[c].BaseStream.Seek((long)wOffset, SeekOrigin.Current); if (whi[c].AudioLength > maxLen) maxLen = whi[c].AudioLength; if (whi[c].Channels == 2) outWav = c; } WavSingleChunkHeader who = new WavSingleChunkHeader(); if (length == 0) length = maxLen; uint wLength = (uint)(whi[outWav].AvgBytesPerSec * ((float)length / 1000)); wLength -= wLength % whi[outWav].BlockAlign; who.FileId = "RIFF"; who.FileLength = (uint)(br[outWav].BaseStream.Length - whi[outWav].FileLength) + wLength; who.RiffType = "WAVE"; who.ChunkHeaderId = "fmt "; who.ChunkHeaderLength = whi[outWav].ChunkHeaderLength; who.FormatTag = whi[outWav].FormatTag; who.Channels = whi[outWav].Channels; who.SamplesPerSec = whi[outWav].SamplesPerSec; who.AvgBytesPerSec = whi[outWav].AvgBytesPerSec; who.BlockAlign = whi[outWav].BlockAlign; who.BitsPerSample = whi[outWav].BitsPerSample; who.ExtraBytes = whi[outWav].ExtraBytes; who.ChunkId = "data"; who.ChunkLength = wLength; using (FileStream fso = File.OpenWrite(dstFilename)) { WriteSingleChunkHeader(who, fso); int loops = (int)((who.AvgBytesPerSec / who.BlockAlign) * ((float)length / 1000)); int fadeLen = (int)((who.AvgBytesPerSec / who.BlockAlign) * ((float)fade / 1000)); Double maxVol = (volume / (float)srcFilenames.Length); //reduce volume Audio in game maxVol *= 1F + ((srcFilenames.Length - 1) * 0.33F); //add an extra third per file to cater for volume loss Double vol = 0; //initial volume if (fade == 0) vol = maxVol; int b32; BinaryEndianWriter bw = new BinaryEndianWriter(fso); Double step = (double)(maxVol - 0) / fadeLen; //fade in if (Double.IsInfinity(step)) step = 0; int allLeft = 0; int allRight = 0; long[] streamPos = new long[br.Length]; //fast way to track pos in stream for (int c = 0; c < br.Length; c++) streamPos[c] = br[c].BaseStream.Position; long[] streamLen = new long[br.Length]; //fast way to get length of stream for (int c = 0; c < br.Length; c++) streamLen[c] = br[c].BaseStream.Length; for (int i = 0; i != loops; i++) { if (i == fadeLen) step = 0; //use max volume if (i == loops - fadeLen) //fade out step = (double)(0 - maxVol) / fadeLen; allLeft = 0; allRight = 0; for (int c = 0; c < br.Length; c++) //each input stream { BinaryEndianReader b = br[c]; WavSingleChunkHeader w = whi[c]; //Left channel b32 = 0; if (streamPos[c] + 2 < streamLen[c]) { b32 = (int)(b.ReadInt16(EndianType.Little) * vols[c]); streamPos[c] += 2; } allLeft += (int)(b32 * vol); allLeft = (short)Math.Max((int)short.MinValue, Math.Min((int)short.MaxValue, allLeft)); if (who.Channels > 1) { if (w.Channels > 1) { //Right channel b32 = 0; if (streamPos[c] + 2 < streamLen[c]) { b32 = (int)(b.ReadInt16(EndianType.Little) * vols[c]); streamPos[c] += 2; } } allRight += (int)(b32 * vol); allRight = (short)Math.Max((int)short.MinValue, Math.Min((int)short.MaxValue, allRight)); } } bw.Write((short)allLeft); if (who.Channels > 1) bw.Write((short)allRight); vol += step; } foreach (BinaryEndianReader b in br) b.Close(); fso.Flush(); } }
private void parse(Stream stream) { _streamStartPosition = stream.Position; _items = new List<QbItemBase>(); //if (stream.Position != 0) // throw new ApplicationException("The stream must start at position 0 as this parser uses the position to validate pointers."); using (BinaryEndianReader br = new BinaryEndianReader(stream)) { _magic = br.ReadUInt32(this.PakFormat.EndianType); _fileSize = br.ReadUInt32(this.PakFormat.EndianType); uint sectionValue; QbItemBase qib = new QbItemUnknown(20, this); qib.Construct(br, QbItemType.Unknown); AddItem(qib); while (this.StreamPos(br.BaseStream) < _fileSize) { sectionValue = br.ReadUInt32(this.PakFormat.EndianType); QbItemType sectionType = this.PakFormat.GetQbItemType(sectionValue); switch (sectionType) { case QbItemType.SectionString: case QbItemType.SectionStringW: qib = new QbItemString(this); break; case QbItemType.SectionArray: qib = new QbItemArray(this); break; case QbItemType.SectionStruct: qib = new QbItemStruct(this); break; case QbItemType.SectionScript: qib = new QbItemScript(this); break; case QbItemType.SectionFloat: qib = new QbItemFloat(this); break; case QbItemType.SectionFloatsX2: case QbItemType.SectionFloatsX3: qib = new QbItemFloatsArray(this); break; case QbItemType.SectionInteger: case QbItemType.SectionStringPointer: qib = new QbItemInteger(this); break; case QbItemType.SectionQbKey: case QbItemType.SectionQbKeyString: case QbItemType.SectionQbKeyStringQs: //GH:GH qib = new QbItemQbKey(this); break; default: throw new ApplicationException(string.Format("Location 0x{0}: Unknown section type 0x{1}", (this.StreamPos(br.BaseStream) - 4).ToString("X").PadLeft(8, '0'), sectionValue.ToString("X").PadLeft(8, '0'))); } qib.Construct(br, sectionType); AddItem(qib); } } uint f = this.FileId; //gettin this sets the file id }
public static void BuildPartition(string partitionBinFilename, string mainDolFilename, string appLoaderImgFilename, string bi2BinFilename, string bootBinFilename, string sourceDirectory, string partitionFilename, bool deleteWhileBuilding) { ulong totalSize = 0; BinaryEndianReader brFst = null; BinaryEndianWriter bwFst = new BinaryEndianWriter(new MemoryStream()); BinaryEndianWriter bwStr = new BinaryEndianWriter(new MemoryStream()); BinaryEndianWriter bwBootBin = null; BinaryEndianWriter bwPartitionBin = null; BinaryEndianWriter bwB12Bin = null; try { DirectoryInfo inputFolder = new DirectoryInfo(sourceDirectory); //DateTime n = DateTime.Now; uint fileCount = recurseFiles(true, inputFolder, bwFst, bwStr, ref totalSize, 0, null, 0, deleteWhileBuilding); //System.Diagnostics.Debug.WriteLine((DateTime.Now - n).Ticks); // get the file sizes we need - apploader and main.dol FileInfo appLoaderImg = new FileInfo(appLoaderImgFilename); FileInfo mainDol = new FileInfo(mainDolFilename); // now calculate the relative offsets uint pad1Size = 0x100 - (((uint)appLoaderImg.Length + 0x2440) % 0x100); uint pad2Size = 0x100 - ((uint)mainDol.Length % 0x100); // just a pad out for no real reason :) uint pad3Size = 0x2000; uint mainDolOffset = 0x2440 + (uint)appLoaderImg.Length + pad1Size; uint fstOffset = mainDolOffset + pad2Size + (uint)mainDol.Length; // modify the data size in partition.bin // read in partition.bin bwPartitionBin = new BinaryEndianWriter(new MemoryStream(File.ReadAllBytes(partitionBinFilename))); // now Actual size = scaled up by sizes totalSize += pad1Size + 0x2440 + pad2Size + pad3Size + (uint)mainDol.Length + (uint)appLoaderImg.Length; ulong dataSize = (totalSize / 0x7c00) * 0x8000; if (dataSize % 0x7c00 != 0) dataSize += 0x8000; bwPartitionBin.Seek(0x2BC, SeekOrigin.Begin); bwPartitionBin.Write((uint)dataSize >> 2, EndianType.Big); // generate a boot.bin bwBootBin = new BinaryEndianWriter(new MemoryStream(File.ReadAllBytes(bootBinFilename))); // now the size offsets bwBootBin.Seek(0x420, SeekOrigin.Begin); bwBootBin.Write(mainDolOffset >> 2, EndianType.Big); bwBootBin.Write(fstOffset >> 2, EndianType.Big); bwBootBin.Write((uint)(bwFst.BaseStream.Length + bwStr.BaseStream.Length) >> 2, EndianType.Big); bwBootBin.Write((uint)(bwFst.BaseStream.Length + bwStr.BaseStream.Length) >> 2, EndianType.Big); // calculate what we need to modify the FST entries by ulong dataOffset = 0x2440 + pad1Size + (uint)appLoaderImg.Length + (uint)mainDol.Length + pad2Size + (uint)bwFst.BaseStream.Length + (uint)bwStr.BaseStream.Length + pad3Size; dataOffset = (dataOffset >> 2); // modify the fst.bin to include all the correct offsets brFst = new BinaryEndianReader(bwFst.BaseStream); brFst.BaseStream.Seek(8, SeekOrigin.Begin); uint fstEntries = brFst.ReadUInt32(EndianType.Big); for (int i = 1; i < fstEntries; i++) //1 as we've already skipped the root { if (brFst.ReadByte() == 0) //file { brFst.BaseStream.Seek(3, SeekOrigin.Current); //skip the rest of the uint uint temp = brFst.ReadUInt32(EndianType.Big); bwFst.BaseStream.Seek(-4, SeekOrigin.Current); //THE STREAMS ARE THE SAME (be careful of bugs when the position moves) bwFst.Write((uint)dataOffset + temp, EndianType.Big); brFst.BaseStream.Seek(4, SeekOrigin.Current); //skip the rest of the file } else brFst.BaseStream.Seek(0xc - 1, SeekOrigin.Current); //skip the rest of the directory } using (FileStream fs = new FileStream(partitionFilename, FileMode.Create)) { copyStream(bwPartitionBin.BaseStream, fs, 4); copyStream(bwBootBin.BaseStream, fs, 4); copyStream(bi2BinFilename, fs, 4); copyStream(appLoaderImgFilename, fs, 4); fs.Write(new byte[pad1Size], 0, (int)pad1Size); copyStream(mainDolFilename, fs, 4); fs.Write(new byte[pad2Size], 0, (int)pad2Size); copyStream(bwFst.BaseStream, fs, 4); copyStream(bwStr.BaseStream, fs, 4); fs.Write(new byte[pad3Size], 0, (int)pad3Size); //copy all the files to the end of the partition totalSize = dataOffset; //will give the offsets the correct value (not that it matters here heh) bwFst.BaseStream.Seek(0, SeekOrigin.Begin); bwStr.BaseStream.Seek(0, SeekOrigin.Begin); recurseFiles(true, inputFolder, bwFst, bwStr, ref totalSize, 0, fs, (ulong)fs.Position - dataOffset, deleteWhileBuilding); if (deleteWhileBuilding) { try { inputFolder.Delete(true); } catch { } } } } finally { if (brFst != null) brFst.Close(); bwFst.Close(); bwStr.Close(); if (bwBootBin != null) bwBootBin.Close(); if (bwPartitionBin != null) bwPartitionBin.Close(); if (bwB12Bin != null) bwB12Bin.Close(); } }
/// <summary> /// Adds silence to wav files alter volume /// </summary> /// <param name="silenceInsertLength">Milliseconds to insert at start of wav</param> /// <param name="volume">0=silent, 1=100%</param> /// <param name="maxLength">If the wav is longer than this then crop (includes silence), if 0 then don't crop</param> /// <param name="srcFilenames">Filenames to pad</param> public static void SetLengthSilenceAndVolume(float silenceInsertLength, float maxLength, float volume, string fileName) { FileStream inS; FileStream outS; WavSingleChunkHeader h; uint silenceLen; string tmpName; //uint origChunkLen; int copied; byte[] buff = new byte[10000]; for (int i = 0; i < buff.Length; i++) buff[i] = 0; tmpName = string.Format("{0}_{1}", fileName, Guid.NewGuid().ToString("N")); using (inS = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { using (outS = new FileStream(tmpName, FileMode.CreateNew, FileAccess.ReadWrite)) { h = ParseWavSingleChunkHeader(inS); //origChunkLen = h.ChunkLength; silenceLen = (uint)((float)h.AvgBytesPerSec * (silenceInsertLength / 1000F)); silenceLen -= silenceLen % h.BlockAlign; uint newLenBytes = maxLength != 0 ? (uint)((float)h.AvgBytesPerSec * (maxLength / 1000F)) : h.ChunkLength + silenceLen; newLenBytes -= newLenBytes % h.BlockAlign; h.ChunkLength = (uint)((uint)inS.Length - h.DataOffset) + silenceLen; if (h.ChunkLength > newLenBytes) h.ChunkLength = newLenBytes; h.ChunkLength -= h.ChunkLength % h.BlockAlign; h.FileLength = (h.ChunkLength + (uint)h.DataOffset) - 8; WriteSingleChunkHeader(h, outS); copied = 0; int len = 0; while (copied < silenceLen) { len = buff.Length; if (copied + buff.Length > silenceLen) len = (int)silenceLen - copied; outS.Write(buff, 0, len); copied += len; } //origChunkLen = h.ChunkLength; //we need to copy this much //copy audio and set volume BinaryEndianWriter bw = new BinaryEndianWriter(outS); BinaryEndianReader br = new BinaryEndianReader(inS); int b32; while (copied != h.ChunkLength) //length is block aligned so don't worry about channel count { b32 = (int)br.ReadInt16(EndianType.Little); b32 = (int)((float)b32 * volume); b32 = Math.Max((int)short.MinValue, Math.Min((int)short.MaxValue, b32)); bw.Write((short)b32, EndianType.Little); copied += 2; } //copied = (int)origChunkLen; //we've copied this much (silence included) //while (copied < h.ChunkLength) //pad to the length we said it was in the header //{ // inS.Read(buff, 0, buff.Length); // if (copied + buff.Length < h.ChunkLength) // outS.Write(buff, 0, buff.Length); // else // outS.Write(buff, 0, (int)h.ChunkLength % - copied); // copied += buff.Length; //} outS.Flush(); } } if (File.Exists(fileName)) { if (File.Exists(tmpName)) FileHelper.Move(tmpName, fileName); } }
protected uint StreamPos(BinaryEndianReader br) { return(Root.StreamPos(br.BaseStream)); }
private void replaceFile(string qbFilename, long newLength, bool remove, WriteDataToStream callback) { int filePad = _pakFormat.FilePadSize; PakHeaderItem phi = null; if (_pakHeaders.ContainsKey(qbFilename.ToLower())) phi = _pakHeaders[qbFilename.ToLower()]; else { string fqk = QbKey.Create(qbFilename).Crc.ToString("X").PadLeft(8, '0').ToLower(); if (_pakHeaders.ContainsKey(fqk)) phi = _pakHeaders[fqk]; } if (phi != null) { long pad = filePad - (newLength % filePad); if (pad == filePad) pad = 0; string newPakFilename = string.Format("{0}_{1}", _pakFormat.FullPakFilename, Guid.NewGuid().ToString("N")); string newPabFilename = string.Format("{0}_{1}", _pakFormat.FullPabFilename, Guid.NewGuid().ToString("N")); uint minOffset = uint.MaxValue; bool itemFound = false; uint nextOffset = 0; foreach (PakHeaderItem ph in _pakHeaders.Values) { if (itemFound) { nextOffset = ph.FileOffset + ph.HeaderStart; itemFound = false; //don't enter this if again } if (object.ReferenceEquals(phi, ph)) itemFound = true; if (ph.HeaderStart + ph.FileOffset < minOffset) minOffset = ph.HeaderStart + ph.FileOffset; } uint lastItemPad = 0; int repPad = filePad - ((int)phi.FileLength % filePad); if (repPad == filePad) repPad = 0; //previously badly padded or last file if (nextOffset != 0 && (nextOffset - (phi.FileOffset + phi.HeaderStart)) % filePad != 0) repPad = (int)((nextOffset - (phi.FileOffset + phi.HeaderStart)) - phi.FileLength); //position of the LAST header item long lastHeaderPos = 0; //the length of all the headers (like pak when there's a pab) with padding long allHeadersLen = minOffset; //position in the input file where our file is to be replaced (not including header pos) long fileReplacePos = (phi.HeaderStart + phi.FileOffset) - allHeadersLen; //position in the input file after the file that is to be replaced long fileAfterReplacePos = fileReplacePos + phi.FileLength + repPad; //item size before modifying header //open input pak using (FileStream fsPakI = File.Open(_pakFilename, FileMode.Open, FileAccess.Read)) { using (BinaryEndianReader brPakI = new BinaryEndianReader(fsPakI)) { //open output pak temp file using (FileStream fsPakO = File.Create(newPakFilename)) { using (BinaryEndianWriter bwPakO = new BinaryEndianWriter(fsPakO)) { long diffLen = 0; //do not compensate for missing header when using zlib compression as the header is padded if (remove && _pakFormat.CompressionType != CompressionType.ZLibChunk) //we need to cater for the header being removed on all items before it. { diffLen = PakHeaderItem.FullHeaderLength; if ((phi.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) diffLen -= PakHeaderItem.FileNameMaxLength; } //write out the headers foreach (PakHeaderItem ph in _pakHeaders.Values) { //apply offset change before finding file to be replaced //this will prevents the offset of the replaced file being changed ph.FileOffset = (uint)(ph.FileOffset - (long)diffLen); if (object.ReferenceEquals(phi, ph)) { if (remove) { long remPad = filePad - (phi.FileLength % filePad); if (remPad == filePad) remPad = 0; diffLen = phi.FileLength + remPad; //now cater for the difference in file size } else { diffLen = (long)((ph.FileLength + repPad) - (newLength + pad)); ph.FileLength = (uint)newLength; //0 for remove } } lastHeaderPos += PakHeaderItem.FullHeaderLength; if (!(remove && object.ReferenceEquals(phi, ph))) writeHeaderItem(bwPakO, ph); if ((ph.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) lastHeaderPos -= PakHeaderItem.FileNameMaxLength; } //Move to the "last" header fsPakI.Seek(lastHeaderPos, SeekOrigin.Begin); //write out "last" HeaderType bwPakO.Write(brPakI.ReadBytes(4)); //Modify and write the offset of the "last" header's data uint lastOffset = brPakI.ReadUInt32(_pakFormat.EndianType); lastOffset = (uint)(lastOffset - (long)diffLen); //fix bad padding on last file if (nextOffset == 0 && ((lastOffset - (phi.FileOffset + phi.HeaderStart) % filePad) % filePad) != 0) { lastItemPad = (uint)filePad - (uint)(lastOffset % filePad); lastOffset += lastItemPad; } bwPakO.Write(lastOffset, _pakFormat.EndianType); //write out the end of the last header copyData(fsPakI, fsPakO, allHeadersLen - fsPakI.Position); } } } } //open input pak using (FileStream fsPakI = File.Open(_requiresPab ? _pakFormat.FullPabFilename : _pakFilename, FileMode.Open, FileAccess.Read)) { using (BinaryEndianReader brPakI = new BinaryEndianReader(fsPakI)) { //open output pak temp file using (FileStream fsPakO = _requiresPab ? File.Open(newPabFilename, FileMode.Create) : File.Open(newPakFilename, FileMode.Append)) { using (BinaryEndianWriter bwPakO = new BinaryEndianWriter(fsPakO)) { if (!_requiresPab) fsPakI.Seek(allHeadersLen, SeekOrigin.Begin); //Write out the data starting from the last header to the start of the file to be replaced (minus the length of the type and offset) copyData(fsPakI, fsPakO, fileReplacePos); //Write the new file into the pak file int pos = (int)fsPakO.Position; callback(fsPakO); if (pad != 0) fsPakO.Write(new byte[pad], 0, (int)pad); if (!_requiresPab) fileAfterReplacePos += allHeadersLen; if (lastItemPad != 0) fileAfterReplacePos -= lastItemPad; // a bit of a hack as this was not applied when this var was set as we didn't know the values //write the remainder of source the pak file fsPakI.Seek(fileAfterReplacePos, SeekOrigin.Begin); copyData(fsPakI, fsPakO, fsPakI.Length - fileAfterReplacePos); fsPakO.Flush(); } } } } fixUncompressedFileLengths(newPakFilename, newPabFilename); File.Delete(_pakFilename); File.Move(newPakFilename, _pakFilename); if (_requiresPab) { File.Delete(_pakFormat.FullPabFilename); File.Move(newPabFilename, _pakFormat.FullPabFilename); } _pakFormat.Compress(); } else throw new ApplicationException(string.Format("'{0}' does not exist in '{1}'", qbFilename, _pakFilename)); }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); _isUnicode = ((type == QbItemType.SectionStringW || type == QbItemType.ArrayStringW || type == QbItemType.StructItemStringW) && (base.Root.PakFormat.PakFormatType == PakFormatType.PC || base.Root.PakFormat.PakFormatType == PakFormatType.XBox)); byte[] bytes; base.Construct(br, type); this.Strings = new string[base.ItemCount]; _charWidth = !_isUnicode ? 1 : 2; if (base.ItemCount != 0) { //use pointers to read quickly if (base.ItemCount > 1) { for (int i = 0; i < base.ItemCount - 1; i++) { if (base.StreamPos(br) != base.Pointers[i]) //pointer test throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[i])); bytes = br.ReadBytes((int)((base.Pointers[i + 1] - _charWidth) - base.StreamPos(br))); _strings[i] = bytesToString(bytes); //handles unicode if (!_isUnicode ? (br.ReadByte() != 0) : (br.ReadByte() != 0 || br.ReadByte() != 0)) throw new ApplicationException(string.Format("Null byte expected reading string array at 0x{0}", (base.StreamPos(br) - _charWidth).ToString("X").PadLeft(8, '0'))); } if (base.StreamPos(br) != base.Pointers[base.ItemCount - 1]) //pointer test throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[base.ItemCount - 1])); } //use the slow method read the last string StringBuilder sb = new StringBuilder(); //if we have come from an array we must align our position to %4 int byteAmount = (int)(4 - (base.StreamPos(br) % 4)); do { bytes = br.ReadBytes(byteAmount); sb.Append(bytesToString(bytes)); byteAmount = 4; } while (!_isUnicode ? (bytes[bytes.Length - 1] != '\0') : (bytes[bytes.Length - 1] != '\0' || bytes[bytes.Length - 2] != '\0')); //get text and remove any trailing null bytes _strings[base.ItemCount - 1] = sb.ToString().TrimEnd(new char[] { '\0' }); } base.ConstructEnd(br); }
private CompressionType xBoxUncompress(string compFilename, string uncompFilename) { if (uncompFilename.ToLower() == compFilename.ToLower()) //nothing to do { return(CompressionType.None); } if (File.Exists(uncompFilename)) { File.Delete(uncompFilename); } CompressionType ct = CompressionType.None; try { using (FileStream inFileStream = new FileStream(compFilename, FileMode.Open, FileAccess.Read)) { using (BinaryEndianReader br = new BinaryEndianReader(inFileStream)) { uint chunkLen = 0; while (chunkLen != 0xffffffff) { using (FileStream outFileStream = new FileStream(uncompFilename, chunkLen == 0 ? FileMode.Create : FileMode.Append)) { using (ZlibOutputStream outZStream = new ZlibOutputStream(outFileStream, Rebex.IO.Compression.CompressionMode.Decompress)) { //test for newer GHWT+ compression long pos = inFileStream.Position; if (Encoding.ASCII.GetString(br.ReadBytes(4)) == "CHNK") { ct = CompressionType.ZLibChunk; EndianType et = this.EndianType; //Decompress each section uint headerLen = br.ReadUInt32(et); uint blockLen = br.ReadUInt32(et); chunkLen = br.ReadUInt32(et); uint nextchunkLen = br.ReadUInt32(et); uint uncompressedLen = br.ReadUInt32(et); uint uncompressedPos = br.ReadUInt32(et); _zLibHeaderLen = headerLen; if (uncompressedLen > this._zLibChunkSize) { this._zLibChunkSize = uncompressedLen; } inFileStream.Seek(headerLen - (inFileStream.Position - pos), SeekOrigin.Current); outZStream.WriteByte(0x58); //Search deflate.cs for "Nanook" for the mod to stop it being written out outZStream.WriteByte(0x85); //this is the header MS uses, thie zlib deflate uses 78DA ?? copyStream(inFileStream, outZStream, (int)blockLen); if (chunkLen != 0xffffffff) { inFileStream.Seek((chunkLen - blockLen) - headerLen, SeekOrigin.Current); } } else { try { inFileStream.Seek(pos, SeekOrigin.Begin); outZStream.WriteByte(0x58); outZStream.WriteByte(0x85); copyStream(inFileStream, outZStream); ct = CompressionType.ZLib; break; } catch { break; //no compression??? } } outZStream.Flush(); outFileStream.Flush(); //outZStream.Close(); } } } } } } catch (Exception ex) { throw new ApplicationException(string.Format("Uncompress Failed: {0}", ex)); } //using (DeflateStream ds = new DeflateStream(File.Open(compFilename, FileMode.Open), CompressionMode.Decompress)) //{ // using (BinaryReader br = new BinaryReader(ds)) // { // using (FileStream ms = File.Create(uncompFilename)) // { // using (BinaryWriter bw = new BinaryWriter(ms)) // { // long l; // do // { // l = ms.Length; // bw.Write(br.ReadBytes(10000)); // } // while (l != ms.Length); // } // } // } //} return(ct); }
private CompressionType xBoxUncompress(string compFilename, string uncompFilename) { if (uncompFilename.ToLower() == compFilename.ToLower()) //nothing to do return CompressionType.None; if (File.Exists(uncompFilename)) File.Delete(uncompFilename); CompressionType ct = CompressionType.None; try { using (FileStream inFileStream = new FileStream(compFilename, FileMode.Open, FileAccess.Read)) { using (BinaryEndianReader br = new BinaryEndianReader(inFileStream)) { uint chunkLen = 0; while (chunkLen != 0xffffffff) { using (FileStream outFileStream = new FileStream(uncompFilename, chunkLen == 0 ? FileMode.Create : FileMode.Append)) { using (ZlibOutputStream outZStream = new ZlibOutputStream(outFileStream, Rebex.IO.Compression.CompressionMode.Decompress)) { //test for newer GHWT+ compression long pos = inFileStream.Position; if (Encoding.ASCII.GetString(br.ReadBytes(4)) == "CHNK") { ct = CompressionType.ZLibChunk; EndianType et = this.EndianType; //Decompress each section uint headerLen = br.ReadUInt32(et); uint blockLen = br.ReadUInt32(et); chunkLen = br.ReadUInt32(et); uint nextchunkLen = br.ReadUInt32(et); uint uncompressedLen = br.ReadUInt32(et); uint uncompressedPos = br.ReadUInt32(et); _zLibHeaderLen = headerLen; if (uncompressedLen > this._zLibChunkSize) this._zLibChunkSize = uncompressedLen; inFileStream.Seek(headerLen - (inFileStream.Position - pos), SeekOrigin.Current); outZStream.WriteByte(0x58); //Search deflate.cs for "Nanook" for the mod to stop it being written out outZStream.WriteByte(0x85); //this is the header MS uses, thie zlib deflate uses 78DA ?? copyStream(inFileStream, outZStream, (int)blockLen); if (chunkLen != 0xffffffff) inFileStream.Seek((chunkLen - blockLen) - headerLen, SeekOrigin.Current); } else { try { inFileStream.Seek(pos, SeekOrigin.Begin); outZStream.WriteByte(0x58); outZStream.WriteByte(0x85); copyStream(inFileStream, outZStream); ct = CompressionType.ZLib; break; } catch { break; //no compression??? } } outZStream.Flush(); outFileStream.Flush(); //outZStream.Close(); } } } } } } catch (Exception ex) { throw new ApplicationException(string.Format("Uncompress Failed: {0}", ex)); } //using (DeflateStream ds = new DeflateStream(File.Open(compFilename, FileMode.Open), CompressionMode.Decompress)) //{ // using (BinaryReader br = new BinaryReader(ds)) // { // using (FileStream ms = File.Create(uncompFilename)) // { // using (BinaryWriter bw = new BinaryWriter(ms)) // { // long l; // do // { // l = ms.Length; // bw.Write(br.ReadBytes(10000)); // } // while (l != ms.Length); // } // } // } //} return ct; }
private void parsePak(PakFormat pakFormat, bool debugFile) { _debugFile = debugFile; _pakFormat = pakFormat; _pakFilename = (!_debugFile ? _pakFormat.FullPakFilename : _pakFormat.FullDebugFilename); Dictionary <uint, PakDbgQbKey> qbKeyFilenames = new Dictionary <uint, PakDbgQbKey>(); //if PC or xbox then we need to look up the filename from the debug file //create a PakEditor and load the debug pak, then load all internal debug files, add the first line to our filenames dictionary if (!debugFile) // && (_pakFormat.PakFormatType == PakFormatType.PC || _pakFormat.PakFormatType == PakFormatType.XBox)) { try { _pakFormat.Decompress(); _pakFilename = _pakFormat.FullPakFilename; } catch (Exception ex) { throw new Exception("Decompression Error", ex); } if (_pakFormat.DebugFileExists && _debugFile) // cancer { string debugFileContents; string filename; uint crc; PakEditor pakDebug = new PakEditor(new PakFormat(_pakFormat.FullDebugFilename, "", _pakFormat.FullDebugFilename, _pakFormat.PakFormatType), true); foreach (PakHeaderItem dphi in pakDebug.Headers.Values) { debugFileContents = string.Empty; filename = string.Empty; crc = 0; if (dphi.FullFilenameQbKey != 0) { crc = dphi.FullFilenameQbKey; } else if (dphi.PakFullFileNameQbKey != 0) { crc = dphi.PakFullFileNameQbKey; } else if (dphi.NameOnlyCrc != 0) { crc = dphi.NameOnlyCrc; } if (crc != 0) { filename = crc.ToString("X").PadLeft(8, '0'); if (pakDebug.Headers.ContainsKey(filename.ToLower())) { debugFileContents = pakDebug.ExtractFileToString(filename); if (debugFileContents.Length != 0) { addDebugFilename(debugFileContents, qbKeyFilenames, crc); } } } } } } long minOffset = uint.MaxValue; long maxOffset = 0; _pakHeaders = new Dictionary <string, PakHeaderItem>(); using (Stream st = File.Open(_pakFilename, FileMode.Open, FileAccess.Read)) { _pakFileLength = st.Length; using (BinaryEndianReader br = new BinaryEndianReader(st)) { PakHeaderItem phi = null; QbKey lastQbKey = QbKey.Create("last"); QbKey dotLastQbKey = QbKey.Create(".last"); do { phi = new PakHeaderItem(); phi.HeaderStart = (uint)st.Position; phi.IsStoredInPak = true; phi.FileType = QbKey.Create(br.ReadUInt32(_pakFormat.EndianType)); //if the entry has the file type of last then we're done if (phi.FileType == lastQbKey || phi.FileType == dotLastQbKey) { break; } phi.FileOffset = br.ReadUInt32(_pakFormat.EndianType); phi.FileLength = br.ReadUInt32(_pakFormat.EndianType); phi.PakFullFileNameQbKey = br.ReadUInt32(_pakFormat.EndianType); phi.FullFilenameQbKey = br.ReadUInt32(_pakFormat.EndianType); phi.NameOnlyCrc = br.ReadUInt32(_pakFormat.EndianType); phi.Unknown = br.ReadUInt32(_pakFormat.EndianType); phi.Flags = (PakHeaderFlags)br.ReadUInt32(_pakFormat.EndianType); if ((phi.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) { uint crc = 0; //get any Crc if (phi.FullFilenameQbKey != 0) { crc = phi.FullFilenameQbKey; } else if (phi.PakFullFileNameQbKey != 0) { crc = phi.PakFullFileNameQbKey; } else if (phi.NameOnlyCrc != 0) { crc = phi.NameOnlyCrc; } if (!debugFile) { uint crc2 = 0; //get a crc that exists in the debug names if (qbKeyFilenames.ContainsKey(phi.FullFilenameQbKey)) { crc2 = phi.FullFilenameQbKey; } else if (qbKeyFilenames.ContainsKey(phi.PakFullFileNameQbKey)) { crc2 = phi.PakFullFileNameQbKey; } else if (qbKeyFilenames.ContainsKey(phi.NameOnlyCrc)) { crc2 = phi.NameOnlyCrc; } //if 0 then get any crc if (crc2 != 0) { phi.Filename = qbKeyFilenames[crc2].Filename; phi.DebugQbKey = qbKeyFilenames[crc2].DebugQbKey; crc = crc2; } } if (phi.Filename == null) { if (crc != 0) { phi.Filename = crc.ToString("X").PadLeft(8, '0'); } else { phi.Filename = string.Format("Unknown={0}", phi.HeaderStart.ToString("X").PadLeft(8, '0')); } } } else { phi.Filename = UTF8Encoding.UTF8.GetString(br.ReadBytes(PakHeaderItem.FileNameMaxLength)).TrimEnd(new char[] { '\0' }); } try { _pakHeaders.Add(phi.Filename.ToLower(), phi); } catch (Exception ex) { throw new ApplicationException(string.Format("Error adding '{0}' to headers: {1}", phi.Filename, ex.Message)); } if (phi.HeaderStart + phi.FileOffset < minOffset) { minOffset = phi.HeaderStart + phi.FileOffset; } if (phi.HeaderStart + phi.FileOffset > maxOffset) { maxOffset = phi.HeaderStart + phi.FileOffset; } }while (1 == 1); //minOffset > fs.Position + 0x100); //drop out if we reach the data //this is a simple hack/fix to cater for padding on PAK files, //it relies on the data starting at the top of the PAB file (which it always does, currently) _requiresPab = maxOffset >= st.Length; if (!debugFile) //only when loading pak { _pakFormat.PakPabMinDataOffset = minOffset; //remember this value } //detect GH5 PAB files if (_requiresPab) { foreach (PakHeaderItem ph in _pakHeaders.Values) { ph.FileOffset += (uint)(_pakFileLength - _pakFormat.PakPabMinDataOffset) - (_pakFormat.PakPabMinDataOffset == 0 ? ph.HeaderStart : 0); //gh5 doesn't hold the offset in relation to the data. } minOffset = _pakFileLength; } } } _qbFilenames = new string[_pakHeaders.Count]; int i = 0; foreach (PakHeaderItem hi in _pakHeaders.Values) { _qbFilenames[i++] = hi.Filename; } StructItemChildrenType s; if (!debugFile) { s = this.StructItemChildrenType; //auto detect the structitemchildren type } }
private void replaceFile(string qbFilename, long newLength, bool remove, WriteDataToStream callback) { int filePad = _pakFormat.FilePadSize; PakHeaderItem phi = null; if (_pakHeaders.ContainsKey(qbFilename.ToLower())) { phi = _pakHeaders[qbFilename.ToLower()]; } else { string fqk = QbKey.Create(qbFilename).Crc.ToString("X").PadLeft(8, '0').ToLower(); if (_pakHeaders.ContainsKey(fqk)) { phi = _pakHeaders[fqk]; } } if (phi != null) { long pad = filePad - (newLength % filePad); if (pad == filePad) { pad = 0; } string newPakFilename = string.Format("{0}_{1}", _pakFormat.FullPakFilename, Guid.NewGuid().ToString("N")); string newPabFilename = string.Format("{0}_{1}", _pakFormat.FullPabFilename, Guid.NewGuid().ToString("N")); uint minOffset = uint.MaxValue; bool itemFound = false; uint nextOffset = 0; foreach (PakHeaderItem ph in _pakHeaders.Values) { if (itemFound) { nextOffset = ph.FileOffset + ph.HeaderStart; itemFound = false; //don't enter this if again } if (object.ReferenceEquals(phi, ph)) { itemFound = true; } if (ph.HeaderStart + ph.FileOffset < minOffset) { minOffset = ph.HeaderStart + ph.FileOffset; } } uint lastItemPad = 0; int repPad = filePad - ((int)phi.FileLength % filePad); if (repPad == filePad) { repPad = 0; } //previously badly padded or last file if (nextOffset != 0 && (nextOffset - (phi.FileOffset + phi.HeaderStart)) % filePad != 0) { repPad = (int)((nextOffset - (phi.FileOffset + phi.HeaderStart)) - phi.FileLength); } //position of the LAST header item long lastHeaderPos = 0; //the length of all the headers (like pak when there's a pab) with padding long allHeadersLen = minOffset; //position in the input file where our file is to be replaced (not including header pos) long fileReplacePos = (phi.HeaderStart + phi.FileOffset) - allHeadersLen; //position in the input file after the file that is to be replaced long fileAfterReplacePos = fileReplacePos + phi.FileLength + repPad; //item size before modifying header //open input pak using (FileStream fsPakI = File.Open(_pakFilename, FileMode.Open, FileAccess.Read)) { using (BinaryEndianReader brPakI = new BinaryEndianReader(fsPakI)) { //open output pak temp file using (FileStream fsPakO = File.Create(newPakFilename)) { using (BinaryEndianWriter bwPakO = new BinaryEndianWriter(fsPakO)) { long diffLen = 0; //do not compensate for missing header when using zlib compression as the header is padded if (remove && _pakFormat.CompressionType != CompressionType.ZLibChunk) //we need to cater for the header being removed on all items before it. { diffLen = PakHeaderItem.FullHeaderLength; if ((phi.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) { diffLen -= PakHeaderItem.FileNameMaxLength; } } //write out the headers foreach (PakHeaderItem ph in _pakHeaders.Values) { //apply offset change before finding file to be replaced //this will prevents the offset of the replaced file being changed ph.FileOffset = (uint)(ph.FileOffset - (long)diffLen); if (object.ReferenceEquals(phi, ph)) { if (remove) { long remPad = filePad - (phi.FileLength % filePad); if (remPad == filePad) { remPad = 0; } diffLen = phi.FileLength + remPad; //now cater for the difference in file size } else { diffLen = (long)((ph.FileLength + repPad) - (newLength + pad)); ph.FileLength = (uint)newLength; //0 for remove } } lastHeaderPos += PakHeaderItem.FullHeaderLength; if (!(remove && object.ReferenceEquals(phi, ph))) { writeHeaderItem(bwPakO, ph); } if ((ph.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) { lastHeaderPos -= PakHeaderItem.FileNameMaxLength; } } //Move to the "last" header fsPakI.Seek(lastHeaderPos, SeekOrigin.Begin); //write out "last" HeaderType bwPakO.Write(brPakI.ReadBytes(4)); //Modify and write the offset of the "last" header's data uint lastOffset = brPakI.ReadUInt32(_pakFormat.EndianType); lastOffset = (uint)(lastOffset - (long)diffLen); //fix bad padding on last file if (nextOffset == 0 && ((lastOffset - (phi.FileOffset + phi.HeaderStart) % filePad) % filePad) != 0) { lastItemPad = (uint)filePad - (uint)(lastOffset % filePad); lastOffset += lastItemPad; } bwPakO.Write(lastOffset, _pakFormat.EndianType); //write out the end of the last header copyData(fsPakI, fsPakO, allHeadersLen - fsPakI.Position); } } } } //open input pak using (FileStream fsPakI = File.Open(_requiresPab ? _pakFormat.FullPabFilename : _pakFilename, FileMode.Open, FileAccess.Read)) { using (BinaryEndianReader brPakI = new BinaryEndianReader(fsPakI)) { //open output pak temp file using (FileStream fsPakO = _requiresPab ? File.Open(newPabFilename, FileMode.Create) : File.Open(newPakFilename, FileMode.Append)) { using (BinaryEndianWriter bwPakO = new BinaryEndianWriter(fsPakO)) { if (!_requiresPab) { fsPakI.Seek(allHeadersLen, SeekOrigin.Begin); } //Write out the data starting from the last header to the start of the file to be replaced (minus the length of the type and offset) copyData(fsPakI, fsPakO, fileReplacePos); //Write the new file into the pak file int pos = (int)fsPakO.Position; callback(fsPakO); if (pad != 0) { fsPakO.Write(new byte[pad], 0, (int)pad); } if (!_requiresPab) { fileAfterReplacePos += allHeadersLen; } if (lastItemPad != 0) { fileAfterReplacePos -= lastItemPad; // a bit of a hack as this was not applied when this var was set as we didn't know the values } //write the remainder of source the pak file fsPakI.Seek(fileAfterReplacePos, SeekOrigin.Begin); copyData(fsPakI, fsPakO, fsPakI.Length - fileAfterReplacePos); fsPakO.Flush(); } } } } fixUncompressedFileLengths(newPakFilename, newPabFilename); File.Delete(_pakFilename); File.Move(newPakFilename, _pakFilename); if (_requiresPab) { File.Delete(_pakFormat.FullPabFilename); File.Move(newPabFilename, _pakFormat.FullPabFilename); } _pakFormat.Compress(); } else { throw new ApplicationException(string.Format("'{0}' does not exist in '{1}'", qbFilename, _pakFilename)); } }
/// <summary> /// Load type data from binary reader /// </summary> public virtual void Construct(BinaryEndianReader br, QbItemType type) { setQbFormat(type); _qbItemType = type; _qbItemValue = this.Root.PakFormat.GetQbItemValue(type, this.Root); _position = this.StreamPos(br) - (1 * 4); //subtract the already read header uint itemQbKeyCrc = 0; #region switch switch (_qbFormat) { case QbFormat.SectionPointer: //Complex section type: // ItemId, FileId, Pointer, Reserved _hasQbKey = true; itemQbKeyCrc = br.ReadUInt32(this.Root.PakFormat.EndianType); _fileId = br.ReadUInt32(this.Root.PakFormat.EndianType); _pointer = br.ReadUInt32(this.Root.PakFormat.EndianType); _reserved = br.ReadUInt32(this.Root.PakFormat.EndianType); _length = (5 * 4); if (type == QbItemType.SectionScript) { _itemCount = 0; } else { _itemCount = 1; } _pointers = new uint[1]; _pointers[0] = _pointer; if (this.StreamPos(br) != _pointer) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _pointer)); } break; case QbFormat.SectionValue: //Simple section type: // ItemId, FileId, Value, Reserved _hasQbKey = true; itemQbKeyCrc = br.ReadUInt32(this.Root.PakFormat.EndianType); _fileId = br.ReadUInt32(this.Root.PakFormat.EndianType); _itemCount = 1; _length = (3 * 4); break; case QbFormat.StructItemPointer: //Complex struct type: // ItemId, Pointer, NextItemPointer _hasQbKey = true; itemQbKeyCrc = br.ReadUInt32(this.Root.PakFormat.EndianType); _pointer = br.ReadUInt32(this.Root.PakFormat.EndianType); _nextItemPointer = br.ReadUInt32(this.Root.PakFormat.EndianType); if (this.StreamPos(br) != _pointer) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _pointer)); } _itemCount = 1; _pointers = new uint[1]; _pointers[0] = _pointer; _length = (4 * 4); break; case QbFormat.StructItemValue: //Simple struct type: // ItemId, Value (4 byte), NextItemPointer _hasQbKey = true; itemQbKeyCrc = br.ReadUInt32(this.Root.PakFormat.EndianType); //always null? if (_itemQbKey == 0 && _qbItemType == QbItemType.StructItemQbKeyString) { _itemQbKey = null; } _itemCount = 1; _length = (2 * 4); break; case QbFormat.ArrayPointer: //Complex array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) _hasQbKey = false; _itemCount = br.ReadUInt32(this.Root.PakFormat.EndianType); _pointer = br.ReadUInt32(this.Root.PakFormat.EndianType); itemQbKeyCrc = 0; _length = (3 * 4); if (_pointer != 0 && this.StreamPos(br) != _pointer) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _pointer)); } _pointers = new uint[_itemCount]; if (_itemCount == 1) { _pointers[0] = _pointer; } else if (_itemCount > 1) { for (int i = 0; i < _itemCount; i++) { _pointers[i] = br.ReadUInt32(this.Root.PakFormat.EndianType); } _length += (_itemCount * 4); } break; case QbFormat.ArrayValue: //Simple array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) _hasQbKey = false; itemQbKeyCrc = 0; _itemCount = br.ReadUInt32(this.Root.PakFormat.EndianType); _length = (2 * 4); if (_itemCount > 1) { _pointer = br.ReadUInt32(this.Root.PakFormat.EndianType); if (this.StreamPos(br) != _pointer) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _pointer)); } _length += (1 * 4); } break; case QbFormat.StructHeader: //when struct array item _hasQbKey = false; _length = (1 * 4); break; case QbFormat.Floats: _hasQbKey = false; _length = (1 * 4); break; case QbFormat.Unknown: _hasQbKey = false; _position += 4; //there is no header so re add the previously removed 4 _length = (0 * 4); break; default: break; } #endregion if (!_hasQbKey) { _itemQbKey = null; } else { string debugName = Root.LookupDebugName(itemQbKeyCrc); if (debugName.Length != 0) { _itemQbKey = QbKey.Create(itemQbKeyCrc, debugName); } else { _itemQbKey = QbKey.Create(itemQbKeyCrc); } } }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); _isUnicode = ((type == QbItemType.SectionStringW || type == QbItemType.ArrayStringW || type == QbItemType.StructItemStringW) && (base.Root.PakFormat.PakFormatType == PakFormatType.PC || base.Root.PakFormat.PakFormatType == PakFormatType.XBox)); byte[] bytes; base.Construct(br, type); this.Strings = new string[base.ItemCount]; _charWidth = !_isUnicode ? 1 : 2; if (base.ItemCount != 0) { //use pointers to read quickly if (base.ItemCount > 1) { for (int i = 0; i < base.ItemCount - 1; i++) { if (base.StreamPos(br) != base.Pointers[i]) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[i])); } bytes = br.ReadBytes((int)((base.Pointers[i + 1] - _charWidth) - base.StreamPos(br))); _strings[i] = bytesToString(bytes); //handles unicode if (!_isUnicode ? (br.ReadByte() != 0) : (br.ReadByte() != 0 || br.ReadByte() != 0)) { throw new ApplicationException(string.Format("Null byte expected reading string array at 0x{0}", (base.StreamPos(br) - _charWidth).ToString("X").PadLeft(8, '0'))); } } if (base.StreamPos(br) != base.Pointers[base.ItemCount - 1]) //pointer test { throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[base.ItemCount - 1])); } } //use the slow method read the last string StringBuilder sb = new StringBuilder(); //if we have come from an array we must align our position to %4 int byteAmount = (int)(4 - (base.StreamPos(br) % 4)); do { bytes = br.ReadBytes(byteAmount); sb.Append(bytesToString(bytes)); byteAmount = 4; }while (!_isUnicode ? (bytes[bytes.Length - 1] != '\0') : (bytes[bytes.Length - 1] != '\0' || bytes[bytes.Length - 2] != '\0')); //get text and remove any trailing null bytes _strings[base.ItemCount - 1] = sb.ToString().TrimEnd(new char[] { '\0' }); } base.ConstructEnd(br); }
/// <summary> /// Call after derived class has read its data in Construct() /// </summary> /// <param name="br"></param> public virtual void ConstructEnd(BinaryEndianReader br) { #region switch switch (_qbFormat) { case QbFormat.SectionValue: //Simple section type: // ItemId, FileId, Value, Reserved _reserved = br.ReadUInt32(this.Root.PakFormat.EndianType); _length += (1 * 4); break; case QbFormat.StructItemPointer: if (_nextItemPointer != 0 && this.StreamPos(br) != _nextItemPointer) //pointer test throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _nextItemPointer)); break; case QbFormat.StructItemValue: //Simple struct type: // ItemId, Value (4 byte), NextItemPointer _nextItemPointer = br.ReadUInt32(this.Root.PakFormat.EndianType); _length += (1 * 4); if (_nextItemPointer != 0 && this.StreamPos(br) != _nextItemPointer) //pointer test throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _nextItemPointer)); break; case QbFormat.ArrayPointer: //Complex array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) for (int i = 0; i < _items.Count; i++) //_items.Count is 0 for strings (it checks it's own) { if (_pointers[i] != _items[i].Position) throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, _items[i].Position, _pointers[i])); } break; default: break; } #endregion setChildMode(); //_itemCount = (uint)this.CalcItemCount(); }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); _unknown = br.ReadUInt32(base.Root.PakFormat.EndianType); uint decompressedSize = br.ReadUInt32(base.Root.PakFormat.EndianType); uint compressedSize = br.ReadUInt32(base.Root.PakFormat.EndianType); // Get script data Lzss lz = new Lzss(); _scriptData = br.ReadBytes((int)compressedSize); if (compressedSize < decompressedSize) _scriptData = lz.Decompress(_scriptData); if (_scriptData.Length != decompressedSize) throw new ApplicationException(string.Format("Location 0x{0}: Script decompressed to {1} bytes not {2}", (base.StreamPos(br) - compressedSize).ToString("X").PadLeft(8, '0'), _scriptData.Length.ToString(), decompressedSize.ToString())); // Padding... if ((base.StreamPos(br) % 4) != 0) br.BaseStream.Seek(4 - (base.StreamPos(br) % 4), SeekOrigin.Current); base.ConstructEnd(br); }
/// <summary> /// Load type data from binary reader /// </summary> public virtual void Construct(BinaryEndianReader br, QbItemType type) { setQbFormat(type); _qbItemType = type; _qbItemValue = this.Root.PakFormat.GetQbItemValue(type, this.Root); _position = this.StreamPos(br) - (1 * 4); //subtract the already read header uint itemQbKeyCrc = 0; #region switch switch (_qbFormat) { case QbFormat.SectionPointer: //Complex section type: // ItemId, FileId, Pointer, Reserved _hasQbKey = true; itemQbKeyCrc = br.ReadUInt32(this.Root.PakFormat.EndianType); _fileId = br.ReadUInt32(this.Root.PakFormat.EndianType); _pointer = br.ReadUInt32(this.Root.PakFormat.EndianType); _reserved = br.ReadUInt32(this.Root.PakFormat.EndianType); _length = (5*4); if (type == QbItemType.SectionScript) _itemCount = 0; else _itemCount = 1; _pointers = new uint[1]; _pointers[0] = _pointer; if (this.StreamPos(br) != _pointer) //pointer test throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _pointer)); break; case QbFormat.SectionValue: //Simple section type: // ItemId, FileId, Value, Reserved _hasQbKey = true; itemQbKeyCrc = br.ReadUInt32(this.Root.PakFormat.EndianType); _fileId = br.ReadUInt32(this.Root.PakFormat.EndianType); _itemCount = 1; _length = (3*4); break; case QbFormat.StructItemPointer: //Complex struct type: // ItemId, Pointer, NextItemPointer _hasQbKey = true; itemQbKeyCrc = br.ReadUInt32(this.Root.PakFormat.EndianType); _pointer = br.ReadUInt32(this.Root.PakFormat.EndianType); _nextItemPointer = br.ReadUInt32(this.Root.PakFormat.EndianType); if (this.StreamPos(br) != _pointer) //pointer test throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _pointer)); _itemCount = 1; _pointers = new uint[1]; _pointers[0] = _pointer; _length = (4*4); break; case QbFormat.StructItemValue: //Simple struct type: // ItemId, Value (4 byte), NextItemPointer _hasQbKey = true; itemQbKeyCrc = br.ReadUInt32(this.Root.PakFormat.EndianType); //always null? if (_itemQbKey == 0 && _qbItemType == QbItemType.StructItemQbKeyString) _itemQbKey = null; _itemCount = 1; _length = (2*4); break; case QbFormat.ArrayPointer: //Complex array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) _hasQbKey = false; _itemCount = br.ReadUInt32(this.Root.PakFormat.EndianType); _pointer = br.ReadUInt32(this.Root.PakFormat.EndianType); itemQbKeyCrc = 0; _length = (3 * 4); if (_pointer != 0 && this.StreamPos(br) != _pointer) //pointer test throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _pointer)); _pointers = new uint[_itemCount]; if (_itemCount == 1) _pointers[0] = _pointer; else if (_itemCount > 1) { for (int i = 0; i < _itemCount; i++) _pointers[i] = br.ReadUInt32(this.Root.PakFormat.EndianType); _length += (_itemCount * 4); } break; case QbFormat.ArrayValue: //Simple array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) _hasQbKey = false; itemQbKeyCrc = 0; _itemCount = br.ReadUInt32(this.Root.PakFormat.EndianType); _length = (2*4); if (_itemCount > 1) { _pointer = br.ReadUInt32(this.Root.PakFormat.EndianType); if (this.StreamPos(br) != _pointer) //pointer test throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, this.StreamPos(br), _pointer)); _length += (1 * 4); } break; case QbFormat.StructHeader: //when struct array item _hasQbKey = false; _length = (1 * 4); break; case QbFormat.Floats: _hasQbKey = false; _length = (1 * 4); break; case QbFormat.Unknown: _hasQbKey = false; _position += 4; //there is no header so re add the previously removed 4 _length = (0*4); break; default: break; } #endregion if (!_hasQbKey) _itemQbKey = null; else { string debugName = Root.LookupDebugName(itemQbKeyCrc); if (debugName.Length != 0) _itemQbKey = QbKey.Create(itemQbKeyCrc, debugName); else _itemQbKey = QbKey.Create(itemQbKeyCrc); } }
private void parse(Stream stream) { _streamStartPosition = stream.Position; _items = new List <QbItemBase>(); //if (stream.Position != 0) // throw new ApplicationException("The stream must start at position 0 as this parser uses the position to validate pointers."); using (BinaryEndianReader br = new BinaryEndianReader(stream)) { _magic = br.ReadUInt32(this.PakFormat.EndianType); _fileSize = br.ReadUInt32(this.PakFormat.EndianType); uint sectionValue; QbItemBase qib = new QbItemUnknown(20, this); qib.Construct(br, QbItemType.Unknown); AddItem(qib); while (this.StreamPos(br.BaseStream) < _fileSize) { sectionValue = br.ReadUInt32(this.PakFormat.EndianType); QbItemType sectionType = this.PakFormat.GetQbItemType(sectionValue); switch (sectionType) { case QbItemType.SectionString: case QbItemType.SectionStringW: qib = new QbItemString(this); break; case QbItemType.SectionArray: qib = new QbItemArray(this); break; case QbItemType.SectionStruct: qib = new QbItemStruct(this); break; case QbItemType.SectionScript: qib = new QbItemScript(this); break; case QbItemType.SectionFloat: qib = new QbItemFloat(this); break; case QbItemType.SectionFloatsX2: case QbItemType.SectionFloatsX3: qib = new QbItemFloatsArray(this); break; case QbItemType.SectionInteger: case QbItemType.SectionStringPointer: qib = new QbItemInteger(this); break; case QbItemType.SectionQbKey: case QbItemType.SectionQbKeyString: case QbItemType.SectionQbKeyStringQs: //GH:GH qib = new QbItemQbKey(this); break; default: throw new ApplicationException(string.Format("Location 0x{0}: Unknown section type 0x{1}", (this.StreamPos(br.BaseStream) - 4).ToString("X").PadLeft(8, '0'), sectionValue.ToString("X").PadLeft(8, '0'))); } qib.Construct(br, sectionType); AddItem(qib); } } uint f = this.FileId; //gettin this sets the file id }
protected uint StreamPos(BinaryEndianReader br) { return Root.StreamPos(br.BaseStream); }
public static void CreateSilentWav(int length, string dstFilename, params string[] srcFilenames) { if (srcFilenames == null || (srcFilenames.Length == 1 && srcFilenames[0].Length == 0)) return; FileHelper.Delete(dstFilename); WavSingleChunkHeader[] whi = new WavSingleChunkHeader[srcFilenames.Length]; BinaryEndianReader[] br = new BinaryEndianReader[srcFilenames.Length]; int outWav = 0; //use this input wav as the format for the output wav for (int c = 0; c < srcFilenames.Length; c++) { br[c] = new BinaryEndianReader(File.OpenRead(srcFilenames[c])); whi[c] = ParseWavSingleChunkHeader(br[c].BaseStream); if (whi[c].Channels == 2) outWav = c; } WavSingleChunkHeader who = new WavSingleChunkHeader(); uint wLength = (uint)((float)whi[outWav].AvgBytesPerSec * (float)(length / 1000F)); wLength -= wLength % whi[outWav].BlockAlign; who.FileId = "RIFF"; who.FileLength = (uint)(whi[outWav].DataOffset + wLength) - 8; who.RiffType = "WAVE"; who.ChunkHeaderId = "fmt "; who.ChunkHeaderLength = whi[outWav].ChunkHeaderLength; who.FormatTag = whi[outWav].FormatTag; who.Channels = whi[outWav].Channels; who.SamplesPerSec = whi[outWav].SamplesPerSec; who.AvgBytesPerSec = whi[outWav].AvgBytesPerSec; who.BlockAlign = whi[outWav].BlockAlign; who.BitsPerSample = whi[outWav].BitsPerSample; who.ExtraBytes = whi[outWav].ExtraBytes; who.ChunkId = "data"; who.ChunkLength = wLength; foreach (BinaryEndianReader b in br) b.Close(); using (FileStream fso = File.OpenWrite(dstFilename)) { WriteSingleChunkHeader(who, fso); byte[] buffer = new byte[who.AvgBytesPerSec]; for (int i = 0; i < buffer.Length; i++) buffer[i] = 0; long written = 0; while (written + buffer.Length < wLength) { fso.Write(buffer, 0, buffer.Length); written += buffer.Length; } if (written != wLength) fso.Write(buffer, 0, (int)(wLength - written)); fso.Flush(); } }
/// <summary> /// Test for silent wavs /// </summary> /// <param name="filename">input raw wav</param> /// <param name="tolerence">0=0% to 1=1%</param> /// <returns></returns> public static bool IsWavSilent(string filename, float tolerence) { long tested = 0; long silent = 0; int pos; using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) { WavSingleChunkHeader h = WavProcessor.ParseWavSingleChunkHeader(fs); BinaryEndianReader br = new BinaryEndianReader(fs); for (int i = h.DataOffset; i < ((int)h.ChunkLength - 1024); i += (1024 * 1024)) //check at each meg { int block = 0; pos = i; fs.Seek((long)pos, SeekOrigin.Begin); while (block != 1024) //length is block aligned so don't worry about channel count { if (br.ReadInt16(EndianType.Little) == 0) silent += 2; tested += 2; block++; } } } if (((double)silent / (double)tested) >= (double)tolerence) return true; else return false; }
public static WavSingleChunkHeader ParseWavSingleChunkHeader(Stream wavStream) { WavSingleChunkHeader w = new WavSingleChunkHeader(); byte[] b; BinaryEndianReader r = new BinaryEndianReader(wavStream); b = r.ReadBytes(4); w.FileId = Encoding.Default.GetString(b); w.FileLength = r.ReadUInt32(EndianType.Little); b = r.ReadBytes(4); w.RiffType = Encoding.Default.GetString(b); b = r.ReadBytes(4); w.ChunkHeaderId = Encoding.Default.GetString(b); w.ChunkHeaderLength = r.ReadUInt32(EndianType.Little); long p = wavStream.Position; w.FormatTag = r.ReadUInt16(EndianType.Little); w.Channels = r.ReadUInt16(EndianType.Little); w.SamplesPerSec = r.ReadUInt32(EndianType.Little); w.AvgBytesPerSec = r.ReadUInt32(EndianType.Little); w.BlockAlign = r.ReadUInt16(EndianType.Little); w.BitsPerSample = r.ReadUInt16(EndianType.Little); if (wavStream.Position - p != w.ChunkHeaderLength) w.ExtraBytes = r.ReadBytes((int)(w.ChunkHeaderLength - (wavStream.Position - p))); b = r.ReadBytes(4); w.ChunkId = Encoding.Default.GetString(b); w.ChunkLength = r.ReadUInt32(EndianType.Little); w.DataOffset = (int)wavStream.Position; return w; }
public override void Construct(BinaryEndianReader br, QbItemType type) { //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.Construct(br, type); uint pointer; if (type != QbItemType.StructHeader) _headerValue = br.ReadUInt32(base.Root.PakFormat.EndianType); else _headerValue = base.Root.PakFormat.GetQbItemValue(type, this.Root); _headerType = base.Root.PakFormat.GetQbItemType(_headerValue); QbItemBase qib = null; QbItemType structType; uint structValue; if (_headerType == QbItemType.StructHeader) { pointer = br.ReadUInt32(base.Root.PakFormat.EndianType); //Should be the current stream position after reading _iniNextItemPointer = pointer; if (pointer != 0 && base.StreamPos(br) != pointer) //pointer test throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), pointer)); while (pointer != 0) { structValue = br.ReadUInt32(this.Root.PakFormat.EndianType); structType = this.Root.PakFormat.GetQbItemType(structValue); switch (structType) { case QbItemType.StructItemStruct: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemStruct(this.Root); break; case QbItemType.StructItemStringPointer: case QbItemType.StructItemInteger: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemInteger(this.Root); break; case QbItemType.StructItemQbKeyString: case QbItemType.StructItemQbKeyStringQs: case QbItemType.StructItemQbKey: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemQbKey(this.Root); break; case QbItemType.StructItemString: case QbItemType.StructItemStringW: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemString(this.Root); break; case QbItemType.StructItemFloat: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemFloat(this.Root); break; case QbItemType.StructItemFloatsX2: case QbItemType.StructItemFloatsX3: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemFloatsArray(this.Root); break; case QbItemType.StructItemArray: this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.StructItems; qib = new QbItemArray(this.Root); break; //Convert array types to structitems to fit in with this parser (if QbFile.HasStructItems is false then internal type will be swapped back to array) case QbItemType.ArrayStruct: structType = QbItemType.StructItemStruct; qib = new QbItemArray(this.Root); break; case QbItemType.ArrayInteger: structType = QbItemType.StructItemInteger; qib = new QbItemInteger(this.Root); break; case QbItemType.ArrayQbKeyString: structType = QbItemType.StructItemQbKeyString; qib = new QbItemQbKey(this.Root); break; case QbItemType.ArrayStringPointer: structType = QbItemType.StructItemStringPointer; qib = new QbItemInteger(this.Root); break; case QbItemType.ArrayQbKeyStringQs: structType = QbItemType.StructItemQbKeyStringQs; qib = new QbItemQbKey(this.Root); break; case QbItemType.ArrayQbKey: structType = QbItemType.StructItemQbKey; qib = new QbItemQbKey(this.Root); break; case QbItemType.ArrayString: structType = QbItemType.StructItemString; qib = new QbItemString(this.Root); break; case QbItemType.ArrayStringW: structType = QbItemType.StructItemStringW; qib = new QbItemString(this.Root); break; case QbItemType.ArrayFloat: structType = QbItemType.StructItemFloat; qib = new QbItemFloat(this.Root); break; case QbItemType.ArrayFloatsX2: structType = QbItemType.StructItemFloatsX2; qib = new QbItemFloatsArray(this.Root); break; case QbItemType.ArrayFloatsX3: structType = QbItemType.StructItemFloatsX3; qib = new QbItemFloatsArray(this.Root); break; case QbItemType.ArrayArray: structType = QbItemType.StructItemArray; qib = new QbItemArray(this.Root); break; default: qib = null; break; } if (qib != null) { if (this.Root.PakFormat.StructItemChildrenType == StructItemChildrenType.NotSet) //will have been set to structItem if qib is not null) this.Root.PakFormat.StructItemChildrenType = StructItemChildrenType.ArrayItems; qib.Construct(br, structType); AddItem(qib); pointer = qib.NextItemPointer; } else throw new ApplicationException(string.Format("Location 0x{0}: Unknown item type 0x{1} in struct ", (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'), structValue.ToString("X").PadLeft(8, '0'))); } } else throw new ApplicationException(string.Format("Location 0x{0}: Struct without header type", (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0'))); base.ConstructEnd(br); }