protected override bool OnInitialize() { RSARNode parent; //Find bank entry in rsar if ((_name == null) && ((parent = RSARNode) != null)) { RSARHeader *rsar = parent.Header; RuintList * list = rsar->INFOBlock->Banks; VoidPtr offset = &rsar->INFOBlock->_collection; SYMBHeader *symb = rsar->SYMBBlock; int count = list->_numEntries; for (int i = 0; i < count; i++) { INFOBankEntry *bank = (INFOBankEntry *)list->Get(offset, i); if (bank->_fileId == _fileIndex) { _name = symb->GetStringEntry(bank->_stringId); break; } } } base.OnInitialize(); ParseBlocks(); return(true); }
private static int EncodeMaskGroup(SYMBHeader *symb, SYMBMaskHeader *header, List <RSAREntryNode> gList, RSARNode n, int grp) { int[] stringIds = gList.Select(x => x._rebuildStringId).Where(x => x >= 0).ToArray(); SYMBMaskEntry.Build(stringIds, symb, header, header->Entries); return(SYMBMaskHeader.Size + (stringIds.Length * 2 - 1) * SYMBMaskEntry.Size); }
internal int EncodeSYMBBlock(SYMBHeader *header, RSAREntryList entries, RSARNode node) { int len = 0; int count = entries._strings.Count; VoidPtr baseAddr = (VoidPtr)header + 8, dataAddr; bint * strEntry = (bint *)(baseAddr + 0x18); PString pStr = (byte *)strEntry + (count << 2); //Strings header->_stringOffset = 0x14; strEntry[-1] = entries._strings.Count; foreach (string s in entries._strings) { *strEntry++ = (int)(pStr - baseAddr); pStr.Write(s, 0, s.Length + 1); pStr += s.Length + 1; } dataAddr = pStr; //Sounds header->_maskOffset1 = (int)(dataAddr - baseAddr); dataAddr += EncodeMaskGroup(header, (SYMBMaskHeader *)dataAddr, entries._sounds, node, 0); //Player Info header->_maskOffset2 = (int)(dataAddr - baseAddr); dataAddr += EncodeMaskGroup(header, (SYMBMaskHeader *)dataAddr, entries._playerInfo, node, 1); //Groups header->_maskOffset3 = (int)(dataAddr - baseAddr); dataAddr += EncodeMaskGroup(header, (SYMBMaskHeader *)dataAddr, entries._groups, node, 2); //Banks header->_maskOffset4 = (int)(dataAddr - baseAddr); dataAddr += EncodeMaskGroup(header, (SYMBMaskHeader *)dataAddr, entries._banks, node, 3); int temp = (int)dataAddr - (int)header; len = temp.Align(0x20); //Fill padding byte *p = (byte *)dataAddr; for (int i = temp; i < len; i++) { *p++ = 0; } //Set header header->_header._tag = SYMBHeader.Tag; header->_header._length = len; return(len); }
//Code written by Mawootad public static void Build(int[] indices, SYMBHeader *header, SYMBMaskHeader *maskHeader, SYMBMaskEntry *entries) { //initialization maskHeader->_rootId = 0; maskHeader->_numEntries = 0; //Loop over indicies and add them. This seems to be roughly how the file is normally built, as it has the same resulting leaf-node-leaf-node pattern foreach (int id in indices) { AddToTrie(entries, maskHeader, id, header); } }
//Failed attempts at generating symb ids commented out below, enjoy //static void GenIds(SYMBHeader* symb, SYMBMaskHeader* header, int index, ushort allowedBit) //{ // SYMBMaskEntry* first = &header->Entries[index]; // string mainName = symb->GetStringEntry(first->_stringId); // for (int i = 1; i < header->_numEntries; i += 2) // { // SYMBMaskEntry* secName = &header->Entries[i]; // SYMBMaskEntry* secBit = &header->Entries[i + 1]; // if (i == index || secBit->_bit != allowedBit) // continue; // string compName = symb->GetStringEntry(secName->_stringId); // int bitIndex = mainName.CompareBits(compName); // if (bitIndex >= 0) // { // //Set the bit index // secBit->_bit = (ushort)bitIndex; // int bit = bitIndex % 8; // int byteIndex = (bitIndex - bit) / 8; // bool leftFound = false, rightFound = false; // mainName = compName; // //Keeping looking down the list for the left and right entries // for (int x = i + 2; x < header->_numEntries; x += 2) // { // SYMBMaskEntry* lrName = &header->Entries[x]; // SYMBMaskEntry* lrBit = &header->Entries[x + 1]; // compName = symb->GetStringEntry(lrName->_stringId); // if (x == index || lrBit->_bit != allowedBit) // continue; // bool forceLeft = false; // if (byteIndex >= Math.Min(mainName.Length, compName.Length)) // forceLeft = true; // if (forceLeft || mainName.AtBit(bitIndex) != compName.AtBit(bitIndex)) // { // if (leftFound) // continue; // leftFound = true; // secBit->_leftId = x + 1; // GenIds(symb, header, x, lrBit->_bit); // } // else // { // if (rightFound) // continue; // rightFound = true; // secBit->_rightId = x + 1; // GenIds(symb, header, x, lrBit->_bit); // } // } // if (!leftFound) //No strings matched // secBit->_leftId = i; // else if (!rightFound) //All strings matched // secBit->_rightId = i; // break; // } // } //} //String Table to convert to a tree //string[] stringTable = new string[] { "SDPLAYER_BGM", "SDPLAYER_SE", "SDPLAYER_VOICE", "SDPLAYER_SYSTEM", "SDPLAYER_LOOP", "SDPLAYER_VOICE2", "SDPLAYER_SE_NOEFFECT" }; //public class TEntry //{ // public string _string; // public string _binary; // public int _bit = -1; // public int _leftID = -1; // public int _rightID = -1; // public int _stringID; // public int _id; // public TEntry(RSAREntryState s) // { // _binary = (_string = s._node._fullPath).ToBinaryArray(); // _stringID = s._stringId; // _id = s._index; // } //} //Making the output table to save me buttloads of time >.> //public void convertToBinary(string): // ''' Converts a text string to a string representation of itself in binary. ''' // return ''.join(['%08d'%int(bin(ord(i))[2:]) for i in string]) //Populating an empty table for my own convenience. //I assume the stringlist is ordered by ID, and is the first and only segment in the symb. //Cause I'm a lazy bastard. //Normal String, String (in binary), bit, LeftID, RightID, StringID, ID //outputTable = [{'string':stringTable[x], 'binary':convertToBinary(stringTable[x]), // 'bit':-1, 'LeftID':-1, 'RightID':-1, 'StringID':x, 'ID':x} for x in xrange(len(stringTable))] //private static void WriteData(List<TEntry> Left, List<TEntry> Right, int bit) //{ // //Writes all the necessary information to the node // TEntry currentNode = Right[0]; // //Write Position // currentNode._bit = bit; // //Write the left branch (matching) This is a bit fugly, because of how I handle the output table. // //I basically determine the 'line' based off the ID. // if (Left.Count > 1) // currentNode._leftID = Left[0]._id * 2; // else // { // currentNode._leftID = Left[0]._id * 2 - 1; // //Edge case for the first node, who has no -1 line. // if (currentNode._leftID < 0) // currentNode._leftID = 0; // } // if (Right.Count > 1) // currentNode._rightID = Right[1]._id * 2; // else // { // currentNode._rightID = Right[0]._id * 2 - 1; // //Edge case for the first node, who has no -1 line. // if (currentNode._rightID < 0) // currentNode._rightID = 0; // } //} //private static void SplitTable(List<TEntry> outputTable, out List<TEntry> Left, out List<TEntry> Right) //{ // //Splits the table in two and writes the data // TEntry originalNode = outputTable[0]; // List<TEntry> Temp; // //Iterate bit by bit // int bit = 0, entry = 0; // for (bit = 0; bit < originalNode._binary.Length; bit++) // { // char compareBit = originalNode._binary[bit]; // //Go over the table // for (entry = 0; entry < outputTable.Count; entry++) // { // //F*****g Ugly edge case - initial string is too long to compare // if (bit >= outputTable[entry]._binary.Length) // { // //Python stuff to change the 'start' of the table to the current position // Temp = outputTable.ShiftFirst(entry); // //Split the ordered table there into Left (matching) and right (non-matching) // Left = new List<TEntry> { outputTable[entry] }; // Right = new List<TEntry>(); // foreach (TEntry t in Temp) // if (t._id != outputTable[entry]._id) // Right.Add(t); // WriteData(Left, Right, bit); // //It splits! // return; // } // //This is the normal case - applies 90% of the time, I find. // if (outputTable[entry]._binary[bit] != compareBit) // { // //Python stuff to change the 'start' of the table to the current position // Temp = outputTable.ShiftFirst(entry); // //Split the ordered table there into Left (matching) and right (non-matching) // Left = new List<TEntry>(); // foreach (TEntry t in Temp) // if (t._binary[bit] == '0') // Left.Add(t); // Right = new List<TEntry>(); // foreach (TEntry t in Temp) // if (t._binary[bit] == '1') // Right.Add(t); // WriteData(Left, Right, bit); // //It splits! // return; // } // } // } // //If it got this far, then it ran out of bits. // //So now we gotta // //Split the ordered table there into Left (matching) and right (non-matching) // Left = new List<TEntry> { originalNode }; // Right = new List<TEntry>(); // foreach (TEntry t in outputTable) // if (t._id != originalNode._id) // Right.Add(t); // WriteData(Left, Right, bit); // //It splits! // return; //} //public static void CalcMatch(List<TEntry> outputTable) //{ // //Split the Table by node // List<TEntry> Left, Right; // SplitTable(outputTable, out Left, out Right); // //foreach (TEntry t in Left) // // Console.WriteLine(String.Format("Left: {0} {1} {2} {3} ", t._string, t._bit, t._leftID, t._rightID)); // //Console.WriteLine("-------------------------------------------------"); // //foreach (TEntry t in Right) // // Console.WriteLine(String.Format("Right: {0} {1} {2} {3} ", t._string, t._bit, t._leftID, t._rightID)); // if (Left.Count > 1) // CalcMatch(Left); // if (Right.Count > 1) // CalcMatch(Right); //} //public class PatriciaTree //{ // public string[] strings; // public string[] bin_strings; // public int out_node_idx = 0; // public PatriciaTree(string[] str) // { // strings = str; // bin_strings = strings.Select(x => x.ToBinaryArray()).ToArray(); // } // public int[] partition_tree(List<int> idx_list, int position) // { // List<int> left = new List<int>(), right = new List<int>(); // for (int i = 0; i < idx_list.Count; i++ ) // { // string bstr = bin_strings[i]; // if (position >= bstr.Length || position < 0) // left.Add(i); // else // { // char ch = bstr[position]; // if (ch == '1') // right.Add(i); // else // left.Add(i); // } // } // int total = left.Count + right.Count; // if (total == 1) // { // //This is a leaf, woo // int pos = -1, t; // if (left.Count > 0) // t = left[0]; // else // t = right[0]; // return new int[] { pos, t }; // } // else if (left.Count == 0 || right.Count == 0) // //This is not a branch, let's try the next bit // if (left.Count > 0) // return partition_tree(left, position + 1); // else // return partition_tree(right, position + 1); // else // { // int[] l = partition_tree(left, position + 1); // int[] r = partition_tree(right, position + 1); // return new int[] { position }.Append(l).Append(r); // } // } // public int tree_size(int[] node) // { // //Node is the return from partition_tree() // if (node[0] == -1) // return 1; // else // return 1 + tree_size(new int[] { node[1] }) + tree_size(new int[] { node[2] }); // } // public void dump_tree(int[] tree) // { // out_node_idx = 0; // _dump_node(tree); // } // public void _dump_node(int[] node) // { // //Node is the return from partition_tree() // int bit_id = node[0]; // if (bit_id == -1) // { // //We're packing a leaf // Console.WriteLine(String.Format("{0} leaf : {1}", out_node_idx, strings[node[1]])); // out_node_idx += 1; // } // else // { // //We're packing a branch // int left_size = tree_size(new int[] { node[1] }); // int left_idx = out_node_idx + 1; // int right_idx = left_idx + left_size; // Console.WriteLine(String.Format("{0} branch: bit={1} left={2} right={3}", out_node_idx, bit_id, left_idx, right_idx)); // out_node_idx += 1; // dump_tree(new int[] { node[1] }); // dump_tree(new int[] { node[2] }); // } // } //} //tree = PatriciaTree(('BANK_HOMEBUTTON','BANK_SYSTEM_SE','BANK_BGM','BANK_SOFTWARE_KEYBOARD_SE')) //print(tree.partition_tree()) //tree.dump_tree(tree.partition_tree()) private static int EncodeMaskGroup(SYMBHeader *symb, SYMBMaskHeader *header, List <RSAREntryState> group, RSARNode n, int grp) { SYMBMaskEntry *entry = header->Entries; //List<TEntry> outputTable = new List<TEntry>(); int i = 0; foreach (RSAREntryState s in group) { entry[i++] = new SYMBMaskEntry(1, -1, -1, -1, s._stringId, s._index); if (s._index != 0) { //entry[i++] = new SYMBMaskEntry(0, 0, 0, 0, -1, -1); entry[i] = n._symbCache[grp][i++]; } //outputTable.Add(new TEntry(s)); } header->_numEntries = group.Count * 2 - 1; header->_rootId = n._rootIds[grp]; //GenIds(symb, header, 0, 0); //CalcMatch(outputTable); //foreach (TEntry t in outputTable) //{ // *entry++ = new SYMBMaskEntry(1, -1, -1, -1, t._stringID, t._id); // if (t._id != 0) // *entry++ = new SYMBMaskEntry(0, (short)t._bit, t._leftID, t._rightID, -1, -1); //} //PatriciaTree t = new PatriciaTree(group.Select(x => x._node._fullPath).ToArray()); //int[] p = t.partition_tree(new List<int>(t.strings.Length), 0); //t.dump_tree(p); int len = 8 + i * SYMBMaskEntry.Size; //int rootId = 0; //int lowestBit = int.MaxValue; //entry = header->Entries; //for (int i = 2; i < header->_numEntries; i += 2) //{ // if (entry[i]._bit < lowestBit) // { // lowestBit = entry[i]._bit; // rootId = i; // } //} //header->_rootId = rootId; return(len); }
internal static int EncodeSYMBBlock(SYMBHeader *header, RSAREntryList entries) { int count = entries._count; VoidPtr baseAddr = (VoidPtr)header + 8, dataAddr; int len; bint * strEntry = (bint *)(baseAddr + 0x18); PString pStr = (byte *)strEntry + (count << 2); //Strings header->_stringOffset = 0x14; strEntry[-1] = entries._strings.Count; foreach (string s in entries._strings) { *strEntry++ = (int)(pStr - baseAddr); pStr.Write(s, 0, s.Length + 1); pStr += s.Length + 1; } dataAddr = pStr; //Sounds header->_maskOffset1 = (int)(dataAddr - baseAddr); dataAddr += EncodeMaskGroup((SYMBMaskHeader *)dataAddr, entries._sounds); //Types header->_maskOffset2 = (int)(dataAddr - baseAddr); dataAddr += EncodeMaskGroup((SYMBMaskHeader *)dataAddr, entries._types); //Groups header->_maskOffset3 = (int)(dataAddr - baseAddr); dataAddr += EncodeMaskGroup((SYMBMaskHeader *)dataAddr, entries._groups); //Banks header->_maskOffset4 = (int)(dataAddr - baseAddr); dataAddr += EncodeMaskGroup((SYMBMaskHeader *)dataAddr, entries._banks); len = ((int)baseAddr).Align(0x20); //Fill padding byte *p = (byte *)dataAddr; for (int i = dataAddr - header; i < len; i++) { *p++ = 0; } //Set header header->_tag = SYMBHeader.Tag; header->_length = len; return(len); }
protected internal override void OnRebuild(VoidPtr address, int length, bool force) { int symbLen, infoLen, fileLen; RSARHeader *rsar = (RSARHeader *)address; SYMBHeader *symb = (SYMBHeader *)(address + 0x40); INFOHeader *info; FILEHeader *data; info = (INFOHeader *)((int)symb + (symbLen = RSARConverter.EncodeSYMBBlock(symb, _entryList))); data = (FILEHeader *)((int)info + (infoLen = RSARConverter.EncodeINFOBlock(info, _entryList))); fileLen = RSARConverter.EncodeFILEBlock(data, _entryList); rsar->Set(symbLen, infoLen, fileLen); _entryList.Clear(); }
public override void OnRebuild(VoidPtr address, int length, bool force) { int symbLen, infoLen, fileLen; RSARHeader *rsar = (RSARHeader *)address; SYMBHeader *symb = (SYMBHeader *)(address + 0x40); INFOHeader *info; FILEHeader *data; info = (INFOHeader *)(checked ((uint)symb + (symbLen = _converter.EncodeSYMBBlock(symb, _entryList, this)))); data = (FILEHeader *)(checked ((uint)info + (infoLen = _converter.EncodeINFOBlock(info, _entryList, this)))); fileLen = _converter.EncodeFILEBlock(data, address, _entryList, this); rsar->Set(symbLen, infoLen, fileLen, VersionMinor); _entryList.Clear(); }
public override void OnPopulate() { //Enumerate entries, attaching them to the files. RSARHeader *rsar = Header; SYMBHeader *symb = rsar->SYMBBlock; sbyte * offset = (sbyte *)symb + 8; buint * stringOffsets = symb->StringOffsets; VoidPtr baseAddr = (VoidPtr)rsar->INFOBlock + 8; ruint * typeList = (ruint *)baseAddr; //Iterate through group types for (int i = 0; i < 5; i++) { _infoCache[i] = new List <RSAREntryNode>(); Type t = null; RuintList *list = (RuintList *)((uint)baseAddr + typeList[i]); sbyte * str, end; switch (i) { case 0: t = typeof(RSARSoundNode); break; case 1: t = typeof(RSARBankNode); break; case 2: t = typeof(RSARPlayerInfoNode); break; case 3: continue; //Files case 4: t = typeof(RSARGroupNode); break; //Last group entry is null } for (int x = 0; x < list->_numEntries; x++) { VoidPtr addr = list->Get(baseAddr, x); ResourceNode parent = this; RSAREntryNode n = Activator.CreateInstance(t) as RSAREntryNode; n._origSource = n._uncompSource = new DataSource(addr, 0); n._infoIndex = x; if (i == 4 && x == list->_numEntries - 1) { n._name = "<null>"; n._parent = this; _nullGroup = n as RSARGroupNode; } else { str = offset + stringOffsets[n.StringId]; for (end = str; *end != 0; end++) { ; } while ((--end > str) && (*end != '_')) { ; } if (end > str) { parent = CreatePath(parent, str, (int)end - (int)str); n._name = new String(end + 1); } else { n._name = new String(str); } } n.Initialize(parent, addr, 0); _infoCache[i].Add(n); } } ftr = *(INFOFooter *)((uint)baseAddr + typeList[5]); foreach (RSARFileNode n in Files) { if (!(n is RSARExtFileNode)) { n.GetName(); } } _rootIds = new int[4]; _symbCache = new List <SYMBMaskEntry> [4]; bint *offsets = (bint *)((VoidPtr)symb + 12); for (int i = 0; i < 4; i++) { _symbCache[i] = new List <SYMBMaskEntry>(); SYMBMaskHeader *hdr = (SYMBMaskHeader *)((VoidPtr)symb + 8 + offsets[i]); //Console.WriteLine("Root Index = " + hdr->_rootId); _rootIds[i] = hdr->_rootId; for (int x = 0; x < hdr->_numEntries; x++) { SYMBMaskEntry *e = &hdr->Entries[x]; _symbCache[i].Add(*e); //Console.WriteLine(String.Format("[{5}] {0}, {1}, {2} - {4}", e->_bit != -1 ? e->_bit.ToString().PadLeft(3) : " ", e->_leftId != -1 ? e->_leftId.ToString().PadLeft(3) : " ", e->_rightId != -1 ? e->_rightId.ToString().PadLeft(3) : " ", e->_index != -1 ? e->_index.ToString().PadLeft(3) : " ", new string(offset + stringOffsets[e->_stringId]), x.ToString().PadLeft(3))); } } //Sort(true); }
private static void AddToTrie(SYMBMaskEntry *trie, SYMBMaskHeader *head, int id, SYMBHeader *table) { //If list is empty add the node and quit if (head->_numEntries == 0) { trie[head->_numEntries++] = new SYMBMaskEntry(1, -1, -1, -1, id, 0); return; } string value = table->GetStringEntry(id); //String.IsNullOrEmpty(value) if ((value ?? "") == "") { throw new ArgumentException("String is null or whitespace"); } SYMBMaskEntry search = trie[head->_rootId]; List <int> path = new List <int> { head->_rootId }; //Find the string that matches the current string in the trie. Needs to be done in order to determine where the important bit is in the string while (search._flags == 0) { //Assume that strings are treated as having an infinite number of null chars following them if (search._bit / 8 >= value.Length) { path.Add(search._leftId); search = trie[search._leftId]; continue; } // _leftId corresponds to bit=0, _rightId corresponds to bit=1 if (CheckBit(value, search._bit)) { path.Add(search._rightId); search = trie[search._rightId]; } else { path.Add(search._leftId); search = trie[search._leftId]; } } string searchVal = table->GetStringEntry(search._stringId); //Can't add duplicate strings if (searchVal == value) { throw new ArgumentException("Duplicate string"); } bool mismatch = false; int minLength = Math.Min(searchVal.Length, value.Length); short bit = 0; //Locate mismatching character between the two strings for (short i = 0; i < minLength; i++) { if (value[i] != searchVal[i]) { mismatch = true; bit = (short)(8 * i); break; } } bool right; //If a char was different one string does not contain the other if (mismatch) { //Find where the bits differed int cmpint = value[bit / 8] ^ searchVal[bit / 8]; bit += clz8[cmpint]; //If the bit is 1 the string being added takes the left fork right = CheckBit(value, bit); if (head->_numEntries == 1) { trie[1] = new SYMBMaskEntry(1, -1, -1, -1, id, 1); trie[2] = new SYMBMaskEntry(0, bit, right ? 0 : 1, right ? 1 : 0, -1, -1); head->_numEntries = 3; head->_rootId = 2; return; } //If the mismatch bit is lower than the first mismatch bit the new branch will be the root of the tree if (bit < trie[path[0]]._bit) { trie[head->_numEntries++] = new SYMBMaskEntry(1, -1, -1, -1, id, head->_numEntries / 2); if (right) { trie[head->_numEntries++] = new SYMBMaskEntry(0, bit, path[0], head->_numEntries - 2, -1, -1); } else { trie[head->_numEntries++] = new SYMBMaskEntry(0, bit, head->_numEntries - 2, path[0], -1, -1); } head->_rootId = head->_numEntries - 1; return; } //Locate where the branch needs to be inserted for (int i = 1; i < path.Count; i++) { if (trie[path[i]]._bit > bit || trie[path[i]]._flags == 1) { //Add leaf trie[head->_numEntries++] = new SYMBMaskEntry(1, -1, -1, -1, id, head->_numEntries / 2); //Remap previous branch to point to new branch if (trie[path[i - 1]]._leftId == path[i]) { trie[path[i - 1]]._leftId = head->_numEntries; } else { trie[path[i - 1]]._rightId = head->_numEntries; } //Create new branch if (right) { trie[head->_numEntries++] = new SYMBMaskEntry(0, bit, path[i], head->_numEntries - 2, -1, -1); } else { trie[head->_numEntries++] = new SYMBMaskEntry(0, bit, head->_numEntries - 2, path[i], -1, -1); } return; } } //This should never happen throw new Exception("Error building tree, unexpected structure"); } //Since mismatch is false, one string is a substring of the other //The longer string is the one that takes the left branch right = value.Length > searchVal.Length; bit = (short)(minLength * 8); if (right) { //Find the first bit after the substring that's 1. Will always occur in the first 8 bits because 0x00 denotes string termination and thus isn't in value bit += clz8[value[bit / 8]]; //If path.Count == 1 the only value is a leaf if (path.Count == 1) { trie[1] = new SYMBMaskEntry(1, -1, -1, -1, id, 1); trie[2] = new SYMBMaskEntry(0, bit, 0, 1, -1, -1); head->_numEntries = 3; head->_rootId = 2; return; } //Update old branch, insert new branch and node, and quit. trie[path[path.Count-2]] is the last branch that was a comparison. trie[head->_numEntries++] = new SYMBMaskEntry(1, -1, -1, -1, id, head->_numEntries / 2); int trace = path.Count - 2; if (trie[path[trace]]._leftId == path[trace + 1]) { //Handling an extremely specific and annoying edge case while (trie[path[trace]]._bit > bit) { trace--; if (trace < 0) { //This node is actually the root of the tree trie[head->_numEntries++] = new SYMBMaskEntry(0, bit, path[0], head->_numEntries - 2, -1, -1); head->_rootId = head->_numEntries - 2; return; } } trie[path[trace]]._leftId = head->_numEntries; } else { trie[path[trace]]._rightId = head->_numEntries; } trie[head->_numEntries++] = new SYMBMaskEntry(0, bit, path[trace + 1], head->_numEntries - 2, -1, -1); return; } //Find first bit comparison that happens after the substring ends int index; for (index = 0; trie[path[index]]._flags == 0 && trie[path[index]]._bit <= bit; index++) { } //Find the first bit that's 1 and isn't already used in the trie int cmpVal = searchVal[bit / 8]; byte clzVal; bool test = trie[path[index]]._flags == 0; while (true) { clzVal = clz8[cmpVal]; if (clzVal == 8) { bit += 8; cmpVal = searchVal[bit / 8]; continue; } if (test && trie[path[index]]._bit <= bit + clzVal) { if (trie[path[index]]._bit == bit + clzVal) { cmpVal ^= (1 << 7) >> clzVal; } test = trie[path[++index]]._flags == 0; continue; } bit += clzVal; break; } //If the trie is a single leaf the new branch is the root of the trie if (head->_numEntries == 1) { trie[1] = new SYMBMaskEntry(1, -1, -1, -1, id, 1); trie[2] = new SYMBMaskEntry(0, bit, 1, 0, -1, -1); head->_numEntries = 3; head->_rootId = 2; return; } //Update old branch, insert new branch and node, and quit trie[head->_numEntries++] = new SYMBMaskEntry(1, -1, -1, -1, id, head->_numEntries / 2); if (trie[path[index - 1]]._leftId == path[index]) { trie[path[index - 1]]._leftId = head->_numEntries; } else { trie[path[index - 1]]._rightId = head->_numEntries; } trie[head->_numEntries++] = new SYMBMaskEntry(0, bit, head->_numEntries - 2, path[index], -1, -1); return; }
protected override void OnPopulate() { RSARFolderNode g = new RSARFolderNode(); g.Name = "Info"; g.Parent = this; g = new RSARFolderNode(); g.Name = "Files"; g.Parent = this; //Retrieve all files to attach to entries GetFiles(); //Enumerate entries, attaching them to the files. RSARHeader *rsar = Header; SYMBHeader *symb = rsar->SYMBBlock; sbyte * offset = (sbyte *)symb + 8; buint * stringOffsets = symb->StringOffsets; VoidPtr types = (VoidPtr)rsar->INFOBlock + 8; ruint * typeList = (ruint *)types; //Iterate through group types for (int i = 0; i < 5; i++) { Type t = null; ruint *entryList = (ruint *)((uint)types + typeList[i] + 4); int entryCount = *((bint *)entryList - 1); sbyte *str, end; switch (i) { case 0: t = typeof(RSARSoundNode); break; case 1: t = typeof(RSARBankNode); break; case 2: t = typeof(RSARTypeNode); break; case 3: continue; case 4: t = typeof(RSARGroupNode); break; } for (int x = 0; x < entryCount; x++) { ResourceNode parent = Children[0]; RSAREntryNode n = Activator.CreateInstance(t) as RSAREntryNode; n._origSource = n._uncompSource = new DataSource(types + entryList[x], 0); str = offset + stringOffsets[n.StringId]; for (end = str; *end != 0; end++) { ; } while ((--end > str) && (*end != '_')) { ; } if (end > str) { parent = CreatePath(parent, str, (int)end - (int)str); n._name = new String(end + 1); } else { n._name = new String(str); } n.Initialize(parent, types + entryList[x], 0); //n.Populate(); } } //Sort(true); }
protected override void OnPopulate() { //RSARNode rsar = RSARNode; //SYMBHeader* symb = null; //RuintList* soundList = null; //INFOSoundEntry** soundIndices = null; //VoidPtr soundOffset = null; //INFOSoundEntry* sEntry; //RWSDHeader* rwsd = Header; //RWSD_DATAHeader* data = rwsd->Data; ////RWSD_WAVEHeader* wave = rwsd->Wave; //RuintList* list = &data->_list; ////RuintList* waveList = &wave->_list; //int count = list->_numEntries; ////Get sound info from RSAR (mainly for names) //if (rsar != null) //{ // symb = rsar.Header->SYMBBlock; // soundOffset = &rsar.Header->INFOBlock->_collection; // soundList = rsar.Header->INFOBlock->Sounds; // soundIndices = (INFOSoundEntry**)Marshal.AllocHGlobal(count * 4); // //int sIndex = 0; // int soundCount = soundList->_numEntries; // for (int i = 0; i < soundCount; i++) // if ((sEntry = (INFOSoundEntry*)soundList->Get(soundOffset, i))->_fileId == _fileIndex) // soundIndices[((INFOSoundPart2*)sEntry->GetPart2(soundOffset))->_soundIndex] = sEntry; //} //for (int i = 0; i < count; i++) //{ // RWSD_DATAEntry* entry = (RWSD_DATAEntry*)list->Get(list, i); // RWSDDataNode node = new RWSDDataNode(); // node.Initialize(this, entry, 0); // //Attach from INFO block // if (soundIndices != null) // { // sEntry = soundIndices[i]; // node._name = symb->GetStringEntry(sEntry->_stringId); // } //} //if (soundIndices != null) // Marshal.FreeHGlobal((IntPtr)soundIndices); //Get labels RSARNode parent; int count = Header->Data->_list._numEntries; if ((_labels == null) && ((parent = RSARNode) != null)) { _labels = new LabelItem[count];// new string[count]; //Get them from RSAR SYMBHeader *symb = parent.Header->SYMBBlock; INFOHeader *info = parent.Header->INFOBlock; VoidPtr offset = &info->_collection; RuintList *soundList = info->Sounds; count = soundList->_numEntries; INFOSoundEntry *entry; for (int i = 0; i < count; i++) { if ((entry = (INFOSoundEntry *)soundList->Get(offset, i))->_fileId == _fileIndex) { _labels[((INFOSoundPart2 *)entry->GetPart2(offset))->_soundIndex] = new LabelItem() { Tag = i, String = symb->GetStringEntry(entry->_stringId) } } } ; } new RWSDGroupNode().Initialize(this, Header->Data, Header->_dataLength); new RWSDGroupNode().Initialize(this, Header->Wave, Header->_waveLength); }
//public RSARGroupNode _nullGroup; public override void OnPopulate() { //Enumerate entries, attaching them to the files. RSARHeader *rsar = Header; SYMBHeader *symb = rsar->SYMBBlock; sbyte * offset = (sbyte *)symb + 8; buint * stringOffsets = symb->StringOffsets; VoidPtr baseAddr = (VoidPtr)rsar->INFOBlock + 8; ruint * typeList = (ruint *)baseAddr; //Iterate through group types for (int i = 0; i < 5; i++) { Type t = null; switch (i) { case 0: t = typeof(RSARSoundNode); break; case 1: t = typeof(RSARBankNode); break; case 2: t = typeof(RSARPlayerInfoNode); break; case 3: continue; //Files case 4: t = typeof(RSARGroupNode); break; //Last group entry has no name } _infoCache[i] = new List <RSAREntryNode>(); RuintList *list = (RuintList *)((uint)baseAddr + typeList[i]); sbyte * str, end; for (int x = 0; x < list->_numEntries; x++) { VoidPtr addr = list->Get(baseAddr, x); ResourceNode parent = this; RSAREntryNode n = Activator.CreateInstance(t) as RSAREntryNode; n._origSource = n._uncompSource = new DataSource(addr, 0); if (n.StringId >= 0) { str = offset + stringOffsets[n.StringId]; for (end = str; *end != 0; end++) { ; } while ((--end > str) && (*end != '_')) { ; } if (end > str) { parent = CreatePath(parent, str, (int)end - (int)str); n._name = new String(end + 1); } else { n._name = new String(str); } } else { n._name = null; } n._infoIndex = x; n.Initialize(parent, addr, 0); _infoCache[i].Add(n); } _ftr = *(INFOFooter *)((uint)baseAddr + typeList[5]); foreach (RSARFileNode n in Files) { if (!(n is RSARExtFileNode)) { n.GetName(); } } } }
public override void OnPopulate() { RWSDHeader * rwsd = Header; RWSD_DATAHeader *data = rwsd->Data; RuintList * list = &data->_list; int count = list->_numEntries; new RWSDDataGroupNode().Initialize(this, Header->Data, Header->_dataLength); if (Header->_waveOffset > 0 && VersionMinor < 3) { new RWSDSoundGroupNode().Initialize(this, Header->Wave, Header->_waveLength); } else if (VersionMinor >= 3) { new RWARNode { _name = "Audio" }.Initialize(this, _audioSource.Address, _audioSource.Length); } //Get labels RSARNode parent; if (_labels == null && (parent = RSARNode) != null) { //Get them from RSAR SYMBHeader *symb2 = parent.Header->SYMBBlock; INFOHeader *info = parent.Header->INFOBlock; VoidPtr offset = &info->_collection; RuintList *soundList = info->Sounds; int count2 = soundList->_numEntries; _labels = new LabelItem[count2]; INFOSoundEntry *entry; for (uint i = 0; i < count2; i++) { if ((entry = (INFOSoundEntry *)soundList->Get(offset, (int)i))->_fileId == _fileIndex) { int x = ((WaveSoundInfo *)entry->GetSoundInfoRef(offset))->_soundIndex; if (x >= 0 && x < count2) { _labels[x] = new LabelItem { Tag = i, String = symb2->GetStringEntry(entry->_stringId) }; } } } } for (int i = 0; i < count; i++) { string name = "Entry" + i; if (_labels != null && i < _labels.Length) { name = _labels[i].String; } RWSD_DATAEntry *entry = (RWSD_DATAEntry *)list->Get(list, i); RWSDDataNode node = new RWSDDataNode { _name = name }; node._offset = list; node.Initialize(Children[0], entry, 0); } }
protected override void OnPopulate() { //Get files GetFiles(); //Enumerate entries, attaching them to the files. RSARHeader *rsar = Header; SYMBHeader *symb = rsar->SYMBBlock; sbyte * offset = (sbyte *)symb + 8; buint * stringOffsets = symb->StringOffsets; VoidPtr gOffset = (VoidPtr)rsar->INFOBlock + 8; ruint * groups = (ruint *)gOffset; for (int i = 0; i < 5; i++) { Type t = null; ruint *list = (ruint *)((uint)groups + groups[i] + 4); int count = *((bint *)list - 1); sbyte *str, end; switch (i) { case 0: t = typeof(RSARSoundNode); break; case 1: t = typeof(RSARBankNode); break; case 2: t = typeof(RSARTypeNode); break; case 3: { //Get files //INFOFileHeader* fileHeader; //INFOFileEntry* fileEntry; //RuintList* entryList; //INFOGroupHeader* group; //INFOGroupEntry* gEntry; //RuintList* groupList = rsar->INFOBlock->Groups; //RSARFileNode n; //DataSource source; //for (int x = 0; x < count; x++) //{ // fileHeader = (INFOFileHeader*)(gOffset + list[x]); // entryList = fileHeader->GetList(gOffset); // if (entryList->_numEntries == 0) // { // //Must be external file. // n = new RSARExtFileNode(); // source = new DataSource(fileHeader, 0); // } // else // { // //use first entry // fileEntry = (INFOFileEntry*)entryList->Get(gOffset, 0); // //Find group with matching ID // group = (INFOGroupHeader*)groupList->Get(gOffset, fileEntry->_groupId); // //Find group entry with matching index // gEntry = (INFOGroupEntry*)group->GetCollection(gOffset)->Get(gOffset, fileEntry->_index); // //Create node and parse // source = new DataSource((int)rsar + group->_headerOffset + gEntry->_headerOffset, gEntry->_headerLength); // if ((n = NodeFactory.GetRaw(source) as RSARFileNode) == null) // n = new RSARFileNode(); // n._audioSource = new DataSource((int)rsar + group->_dataOffset + gEntry->_dataOffset, gEntry->_dataLength); // } // n._fileIndex = x; // n._parent = this; //This is so that the node won't add itself to the child list. // n.Initialize(this, source); // _files.Add(n); //} continue; } case 4: t = typeof(RSARGroupNode); break; } for (int x = 0; x < count; x++) { ResourceNode parent = this; RSAREntryNode n = Activator.CreateInstance(t) as RSAREntryNode; n._origSource = n._uncompSource = new DataSource(gOffset + list[x], 0); str = offset + stringOffsets[n.StringId]; for (end = str; *end != 0; end++) { ; } while ((--end > str) && (*end != '_')) { ; } if (end > str) { parent = CreatePath(parent, str, (int)end - (int)str); n._name = new String(end + 1); } else { n._name = new String(str); } n.Initialize(parent, gOffset + list[x], 0); } } Sort(true); }