Example #1
0
        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);
        }
Example #2
0
 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);
 }
Example #3
0
        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);
        }
Example #4
0
        //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);
            }
        }
Example #5
0
        //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);
        }
Example #6
0
        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);
        }
Example #7
0
        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();
        }
Example #8
0
        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();
        }
Example #9
0
        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);
        }
Example #10
0
        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;
        }
Example #11
0
        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);
        }
Example #12
0
        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);
        }
Example #13
0
        //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();
                    }
                }
            }
        }
Example #14
0
        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);
            }
        }
Example #15
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);
        }