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); }
/// <summary> /// Rename the filename and set the data types /// </summary> /// <param name="newFullQbFilename">Full QB filename</param> /// <param name="fileType">.qb or .sqb=QB, .mqb=mid, .img=img .dbg=dbg etc</param> /// <param name="extension">.ngc for Wii for example</param> /// <param name="baseOn">base the qbKeys that are present on the passed item</param> public void SetFilename(string newFullQbFilename, QbKey itemType, string extension, PakHeaderItem baseOn) { if (newFullQbFilename.Length > PakHeaderItem.FileNameMaxLength) { throw new ApplicationException("newQbFilename is too long"); } if (!itemType.HasText || itemType.Text.Length == 0) { throw new ApplicationException("fileType is not recognised"); } //filename is stored in the header if ((this.Flags & PakHeaderFlags.Filename) == PakHeaderFlags.Filename) { this.Filename = newFullQbFilename; this.FullFilenameQbKey = 0; } else { this.Filename = QbKey.Create(newFullQbFilename).Crc.ToString("X").PadLeft(8, '0').ToLower(); if (baseOn == null || baseOn.FullFilenameQbKey != 0) { this.FullFilenameQbKey = QbKey.Create(newFullQbFilename).Crc; } else { this.FullFilenameQbKey = 0; } } string[] pts = newFullQbFilename.Split('.'); string nameOnly = pts[0]; if (baseOn == null || baseOn.FullFilenameQbKey != 0) { this.NameOnlyCrc = QbKey.Create(nameOnly).Crc; } else { this.NameOnlyCrc = 0; } this.FileType = itemType; if (baseOn == null || baseOn.PakFullFileNameQbKey != 0) { this.PakFullFileNameQbKey = QbKey.Create(newFullQbFilename).Crc; } else { this.PakFullFileNameQbKey = 0; } }
public QbKey ToQbKey() { Type t = typeof(QbKey); if (t != _type) { throw new ApplicationException(getToError(_type, t)); } return(QbKey.Create(_value)); }
public QbKey Clone() { if (this.HasText) { return(QbKey.Create(this.Text)); } else { return(QbKey.Create(this.Crc)); } }
private void loadNonDebugQbKey() { if (File.Exists(FullNonDebugQbKeyFilename)) { string[] f; foreach (string s in File.ReadAllLines(FullNonDebugQbKeyFilename)) { f = s.Split('|'); AddNonDebugQbKey(QbKey.Create(uint.Parse(f[0].Substring(2), System.Globalization.NumberStyles.HexNumber), f[1]), f[2], null); } } }
/// <summary> /// The FileId is based on the filename, this will recalculate it, GH3 has a bug where the first character is missing from the path. /// The FileId doesn't appear to affect the game, it may just need to be unique /// </summary> public void SetNewFileId() { uint fileId = QbKey.Create(this.Filename).Crc; foreach (QbItemBase qbi in this.Items) { if (qbi.QbItemType != QbItemType.Unknown) { qbi.FileId = fileId; } } }
static PakHeaderItem() { // qb, qb, debug, image, midi string[] s = new string[] { ".qb", ".sqb", ".dbg", ".img", ".mqb", ".tex", ".skin", ".cam", ".col", ".fam", ".fnc", ".fnt", ".fnv", ".gap", ".hkc", ".imv", ".last", ".mcol", ".mdl", ".mdv", ".nav", ".nqb", ".oba", ".pfx", ".pimg", ".png", ".rag", ".rnb", ".rnb_lvl", ".rnb_mdl", ".scn", ".scv", ".shd", ".ska", ".ske", ".skiv", ".stex", ".table", ".tvx", ".wav", ".empty", ".clt", ".jam", ".note", ".nqb", ".perf", ".pimv", ".qs", ".qs.br", ".qs.de", ".qs.en", ".qs.es", ".qs.fr", ".qs.it", ".raw", ".rgn", ".trkobj", ".xml" }; _itemTypes = new QbKey[s.Length]; for (int i = 0; i < s.Length; i++) { _itemTypes[i] = QbKey.Create(s[i]); } }
public override void Create(QbItemType type) { if (type != QbItemType.SectionQbKey && type != QbItemType.SectionQbKeyString && type != QbItemType.SectionQbKeyStringQs && type != QbItemType.ArrayQbKey && type != QbItemType.ArrayQbKeyString && type != QbItemType.ArrayQbKeyStringQs && type != QbItemType.StructItemQbKey && type != QbItemType.StructItemQbKeyString && type != QbItemType.StructItemQbKeyStringQs) { throw new ApplicationException(string.Format("type '{0}' is not a QB key item type", type.ToString())); } base.Create(type); this.Values = new QbKey[1]; //sets item count _values[0] = QbKey.Create(0); }
/// <summary> /// Convert text representations /// </summary> /// <param name="text"></param> /// <param name="toType">Type to convert to</param> /// <returns></returns> private string convert(Type toType) { byte[] b = null; float f; uint u; int i; string result = _value; if (_currType == null) { _currType = _type; } if (_currType == toType) { return(_value); } if (!this.CanConvertTo(toType)) { return(_value); } //if QBKey then swap between Hex and String if (_type == typeof(QbKey)) { QbKey qb = QbKey.Create(_value); if (_currType == typeof(byte[]) && toType == typeof(string)) { if (_qbKey == qb) { return(_qbKey.ToString()); } else { return(qb.ToString()); } } else if (_currType == typeof(string) && toType == typeof(byte[])) { if (_value.Trim().Length != 0) { _qbKey = QbKey.Create(_value); } return(_qbKey.Crc.ToString("X").PadLeft(8, '0')); } else { return(_value); } } //get the data into a byte array if (_currType == typeof(float)) { if (float.TryParse(_value, out f)) { b = BitConverter.GetBytes(f); } } else if (_currType == typeof(uint)) { if (uint.TryParse(_value, out u)) { b = BitConverter.GetBytes(u); } } else if (_currType == typeof(int)) { if (int.TryParse(_value, out i)) { b = BitConverter.GetBytes(i); } } else if (_currType == typeof(byte[])) { if (_value.Length > 2) { b = new byte[_value.Length / 2]; for (int c = 0; c < _value.Length; c += 2) { b[c / 2] = byte.Parse(_value.Substring(c, 2), System.Globalization.NumberStyles.HexNumber); } if (_typeNumeric && BitConverter.IsLittleEndian) { Array.Reverse(b); } } } else if (_currType == typeof(string)) { b = Encoding.Default.GetBytes(_value); } //else // throw new ArgumentOutOfRangeException(string.Format("{0} is not supported", _currType.FullName)); if (b != null) { //convert the data to the new type if (toType == typeof(float)) { f = BitConverter.ToSingle(b, 0); result = f.ToString(); } else if (toType == typeof(uint)) { u = BitConverter.ToUInt32(b, 0); result = u.ToString(); } else if (toType == typeof(int)) { i = BitConverter.ToInt32(b, 0); result = i.ToString(); } else if (toType == typeof(byte[])) { StringBuilder sb = new StringBuilder(); if (_typeNumeric && BitConverter.IsLittleEndian) { Array.Reverse(b); } foreach (byte x in b) { sb.Append(x.ToString("X").PadLeft(2, '0')); } result = sb.ToString(); } else if (toType == typeof(string)) { result = Encoding.Default.GetString(b); } //else // throw new ArgumentOutOfRangeException(string.Format("{0} is not supported", toType.FullName)); } return(result); }
public static void SetGenericItems(QbItemBase item, List <GenericQbItem> gItems) { MemberInfo[] ms = item.GetType().FindMembers(MemberTypes.Property, /*BindingFlags.DeclaredOnly |*/ BindingFlags.Instance | BindingFlags.Public, Type.FilterName, "*"); int i = 0; GenericQbItem gi; List <GenericQbItem> list = null; if (gItems.Count == 0) { //test if this is an array item GenericQbItem gqi = QbFile.CreateGenericArrayItem(item); //null if not an array type if (gqi != null) { //use this item to identify the array to set to 0 items MemberInfo m = Array.Find(ms, delegate(MemberInfo mi) { return(mi.Name == gqi.SourceProperty); }); if (m != null) { Type t = ((PropertyInfo)m).GetValue(item, null).GetType(); if (t == typeof(QbKey[])) { ((PropertyInfo)m).SetValue(item, new QbKey[0], null); } else if (t == typeof(float[])) { ((PropertyInfo)m).SetValue(item, new float[0], null); } else if (t == typeof(uint[])) { ((PropertyInfo)m).SetValue(item, new uint[0], null); } else if (t == typeof(int[])) { ((PropertyInfo)m).SetValue(item, new int[0], null); } else if (t == typeof(string[])) { ((PropertyInfo)m).SetValue(item, new string[0], null); } } } } while (i < gItems.Count) { gi = gItems[i++]; if (gi.ReadOnly) { continue; } //list = null; list = new List <GenericQbItem>(); list.Add(gi); while (i < gItems.Count && gi.SourceProperty == gItems[i].SourceProperty) { list.Add(gItems[i++]); } MemberInfo m = Array.Find(ms, delegate(MemberInfo mi) { return(mi.Name == gi.SourceProperty); }); if (m != null) { Type t = ((PropertyInfo)m).GetValue(item, null).GetType(); if (t == typeof(QbKey[])) { QbKey[] qb = new QbKey[list.Count]; QbKey q; string qS; for (int c = 0; c < list.Count; c++) { q = list[c].ToQbKey(); qS = item.Root.LookupDebugName(q.Crc); if (qS.Length != 0) { q = QbKey.Create(q.Crc, qS); } qb[c] = q; } ((PropertyInfo)m).SetValue(item, qb, null); } else if (t == typeof(float[])) { float[] f = new float[list.Count]; for (int c = 0; c < list.Count; c++) { f[c] = list[c].ToSingle(); } ((PropertyInfo)m).SetValue(item, f, null); } else if (t == typeof(uint[])) { uint[] ui = new uint[list.Count]; for (int c = 0; c < list.Count; c++) { ui[c] = list[c].ToUInt32(); } ((PropertyInfo)m).SetValue(item, ui, null); } else if (t == typeof(int[])) { int[] si = new int[list.Count]; for (int c = 0; c < list.Count; c++) { si[c] = list[c].ToInt32(); } ((PropertyInfo)m).SetValue(item, si, null); } else if (t == typeof(string[])) { string[] s = new string[list.Count]; for (int c = 0; c < list.Count; c++) { s[c] = list[c].ToString(); } ((PropertyInfo)m).SetValue(item, s, null); } else if (t == typeof(QbKey)) { QbKey q = gi.ToQbKey(); string qS = item.Root.LookupDebugName(q.Crc); if (qS.Length != 0) { q = QbKey.Create(q.Crc, qS); } ((PropertyInfo)m).SetValue(item, q, null); } else if (t == typeof(float)) { ((PropertyInfo)m).SetValue(item, gi.ToSingle(), null); } else if (t == typeof(uint)) { ((PropertyInfo)m).SetValue(item, gi.ToUInt32(), null); } else if (t == typeof(int)) { ((PropertyInfo)m).SetValue(item, gi.ToInt32(), null); } else if (t == typeof(string)) { ((PropertyInfo)m).SetValue(item, gi.ToString(), null); } else if (t == typeof(byte[])) { ((PropertyInfo)m).SetValue(item, gi.ToByteArray(), null); } else { throw new ApplicationException(string.Format("DataType {0} not supported.", t.Name)); } } } }
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)); } }
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 } }
/// <summary> /// Load type data from binary reader /// </summary> public virtual void Create(QbItemType type) { setQbFormat(type); _qbItemType = type; _qbItemValue = this.Root.PakFormat.GetQbItemValue(type, this.Root); _position = 0; //unknown #region switch switch (_qbFormat) { case QbFormat.SectionPointer: //Complex section type: // ItemId, FileId, Pointer, Reserved _itemQbKey = QbKey.Create(0); _fileId = this.Root.FileId; _pointer = 0; _reserved = 0; _length = (5 * 4); _itemCount = 1; _pointers = new uint[1]; _pointers[0] = 0; break; case QbFormat.SectionValue: //Simple section type: // ItemId, FileId, Value, Reserved _itemQbKey = QbKey.Create(0); _fileId = this.Root.FileId; _itemCount = 1; _length = (4 * 4); break; case QbFormat.StructItemPointer: //Complex struct type: // ItemId, Pointer, NextItemPointer _itemQbKey = QbKey.Create(0); _pointer = 0; _nextItemPointer = 0; _itemCount = 1; _pointers = new uint[1]; _pointers[0] = _pointer; _length = (4 * 4); break; case QbFormat.StructItemValue: //Simple struct type: // ItemId, Value (4 byte), NextItemPointer _itemQbKey = QbKey.Create(0); //always null? _itemCount = 1; _length = (3 * 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) _itemCount = 0; _pointer = 0; _itemQbKey = null; _length = (3 * 4); _pointers = new uint[_itemCount]; break; case QbFormat.ArrayValue: //Simple array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) _itemQbKey = null; _itemCount = 0; _length = (2 * 4); break; case QbFormat.StructHeader: //when struct array item _length = (1 * 4); break; case QbFormat.Floats: _itemCount = 2; _length = (1 * 4); break; case QbFormat.Unknown: _position += 4; //there is no header so re add the previously removed 4 _length = (0 * 4); break; default: break; } #endregion setChildMode(); _itemCount = (uint)this.CalcItemCount(); }
/// <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); } } }