Exemplo n.º 1
0
 public VMSChallengeResult(byte[] htmlpage)
 {
     byte[] decr = VMSFile.GetDataFromHTML(htmlpage);
     DataType   = (DataIDs)BitConverter.ToUInt32(decr, 0x04);
     UserData   = new PDATA(decr, 0x08);
     ResultData = new EventResultDataChild(decr, 0x44);
 }
Exemplo n.º 2
0
 public static byte[] GetDataFromHTML(byte[] file)
 {
     for (int u = 0; u < file.Length - 15; u++)
     {
         if (System.Text.Encoding.GetEncoding(932).GetString(file, u, 15) == "NAME=\"chaodata\"")
         {
             // Load Base64
             StringBuilder b64str = new StringBuilder();
             for (int k = u + 23; k < file.Length - 2; k++)
             {
                 if (file[k] == 0x22 && file[k + 1] == 0x3E)
                 {
                     break;
                 }
                 else
                 {
                     b64str.Append((Convert.ToChar(file[k])).ToString());
                 }
             }
             // Decode Base64, decrypt
             byte[] data = Convert.FromBase64String(b64str.ToString());
             VMSFile.DecryptData(ref data);
             return(data);
         }
     }
     return(null);
 }
Exemplo n.º 3
0
        private void SaveDecodedData(string source)
        {
            byte[] decr     = VMSFile.GetDataFromHTML(File.ReadAllBytes(source));
            string filename = Path.Combine(Path.GetDirectoryName(source), Path.GetFileNameWithoutExtension(source + "_data.bin"));

            File.WriteAllBytes(filename, decr);
            System.Windows.Forms.MessageBox.Show("Decrypted data saved as " + filename + ".");
        }
Exemplo n.º 4
0
        static void GetPdata(string filepath)
        {
            byte[] file = File.ReadAllBytes(filepath);
            byte[] data = VMSFile.GetDataFromHTML(file);
            PDATA  pd   = new PDATA(data, 8);

            File.WriteAllBytes(Path.ChangeExtension(filepath, ".pd"), pd.GetBytes());
            Application.Exit();
        }
Exemplo n.º 5
0
        public VMIFile(VMSFile data, string ResName)
        {
            if (ResName.Length > 8)
            {
                System.Windows.Forms.MessageBox.Show("For the VMI file to work correctly, VMS filename should be 8 characters or less.", "DLC Tool Warning", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
            }
            Description = data.Description;
            Copyright   = data.AppName;
            Year        = (ushort)DateTime.Now.Year;
            Month       = (byte)DateTime.Now.Month;
            Day         = (byte)DateTime.Now.Day;
            Hour        = (byte)DateTime.Now.Hour;
            Minute      = (byte)DateTime.Now.Minute;
            Second      = (byte)DateTime.Now.Second;
            switch (DateTime.Now.DayOfWeek)
            {
            case DayOfWeek.Sunday:
                Weekday = 0;
                break;

            case DayOfWeek.Monday:
                Weekday = 1;
                break;

            case DayOfWeek.Tuesday:
                Weekday = 2;
                break;

            case DayOfWeek.Wednesday:
                Weekday = 3;
                break;

            case DayOfWeek.Thursday:
                Weekday = 4;
                break;

            case DayOfWeek.Friday:
                Weekday = 5;
                break;

            case DayOfWeek.Saturday:
                Weekday = 6;
                break;
            }
            FileID       = 1;
            ResourceName = ResName;
            if (data is VMS_DLC dlc)
            {
                FileName = "SONICADV_" + dlc.Identifier.ToString("D3");
                Size     = (uint)dlc.GetBytes().Length;
            }
            else
            {
                FileName = "VMSDATA";
                Size     = data.GetLength();
            }
        }
Exemplo n.º 6
0
        public static void ProcessVMS(ref byte[] input)
        {
            int aniFrames = input[0x40] + (input[0x41] << 8);
            int dataStart = 0x80 + (aniFrames * 0x200);

            byte[] encrypted = new byte[input.Length - dataStart];
            Array.Copy(input, dataStart, encrypted, 0, encrypted.Length);
            VMSFile.DecryptData(ref encrypted);
            Array.Copy(encrypted, 0, input, dataStart, encrypted.Length);
        }
Exemplo n.º 7
0
 public void LoadWorldRankFile(string filename)
 {
     byte[] file = File.ReadAllBytes(filename);
     // Get region
     radioButtonJapan.Checked         = BitConverter.ToUInt32(file, 0) == 0xC0B0DEC3;
     radioButtonInternational.Checked = Encoding.GetEncoding(932).GetString(file, 0, 11) == "DATA_UPLOAD";
     // Decrypt data
     DecryptedData = VMSFile.GetDataFromHTML(file);
     // Set fields
     labelPlayTime.Text              = "Total Time: " + FramesToTimeString(BitConverter.ToInt32(DecryptedData, 0x48));
     textBoxIndividualID.Text        = VMSFile.GetFieldFromHTML(file, "dcid");
     textBoxSubmitted.Text           = VMSFile.GetFieldFromHTML(file, "mailid");
     saveAsToolStripMenuItem.Enabled = true;
 }
Exemplo n.º 8
0
 private void decodeUploadDataToolStripMenuItem_Click(object sender, EventArgs e)
 {
     using (OpenFileDialog od = new OpenFileDialog()
     {
         DefaultExt = "vms", Filter = "VMS Files|*.vms|All Files|*.*"
     })
         if (od.ShowDialog(this) == DialogResult.OK)
         {
             byte[] data    = File.ReadAllBytes(od.FileName);
             byte[] result  = VMSFile.GetDataFromHTML(data);
             string outpath = Path.Combine(Path.GetDirectoryName(od.FileName), Path.GetFileNameWithoutExtension(od.FileName)) + "_dec.bin";
             File.WriteAllBytes(outpath, result);
             MessageBox.Show(this, "Binary file saved as:\n" + outpath, "VMS Editor", MessageBoxButtons.OK, MessageBoxIcon.Information);
         }
 }
Exemplo n.º 9
0
        public byte[] GetBytes()
        {
            List <byte> result = new List <byte>();

            result.AddRange(BitConverter.GetBytes((uint)0));             // Checksum
            result.AddRange(BitConverter.GetBytes((uint)DataType));      // Hardcoded data ID
            result.AddRange(UserData.GetBytes());
            result.AddRange(ResultData.GetBytes());
            byte[] end      = result.ToArray();
            int    checksum = VMSFile.CalculateUploadCRC(ref end);

            result.RemoveRange(0, 4);
            result.InsertRange(0, BitConverter.GetBytes(checksum));
            return(result.ToArray());
        }
Exemplo n.º 10
0
        private void LoadEventResult(string filename)
        {
            byte[]             file   = File.ReadAllBytes(filename);
            VMSChallengeResult result = new VMSChallengeResult(file);

            numericUpDownEventID.Value      = result.ResultData.EventID;
            numericUpDownFrames.Value       = result.ResultData.EventTime;
            comboBoxCharacter.SelectedIndex = (int)result.ResultData.Character;
            labelTime.Text                   = "Total Time: " + FramesToTimeString((int)result.ResultData.EventTime);
            radioButtonCart.Checked          = result.DataType == DataIDs.CartResultChecksum;
            radioButtonEvent.Checked         = result.DataType == DataIDs.EventResultChecksum;
            textBoxIndividualID.Text         = VMSFile.GetFieldFromHTML(file, "dcid");
            textBoxSubmitted.Text            = VMSFile.GetFieldFromHTML(file, "mailid");
            radioButtonJapan.Checked         = (BitConverter.ToUInt32(file, 0) == 0xDDDECDB2) || (BitConverter.ToUInt32(file, 0) == 0xC0C4B0B6);
            radioButtonInternational.Checked = System.Text.Encoding.GetEncoding(932).GetString(file, 0, 12) == "EVENT_RESULT" || System.Text.Encoding.GetEncoding(932).GetString(file, 0, 9) == "CART_TIME";
        }
Exemplo n.º 11
0
 private void vMSFileToolStripMenuItem_Click(object sender, EventArgs e)
 {
     using (OpenFileDialog od = new OpenFileDialog()
     {
         DefaultExt = "vms", Filter = "VMS Files|*.vms|All Files|*.*"
     })
         if (od.ShowDialog(this) == DialogResult.OK)
         {
             byte[] data      = File.ReadAllBytes(od.FileName);
             int    aniFrames = data[0x40] + (data[0x41] << 8);
             int    dataStart = 0x80 + (aniFrames * 0x200);
             byte[] encrypted = new byte[data.Length - dataStart];
             Array.Copy(data, dataStart, encrypted, 0, encrypted.Length);
             VMSFile.DecryptData(ref encrypted);
             Array.Copy(encrypted, 0, data, dataStart, encrypted.Length);
             string outpath = Path.Combine(Path.GetDirectoryName(od.FileName), Path.GetFileNameWithoutExtension(od.FileName)) + "_dec.vms";
             File.WriteAllBytes(outpath, data);
             MessageBox.Show(this, "VMS file saved as:\n" + outpath, "VMS Editor", MessageBoxButtons.OK, MessageBoxIcon.Information);
         }
 }
Exemplo n.º 12
0
        public void LoadVMS_DLC(string filename)
        {
            byte[] file = File.ReadAllBytes(filename);
            // Get metadata and icon
            meta       = new VMS_DLC(file);
            metaBackup = new VMS_DLC(meta);
            meta.Icon  = GetIconFromFile(file);
            // Get PVM pointer
            uint pvm_pointer = BitConverter.ToUInt32(file, 0x290);
            int  pvm_value   = BitConverter.ToInt32(file, 0x294);
            int  pvm_count   = BitConverter.ToInt32(file, 0x298);

            if (pvm_value != 0)
            {
                Console.WriteLine("PVM at {0}, number of textures {1}", pvm_pointer.ToString("X"), pvm_count);
            }
            checkBoxEnableTextures.Checked = pvm_value != 0;
            // Get MLT pointer
            uint mlt_pointer = BitConverter.ToUInt32(file, 0x29C);
            int  mlt_value   = BitConverter.ToInt32(file, 0x2A0);

            if (mlt_value != 0)
            {
                Console.WriteLine("MLT at {0}", mlt_pointer.ToString("X"));
            }
            // Get PRS pointer
            uint prs_pointer = BitConverter.ToUInt32(file, 0x2A4);
            int  prs_value   = BitConverter.ToInt32(file, 0x2A8);

            if (prs_value != 0)
            {
                Console.WriteLine("PRS at {0}", prs_pointer.ToString("X"));
            }
            // Checksum
            uint crc = VMSFile.CalculateChecksum(ref file, 0x2C0, file.Length);

            Console.WriteLine("Checksum file / calculated: {0} ({1}) / {2} ({3})", BitConverter.ToInt32(file, 0x2AC).ToString("X"), BitConverter.ToInt32(file, 0x2AC), crc.ToString("X"), (int)crc);
            // Retrieve sections
            // Get PVM
            int pvm_size = (int)mlt_pointer - (int)pvm_pointer;

            if (pvm_size > 0 && pvm_size + pvm_pointer <= file.Length)
            {
                meta.TextureData = new byte[pvm_size];
                Array.Copy(file, pvm_pointer, meta.TextureData, 0, pvm_size);
                UpdateTextures();
            }
            // Get MLT
            int mlt_size = (int)prs_pointer - (int)mlt_pointer;

            if (mlt_size > 0 && mlt_pointer + mlt_size <= file.Length)
            {
                buttonLoadMLT.Enabled = buttonSaveMLT.Enabled = checkBoxEnableSound.Checked = true;
                meta.SoundData        = new byte[mlt_size];
                Array.Copy(file, mlt_pointer, meta.SoundData, 0, mlt_size);
                //File.WriteAllBytes(Path.Combine(dir, fname + ".mlt"), mltdata);
                labelSoundSectionSize.Text = "Section size: " + meta.SoundData.Length.ToString() + " bytes";
            }
            uint sectionsize = BitConverter.ToUInt32(file, 0x48);
            int  text_count  = BitConverter.ToInt32(file, 0x28C);
            int  item_count  = BitConverter.ToInt32(file, 0x284);
            int  item_size   = (item_count * 30 + 12); // 12-byte header

            do
            {
                item_size++;
            }while (item_size % 16 != 0);
            int prs_size = 0;

            if (prs_value != 0)
            {
                prs_size = file.Length - (int)prs_pointer;
            }
            Console.WriteLine("Headerless size {0}, item size {1}, text size {2}, PVM size {3}, MLT size {4}, PRS size {5}", sectionsize, item_size, text_count * 64, pvm_size, mlt_size, prs_size);
            // Get Model
            if (prs_size > 0 && prs_pointer + prs_size <= file.Length)
            {
                byte[] prsdata = new byte[prs_size];
                //Console.WriteLine("Copy from array of size {0} from {1} to array size {2}", file.Length, prs_pointer, prsdata.Length);
                Array.Copy(file, prs_pointer, prsdata, 0, prs_size);
                prsdata = FraGag.Compression.Prs.Decompress(prsdata);
                // Model pointer
                uint modelpointer = BitConverter.ToUInt32(prsdata, 0) - 0xCCA4000;
                //Console.WriteLine("Model pointer: {0}", modelpointer.ToString("X"));
                labelModelSectionSize.Text = "Section size: " + prsdata.Length.ToString() + " bytes";
                try
                {
                    NJS_OBJECT mdl = new NJS_OBJECT(prsdata, (int)modelpointer, 0xCCA4000, ModelFormat.Basic, null);
                    labelModelInfo.Text = GetModelInfo(mdl);
                }
                catch (Exception)
                {
                    labelModelInfo.Text = "Error getting model information.";
                }
                checkBoxEnableModel.Checked = true;
            }
            UpdateGeneralInfo();
            currentFilename = toolStripStatusFile.Text = Path.GetFileName(filename);
            currentFullPath = filename;
            saveToolStripMenuItem.Enabled = true;
            // Add data for empty strings
            for (int i = 0; i < 16; i++)
            {
                if (meta.JapaneseStrings[i] == null)
                {
                    meta.JapaneseStrings[i] = "";
                }
                if (meta.EnglishStrings[i] == null)
                {
                    meta.EnglishStrings[i] = "";
                }
                if (meta.FrenchStrings[i] == null)
                {
                    meta.FrenchStrings[i] = "";
                }
                if (meta.GermanStrings[i] == null)
                {
                    meta.GermanStrings[i] = "";
                }
                if (meta.SpanishStrings[i] == null)
                {
                    meta.SpanishStrings[i] = "";
                }
            }
            UpdateMessage();
            UpdateSize();
        }
Exemplo n.º 13
0
            /// <summary>
            /// Save to a byte array (VMS file)
            /// </summary>
            public byte[] GetBytes()
            {
                List <byte> result = new List <byte>();
                // Convert item table header
                List <byte> itemtable = new List <byte>();

                itemtable.AddRange(BitConverter.GetBytes(Identifier));
                byte chars_sonictails = 0;
                byte chars_knuxe102   = 0;
                byte chars_amybig     = 0;
                byte chars_whatev     = 0;

                if (EnableSonic)
                {
                    chars_sonictails |= 0x1;
                }
                if (EnableTails)
                {
                    chars_sonictails |= 0x10;
                }
                itemtable.Add(chars_sonictails);
                if (EnableKnuckles)
                {
                    chars_knuxe102 |= 0x1;
                }
                if (EnableGamma)
                {
                    chars_knuxe102 |= 0x10;
                }
                itemtable.Add(chars_knuxe102);
                if (EnableAmy)
                {
                    chars_amybig |= 0x1;
                }
                if (EnableBig)
                {
                    chars_amybig |= 0x10;
                }
                itemtable.Add(chars_amybig);
                if (EnableWhatever1)
                {
                    chars_whatev |= 0x1;
                }
                if (EnableWhatever2)
                {
                    chars_whatev |= 0x10;
                }
                itemtable.Add(chars_whatev);
                itemtable.AddRange(BitConverter.GetBytes((int)Region));
                // Convert item table
                if (Items != null && Items.Count > 0)
                {
                    foreach (DLCObjectData item in Items)
                    {
                        itemtable.Add(item.Level);
                        itemtable.Add(item.Act);
                        itemtable.Add(item.ScaleX);
                        itemtable.Add(item.ScaleY);
                        itemtable.Add(item.ScaleZ);
                        itemtable.Add((byte)item.RotSpeedX);
                        itemtable.Add((byte)item.RotSpeedY);
                        itemtable.Add((byte)item.RotSpeedZ);
                        itemtable.Add((byte)item.ObjectType);
                        itemtable.Add(item.Texture);
                        itemtable.AddRange((BitConverter.GetBytes((ushort)item.Flags)));
                        itemtable.Add(item.InternalID);
                        itemtable.Add(item.Unknown3);
                        itemtable.Add(item.Message);
                        itemtable.Add(item.TriggerDistance);
                        itemtable.Add(item.WarpLevelOrSoundbank);
                        itemtable.Add(item.WarpActOrSoundID);
                        itemtable.AddRange(BitConverter.GetBytes(item.RotationX));
                        itemtable.AddRange(BitConverter.GetBytes(item.RotationY));
                        itemtable.AddRange(BitConverter.GetBytes(item.RotationZ));
                        itemtable.AddRange(BitConverter.GetBytes(item.X));
                        itemtable.AddRange(BitConverter.GetBytes(item.Y));
                        itemtable.AddRange(BitConverter.GetBytes(item.Z));
                    }
                }
                if (itemtable.Count % 32 != 0)
                {
                    do
                    {
                        itemtable.Add(0);
                    }while (itemtable.Count % 32 != 0);
                }
                // Convert Japanese strings
                List <byte> stringtable = new List <byte>();

                foreach (string str in JapaneseStrings)
                {
                    if (str != null)
                    {
                        for (int s = 0; s < str.Length; s++)
                        {
                            if (str[s] == '\t')
                            {
                                stringtable.AddRange(System.Text.Encoding.GetEncoding(932).GetBytes("t"));
                            }
                            else if (str[s] == '\n')
                            {
                                stringtable.AddRange(System.Text.Encoding.GetEncoding(932).GetBytes("n"));
                            }
                            else
                            {
                                stringtable.AddRange(System.Text.Encoding.GetEncoding(932).GetBytes(str[s].ToString()));
                            }
                        }
                    }
                    do
                    {
                        stringtable.Add(0);
                    }while (stringtable.Count % 64 != 0);
                }
                // Convert European strings
                if (EnglishStrings != null)
                {
                    stringtable.AddRange(ProcessStrings(EnglishStrings, 932)); // English uses the same character set as Japanese
                    stringtable.AddRange(ProcessStrings(FrenchStrings));
                    stringtable.AddRange(ProcessStrings(SpanishStrings));
                    stringtable.AddRange(ProcessStrings(GermanStrings));
                }
                // Set size
                int fullsize = SoundData.Length + ModelData.Length + TextureData.Length + itemtable.Count + stringtable.Count + 64; // 64 is sections table at 0x280 w/checksum + 16 bytes of padding

                if ((fullsize + 640) % 512 != 0)
                {
                    do
                    {
                        fullsize++;
                    }while ((fullsize + 640) % 512 != 0);
                }
                // Convert title, description etc.
                byte[] title_b = new byte[16];
                byte[] title   = System.Text.Encoding.GetEncoding(932).GetBytes(Title);
                Array.Copy(title, 0, title_b, 0, title.Length);
                result.AddRange(title_b);
                byte[] desc_b = new byte[32];
                byte[] desc   = System.Text.Encoding.GetEncoding(932).GetBytes(Description);
                Array.Copy(desc, 0, desc_b, 0, desc.Length);
                result.AddRange(desc_b);
                byte[] app_b = new byte[16];
                byte[] app   = System.Text.Encoding.GetEncoding(932).GetBytes(AppName);
                Array.Copy(app, 0, app_b, 0, app.Length);
                result.AddRange(app_b);
                result.AddRange(BitConverter.GetBytes((ushort)1));      // Number of icons
                result.AddRange(BitConverter.GetBytes((ushort)1));      // Animation speed
                result.AddRange(BitConverter.GetBytes((ushort)0));      // Eyecatch type
                result.AddRange(BitConverter.GetBytes((ushort)0));      // CRC (unused)
                result.AddRange(BitConverter.GetBytes((uint)fullsize)); // Size of the entire thing without VMS header
                for (int u = 0; u < 20; u++)
                {
                    result.Add(0);
                }
                result.AddRange(GetIconBytes(Icon));
                result.AddRange(BitConverter.GetBytes((uint)0x2C0)); // Item layout table pointer
                result.AddRange(BitConverter.GetBytes((uint)Items.Count));
                int textpointer = 704 + itemtable.Count;

                result.AddRange(BitConverter.GetBytes((uint)textpointer)); // Text table pointer
                int textcount = JapaneseStrings.Length + EnglishStrings.Length + FrenchStrings.Length + GermanStrings.Length + SpanishStrings.Length;

                result.AddRange(BitConverter.GetBytes((uint)textcount));
                int pvmpointer = textpointer + 64 * textcount;

                result.AddRange(BitConverter.GetBytes((uint)pvmpointer));
                int pvmcount = (TextureData != null && TextureData.Length != 0) ? 1 : 0;

                result.AddRange(BitConverter.GetBytes((uint)pvmcount)); // PVM count
                ushort numtextures = 0;

                if (pvmcount != 0)
                {
                    numtextures = BitConverter.ToUInt16(TextureData, 0xA);
                }
                result.AddRange(BitConverter.GetBytes((uint)numtextures)); // Number of textures in the PVM
                int mltpointer = pvmpointer + TextureData.Length;

                result.AddRange(BitConverter.GetBytes((uint)mltpointer));
                if (ContainsSound)
                {
                    result.AddRange(BitConverter.GetBytes((uint)1)); // MLT count
                }
                else
                {
                    result.AddRange(BitConverter.GetBytes((uint)0));
                }
                int prspointer = mltpointer + SoundData.Length;

                result.AddRange(BitConverter.GetBytes((uint)prspointer));
                if (ModelData != null && ModelData.Length > 0)
                {
                    result.AddRange(BitConverter.GetBytes((uint)1)); // Number of PRS
                }
                else
                {
                    result.AddRange(BitConverter.GetBytes((uint)0));
                }
                List <byte> final = new List <byte>();

                final.AddRange(itemtable.ToArray());
                final.AddRange(stringtable.ToArray());
                if (TextureData != null && TextureData.Length > 0)
                {
                    final.AddRange(TextureData);
                }
                if (ContainsSound)
                {
                    final.AddRange(SoundData);
                }
                final.AddRange(ModelData);
                byte[] finalarr = final.ToArray();
                uint   checksum = VMSFile.CalculateChecksum(ref finalarr, 0, finalarr.Length);

                result.AddRange(BitConverter.GetBytes(checksum));
                for (int u = 0; u < 16; u++)
                {
                    result.Add(0);
                }
                result.AddRange(final);
                if (result.Count % 512 != 0)
                {
                    do
                    {
                        result.Add(0);
                    }while (result.Count % 512 != 0);
                }
                // Encrypt
                byte[] resdata = result.ToArray();
                ProcessVMS(ref resdata);
                return(resdata);
            }
Exemplo n.º 14
0
            /// <summary>
            /// Load from a byte array (VMS file)
            /// </summary>
            public VMS_DLC(byte[] file)
            {
                // Decrypt if encrypted
                if (BitConverter.ToUInt32(file, 0x280) != 0x2C0)
                {
                    int    aniFrames = file[0x40] + (file[0x41] << 8);
                    int    dataStart = 0x80 + (aniFrames * 0x200);
                    byte[] encrypted = new byte[file.Length - dataStart];
                    Array.Copy(file, dataStart, encrypted, 0, encrypted.Length);
                    VMSFile.DecryptData(ref encrypted);
                    Array.Copy(encrypted, 0, file, dataStart, encrypted.Length);
                }
                // Get title and other stuff
                byte[] title_b       = GetTextItem(ref file, 0, 16);
                byte[] description_b = GetTextItem(ref file, 0x10, 32);
                byte[] appname_b     = GetTextItem(ref file, 0x30, 16);
                Description = System.Text.Encoding.GetEncoding(932).GetString(description_b);
                Title       = System.Text.Encoding.GetEncoding(932).GetString(title_b);
                AppName     = System.Text.Encoding.GetEncoding(932).GetString(appname_b);
                Icon        = GetIconFromFile(file);
                // Get items
                int item_pointer = BitConverter.ToInt32(file, 0x280);

                if (item_pointer != 0x2C0)
                {
                    System.Windows.Forms.MessageBox.Show("Unable to find SA1 DLC data.", "DLC Tool Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                    Items           = new List <DLCObjectData>();
                    JapaneseStrings = new string[16];
                    EnglishStrings  = new string[16];
                    FrenchStrings   = new string[16];
                    GermanStrings   = new string[16];
                    SpanishStrings  = new string[16];
                    TextureData     = new byte[0];
                    SoundData       = new byte[0];
                    ModelData       = new byte[0];
                    return;
                }
                Identifier = BitConverter.ToUInt32(file, item_pointer);
                if ((file[item_pointer + 4] & 0xF) > 0)
                {
                    EnableSonic = true;
                }
                if ((file[item_pointer + 4] >> 4) > 0)
                {
                    EnableTails = true;
                }
                if ((file[item_pointer + 5] & 0xF) > 0)
                {
                    EnableKnuckles = true;
                }
                if ((file[item_pointer + 5] >> 4) > 0)
                {
                    EnableGamma = true;
                }
                if ((file[item_pointer + 6] & 0xF) > 0)
                {
                    EnableAmy = true;
                }
                if ((file[item_pointer + 6] >> 4) > 0)
                {
                    EnableBig = true;
                }
                if ((file[item_pointer + 7] & 0xF) > 0)
                {
                    EnableWhatever1 = true;
                }
                if ((file[item_pointer + 7] >> 4) > 0)
                {
                    EnableWhatever2 = true;
                }
                Region = (DLCRegionLocks)BitConverter.ToInt32(file, item_pointer + 8);
                // Item table
                int item_count = BitConverter.ToInt32(file, 0x284);

                Items         = new List <DLCObjectData>(item_count);
                item_pointer += 12; // Skip 12-byte item section header
                for (int u = 0; u < item_count; u++)
                {
                    DLCObjectData dlcitem = new DLCObjectData();
                    dlcitem.Level                = file[item_pointer + u * 30];
                    dlcitem.Act                  = file[item_pointer + u * 30 + 1];
                    dlcitem.ScaleX               = file[item_pointer + u * 30 + 2];
                    dlcitem.ScaleY               = file[item_pointer + u * 30 + 3];
                    dlcitem.ScaleZ               = file[item_pointer + u * 30 + 4];
                    dlcitem.RotSpeedX            = (sbyte)file[item_pointer + u * 30 + 5];
                    dlcitem.RotSpeedY            = (sbyte)file[item_pointer + u * 30 + 6];
                    dlcitem.RotSpeedX            = (sbyte)file[item_pointer + u * 30 + 7];
                    dlcitem.ObjectType           = (DLCObjectTypes)file[item_pointer + u * 30 + 8];
                    dlcitem.Texture              = file[item_pointer + u * 30 + 9];
                    dlcitem.Flags                = (DLCObjectFlags)(BitConverter.ToUInt16(file, item_pointer + u * 30 + 10));
                    dlcitem.InternalID           = file[item_pointer + u * 30 + 12];
                    dlcitem.Unknown3             = file[item_pointer + u * 30 + 13];
                    dlcitem.Message              = file[item_pointer + u * 30 + 14];
                    dlcitem.TriggerDistance      = file[item_pointer + u * 30 + 15];
                    dlcitem.WarpLevelOrSoundbank = file[item_pointer + u * 30 + 16];
                    dlcitem.WarpActOrSoundID     = file[item_pointer + u * 30 + 17];
                    dlcitem.RotationX            = BitConverter.ToUInt16(file, item_pointer + u * 30 + 18);
                    dlcitem.RotationY            = BitConverter.ToUInt16(file, item_pointer + u * 30 + 20);
                    dlcitem.RotationZ            = BitConverter.ToUInt16(file, item_pointer + u * 30 + 22);
                    dlcitem.X = BitConverter.ToInt16(file, item_pointer + u * 30 + 24);
                    dlcitem.Y = BitConverter.ToInt16(file, item_pointer + u * 30 + 26);
                    dlcitem.Z = BitConverter.ToInt16(file, item_pointer + u * 30 + 28);
                    Items.Add(dlcitem);
                }
                // Get strings
                JapaneseStrings = new string[16];
                EnglishStrings  = new string[16];
                FrenchStrings   = new string[16];
                SpanishStrings  = new string[16];
                GermanStrings   = new string[16];
                int           text_pointer = BitConverter.ToInt32(file, 0x288);
                int           text_count   = BitConverter.ToInt32(file, 0x28C);
                List <string> strings      = new List <string>();

                for (int u = 0; u < text_count; u++)
                {
                    byte[] arr = new byte[64];
                    Array.Copy(file, text_pointer + 64 * u, arr, 0, 64);
                    int charcount = 0;
                    for (int a = 0; a < arr.Length; a++)
                    {
                        if (arr[a] == 0)
                        {
                            break;
                        }
                        charcount++;
                    }
                    System.Text.Encoding enc = System.Text.Encoding.GetEncoding(932);
                    if (u >= 32)
                    {
                        enc = System.Text.Encoding.GetEncoding(1252);
                    }
                    string str = enc.GetString(arr, 0, charcount);
                    strings.Add(str);
                }
                // Process special characters
                List <string> strings_new = new List <string>();

                foreach (string str in strings)
                {
                    string newstr = System.String.Empty;
                    for (int s = 0; s < str.Length; s++)
                    {
                        if (s == 0 && (str[s] == '~' || str[s] == 't'))
                        {
                            newstr += ("\t");
                        }
                        else if (str[s] == 't' && str[0] == 't')
                        {
                            newstr += ("\t");
                        }
                        else if (str[s] == '~' && str[0] == '~')
                        {
                            newstr += ("\t");
                        }
                        else if ((str[s] == 'n' && str[0] == 't') || (str[s] == '@' && str[0] == '~'))
                        {
                            newstr += ("\n");
                        }
                        else
                        {
                            newstr += str[s];
                        }
                    }
                    strings_new.Add(newstr);
                }
                string[] stringarr = strings_new.ToArray();
                for (int u = 0; u < 16; u++)
                {
                    if (u >= text_count)
                    {
                        break;
                    }
                    JapaneseStrings[u] = stringarr[u];
                    if (text_count <= 16)
                    {
                        continue;
                    }
                    EnglishStrings[u] = stringarr[u + 16];
                    if (text_count <= 32)
                    {
                        continue;
                    }
                    FrenchStrings[u] = stringarr[u + 32];
                    if (text_count <= 48)
                    {
                        continue;
                    }
                    SpanishStrings[u] = stringarr[u + 48];
                    if (text_count <= 64)
                    {
                        continue;
                    }
                    GermanStrings[u] = stringarr[u + 64];
                }
                TextureData = new byte[0];
                SoundData   = new byte[0];
                ModelData   = new byte[0];
                // Get PVM pointer
                uint pvm_pointer = BitConverter.ToUInt32(file, 0x290); // Number of PVMs at 0x294, number of textures at 0x298
                // Get MLT pointer
                uint mlt_pointer = BitConverter.ToUInt32(file, 0x29C);
                int  nummlt      = BitConverter.ToInt32(file, 0x2A0);

                if (nummlt != 0)
                {
                    ContainsSound = true;
                }
                // Get PRS pointer
                uint prs_pointer = BitConverter.ToUInt32(file, 0x2A4); // Number of PRSes at 0x2A8
                // Get PVM data
                int pvm_size = (int)mlt_pointer - (int)pvm_pointer;

                if (pvm_size > 0)
                {
                    TextureData = new byte[pvm_size];
                    Array.Copy(file, pvm_pointer, TextureData, 0, pvm_size);
                }
                // Get MLT data
                int mlt_size = (int)prs_pointer - (int)mlt_pointer;

                if (mlt_size > 0)
                {
                    SoundData = new byte[mlt_size];
                    Array.Copy(file, mlt_pointer, SoundData, 0, mlt_size);
                }
                int item_size = (item_count * 30 + 12); // 12-byte header, headerless section size at 0x48

                do
                {
                    item_size++;
                }while (item_size % 16 != 0);
                // The size of the PRS cannot be determined reliably because the file might be padded to have a size divisible by 512
                // To get the correct size, the PRS chunk is read until the end of file or a sequence of 16 empty bytes
                int prs_size = 0;

                for (int indx = (int)prs_pointer; indx < file.Length; indx += 16)
                {
                    bool valid = false;
                    for (int u = 0; u < 16; u++)
                    {
                        if (file[indx + u] != 0)
                        {
                            valid = true;
                            break;
                        }
                    }
                    if (valid)
                    {
                        prs_size += 16;
                    }
                    else
                    {
                        break;
                    }
                }
                // Get PRS data
                if (prs_size > 0)
                {
                    ModelData = new byte[prs_size];
                    Array.Copy(file, prs_pointer, ModelData, 0, prs_size);
                }
            }