Exemple #1
0
        public override byte[] ToRaw()
        {
            MemoryStream rebuildingFile   = new MemoryStream();
            BinaryWriter rebuildingWriter = new BinaryWriter(rebuildingFile);

            rebuildingWriter.Write(0x32425354); //TSB2
            int currentStart = 0xC;

            rebuildingFile.Seek(0xC, SeekOrigin.Begin);
            for (int i = 0; i < subroutines.Count; i++)
            {
                rebuildingFile.Seek(4, SeekOrigin.Current);
                subroutine temp = (subroutine)subroutines[i];
                rebuildingWriter.Write(ASCIIEncoding.UTF8.GetBytes(temp.name.PadRight(0x20, '\0')));
                int headerLoc = (int)rebuildingFile.Position;
                rebuildingFile.Seek(0xC, SeekOrigin.Current);
                //rebuildingFile.Write(temp.subType);       Fill this in with the rest!
                ArrayList localVariables = new ArrayList();
                int[]     opcodeLocs     = new int[temp.opcodes.Count];
                int       writeStart     = (int)rebuildingFile.Position;
                for (int j = 0; j < temp.opcodes.Count; j++)
                {
                    opcodeLocs[j] = (int)rebuildingFile.Position - writeStart;
                    operation tempOpcode = (operation)temp.opcodes[j];
                    rebuildingWriter.Write(tempOpcode.opcode);
                    if (tempOpcode.opcode == 0x46)  //Only one with an actual string argument
                    {
                        byte[] convertedString = ASCIIEncoding.GetEncoding("shift-jis").GetBytes(tempOpcode.strArg + '\0');
                        if (convertedString.Length % 4 != 0)
                        {
                            Array.Resize(ref convertedString, (convertedString.Length + 3) & 0xFFFFFFC);
                        }
                        tempOpcode.intArg = convertedString.Length / 4;
                        rebuildingWriter.Write(tempOpcode.intArg);
                        rebuildingWriter.Write(convertedString);
                    }
                    else if (opcodeTypes[tempOpcode.opcode] == 4) //These are the local variable ones!
                    {
                        if (!stringNames.Contains(tempOpcode.strArg))
                        {
                            Array.Resize(ref stringNames, stringNames.Length + 1);
                            stringNames[stringNames.Length - 1] = tempOpcode.strArg;
                        }
                        localVariables.Add(Array.IndexOf(stringNames, tempOpcode.strArg));
                        localVariables.Add((int)((rebuildingFile.Position - 0xC - headerLoc) / 4));
                        rebuildingWriter.Write((int)(-1));//Array.IndexOf(stringNames, tempOpcode.strArg));
                    }
                    else if (opcodeTypes[tempOpcode.opcode] == 3)
                    {
                        rebuildingWriter.Write(tempOpcode.floatArg);
                    }
                    else if (opcodeTypes[tempOpcode.opcode] == 2)
                    {
                        rebuildingWriter.Write(tempOpcode.intArg);
                    }
                }
                int localVarLoc = (int)rebuildingFile.Position;

                for (int j = 0; j < opcodeLocs.Length; j++)
                {
                    if (((operation)temp.opcodes[j]).opcode > 0x2B && ((operation)temp.opcodes[j]).opcode < 0x2F)
                    {
                        int branchSource = opcodeLocs[j] + 0x8;
                        int realDest     = opcodeLocs[((operation)temp.opcodes[j]).intArg];
                        rebuildingFile.Seek(writeStart + opcodeLocs[j] + 0x4, SeekOrigin.Begin);
                        rebuildingWriter.Write((int)(realDest - branchSource) >> 2);
                    }
                }

                rebuildingFile.Seek(localVarLoc, SeekOrigin.Begin);
                for (int j = 0; j < localVariables.Count; j += 2)
                {
                    rebuildingWriter.Write((int)localVariables[localVariables.Count - 2 - j]);
                    rebuildingWriter.Write((int)localVariables[localVariables.Count - 1 - j]);
                }
                int nextSubLoc = (int)rebuildingFile.Position;
                rebuildingFile.Seek(headerLoc, SeekOrigin.Begin);
                rebuildingWriter.Write((int)localVarLoc - headerLoc - 0xC);
                rebuildingWriter.Write(temp.subType);
                rebuildingWriter.Write(localVariables.Count / 2);
                rebuildingFile.Seek(currentStart, SeekOrigin.Begin);
                if (i + 1 < subroutines.Count)
                {
                    rebuildingWriter.Write(nextSubLoc - 0xC);
                }
                else
                {
                    rebuildingWriter.Write((int)0);
                }
                rebuildingFile.Seek(nextSubLoc, SeekOrigin.Begin);
                currentStart = nextSubLoc;
            }
            int stringListLoc = (int)rebuildingFile.Position;

            for (int i = 0; i < stringNames.Length; i++)
            {
                rebuildingWriter.Write(ASCIIEncoding.UTF8.GetBytes(stringNames[i].PadRight(0x20, '\0')));
            }
            rebuildingFile.Seek(4, SeekOrigin.Begin);
            rebuildingWriter.Write(stringListLoc - 0xC);
            rebuildingWriter.Write(stringNames.Length * 0x20);
            byte[] compressedFile = PrsCompDecomp.compress(rebuildingFile.ToArray());
            byte[] toReturn       = new byte[compressedFile.Length + 0x1C];
            Array.Copy(BitConverter.GetBytes(rebuildingFile.Length), 0, toReturn, 0, 4);
            Array.Copy(BitConverter.GetBytes(compressedFile.Length), 0, toReturn, 4, 4);
            Array.Copy(compressedFile, 0, toReturn, 0x1C, compressedFile.Length);
            return(toReturn);
        }
Exemple #2
0
        public ScriptFile(string inFilename, byte[] rawData, bool bigEndian = false)
        {
            filename = inFilename;
            int inFilesize, outFilesize;

            if (!bigEndian)
            {
                outFilesize = BitConverter.ToInt32(rawData, 0);
                inFilesize  = BitConverter.ToInt32(rawData, 4);
            }
            else
            {
                byte[] outFilesizeBytes = new byte[] { rawData[3], rawData[2], rawData[1], rawData[0] };
                byte[] inFilesizeBytes  = new byte[] { rawData[7], rawData[6], rawData[5], rawData[4] };
                if (BitConverter.ToUInt32(inFilesizeBytes, 0) > rawData.Length)
                {
                    //Stupid hack to try to fix tobitama
                    outFilesize = BitConverter.ToInt32(outFilesizeBytes.Reverse().ToArray(), 0);
                    inFilesize  = BitConverter.ToInt32(inFilesizeBytes.Reverse().ToArray(), 0);
                }
                else
                {
                    outFilesize = BitConverter.ToInt32(outFilesizeBytes, 0);
                    inFilesize  = BitConverter.ToInt32(inFilesizeBytes, 0);
                }
            }

            byte[] temp = new byte[inFilesize];
            Array.Copy(rawData, 0x1C, temp, 0, inFilesize);
            byte[] decompressed = PrsCompDecomp.Decompress(temp, (uint)outFilesize);

            MemoryStream scriptStream = new MemoryStream(decompressed);
            BinaryReader scriptReader;

            if (bigEndian)
            {
                scriptReader = new BigEndianBinaryReader(scriptStream);
            }
            else
            {
                scriptReader = new BinaryReader(scriptStream);
            }
            scriptStream.Seek(4, SeekOrigin.Begin);
            int stringListPtr    = scriptReader.ReadInt32();
            int stringListLength = scriptReader.ReadInt32();

            scriptStream.Seek(stringListPtr + 0xC, SeekOrigin.Begin);
            stringNames = new string[stringListLength / 0x20];
            for (int i = 0; i < stringNames.Length; i++)
            {
                stringNames[i] = ASCIIEncoding.UTF8.GetString(scriptReader.ReadBytes(0x20));
                stringNames[i] = stringNames[i].TrimEnd('\0');
            }
            scriptStream.Seek(0xC, SeekOrigin.Begin);

            //ArrayList subroutines = new ArrayList();
            while (scriptStream.Position < stringListPtr)
            {
                int    nextSubLoc     = scriptReader.ReadInt32() + 0xC;
                string subroutineName = ASCIIEncoding.UTF8.GetString(scriptReader.ReadBytes(0x20)).TrimEnd('\0');
                int    subLength      = scriptReader.ReadInt32();
                int    subType        = scriptReader.ReadLittleEndianInt32();
                int    locals         = scriptReader.ReadInt32();
                int    currLoc        = (int)scriptStream.Position;
                int    subEnd         = currLoc + subLength;
                scriptStream.Seek(subLength, SeekOrigin.Current);
                int[] localNums = new int[locals];
                int[] localLocs = new int[locals];
                if (subType == 0x4C)
                {
                    for (int i = 0; i < locals; i++)
                    {
                        localNums[i] = scriptReader.ReadInt32();
                        localLocs[i] = scriptReader.ReadInt32() * 4;
                    }
                }
                List <operation> operations = new List <operation>();
                List <int>       opcodeLocs = new List <int>();

                scriptStream.Seek(currLoc, SeekOrigin.Begin);
                while (scriptStream.Position < subEnd)
                {
                    opcodeLocs.Add((int)(scriptStream.Position - currLoc));
                    int currOpcode = scriptReader.ReadInt32();

                    operation tempOp = new operation();
                    if (opcodeTypes[currOpcode] == 3)
                    {
                        tempOp.floatArg = scriptReader.ReadSingle();
                    }
                    else if (opcodeTypes[currOpcode] > 1 && opcodeTypes[currOpcode] != 4 && !localLocs.Contains((int)(scriptStream.Position - currLoc)))
                    {
                        tempOp.intArg = scriptReader.ReadInt32();
                    }
                    else if (localLocs.Contains((int)(scriptStream.Position - currLoc)))
                    {
                        tempOp.strArg = stringNames[localNums[Array.IndexOf(localLocs, (int)(scriptStream.Position - currLoc))]];
                        tempOp.intArg = scriptReader.ReadInt32();
                    }
                    if (opcodeTypes[currOpcode] == 99)
                    {
                        tempOp.strArg = ASCIIEncoding.GetEncoding("shift-jis").GetString(scriptReader.ReadBytes(tempOp.intArg * 4)).TrimEnd('\0');
                    }
                    tempOp.opcode = currOpcode;
                    operations.Add(tempOp);
                }

                for (int i = 0; i < operations.Count; i++)
                {
                    if (((operation)operations[i]).opcode > 0x2B && ((operation)operations[i]).opcode < 0x2F)
                    {
                        int branchSource  = opcodeLocs[i] + 0x8;
                        int branchDestRaw = branchSource + 4 * ((operation)operations[i]).intArg;
                        for (int j = 0; j < operations.Count; j++)
                        {
                            if (branchDestRaw == opcodeLocs[j])
                            {
                                ((operation)operations[i]).intArg = j;
                                break;
                            }
                        }
                    }
                }
                subroutine tempSub = new subroutine();
                tempSub.name    = subroutineName;
                tempSub.subType = subType;
                if (subType != 0x4C)
                {
                    tempSub.miscData = locals;
                }
                else
                {
                    tempSub.miscData = -1;
                }
                tempSub.opcodes = operations;

                subroutines.Add(tempSub);
                if (nextSubLoc == 0xC)
                {
                    break;
                }
                scriptStream.Seek(nextSubLoc, SeekOrigin.Begin);
            }
            scriptReader.Close();
        }
Exemple #3
0
        private NblChunk loadGroup(Stream fileToLoad, BinaryReader fileLoader)
        {
            NblChunk toRet = new NblChunk();

            toRet.bigEndian = isBigEndian;
            long offset = fileToLoad.Position;

            string formatName          = new String(fileLoader.ReadChars(4));
            ushort fileVersion         = fileLoader.ReadUInt16();
            int    paddingAmount       = fileVersion == 0x1002 ? 0x3F : 0x7FF;
            uint   mask                = fileVersion == 0x1002 ? 0xFFFFFFC0 : 0xFFFFF800;
            ushort chunkFilenameLength = fileLoader.ReadUInt16();
            int    headerSize          = fileLoader.ReadInt32();
            int    numFiles            = fileLoader.ReadInt32();
            uint   uncompressedSize    = fileLoader.ReadUInt32();
            uint   compressedSize      = fileLoader.ReadUInt32();
            uint   pointerLength       = fileLoader.ReadUInt32() / 4;

            if (formatName.StartsWith("NML"))
            {
                decryptKey = fileLoader.ReadUInt32();
            }
            else
            {
                fileLoader.ReadUInt32();
            }
            uint size = compressedSize == 0 ? uncompressedSize : compressedSize;

            uint nmllDataLoc    = (uint)((headerSize + paddingAmount) & mask);
            uint pointerLoc     = (uint)(nmllDataLoc + size + paddingAmount) & mask;
            uint mainHeaderSize = 0x20;

            if (formatName.StartsWith("NML"))
            {
                mainHeaderSize = 0x30;
                uint tmllHeaderSize     = fileLoader.ReadUInt32();
                uint tmllDataSizeUncomp = fileLoader.ReadUInt32();
                uint tmllDataSizeComp   = fileLoader.ReadUInt32();
                uint tmllCount          = fileLoader.ReadUInt32();
                if (tmllCount > 0)
                {
                    tmllHeaderLoc = (uint)(pointerLoc + pointerLength * 4 + paddingAmount) & mask;
                }
            }

            decryptor = new BlewFish(decryptKey, isBigEndian);
            FileHeader[] groupHeaders = new FileHeader[numFiles];

            for (int i = 0; i < numFiles; i++)
            {
                fileToLoad.Seek(mainHeaderSize + 0x60 * i + offset, SeekOrigin.Begin);
                FileHeader currentHeader = readHeader(fileLoader.ReadBytes(0x60));
                groupHeaders[i] = currentHeader;
            }

            fileToLoad.Seek(nmllDataLoc + offset, SeekOrigin.Begin);
            int encryptedSectionSize;

            if (fileVersion == 0x1002)
            {
                //Obfuscation stuff from sega.
                int rawEncryptedSectionSize = (int)((((compressedSize >> 0xB) ^ compressedSize) & 0xE0) + 0x20);
                encryptedSectionSize = Math.Min(rawEncryptedSectionSize, (int)compressedSize);
            }
            else
            {
                encryptedSectionSize = (int)size;
            }

            if (encryptedSectionSize % 8 != 0)
            {
                encryptedSectionSize -= (encryptedSectionSize % 8);
            }

            byte[] decryptedFiles;
            if (decryptKey != 0 && formatName.StartsWith("NML"))
            {
                byte[] encryptedFiles = fileLoader.ReadBytes((int)size);
                decryptedFiles = decryptor.decryptBlock(encryptedFiles, encryptedSectionSize);
            }
            else
            {
                decryptedFiles = fileLoader.ReadBytes((int)size + 7);
            }

            if (compressedSize != 0)
            {
                if (fileVersion == 0x1002)
                {
                    DeflateStream ds = new DeflateStream(new MemoryStream(decryptedFiles), CompressionMode.Decompress);
                    MemoryStream  decompressedStream = new MemoryStream((int)uncompressedSize);
                    ds.CopyTo(decompressedStream);
                    decompressedFiles = decompressedStream.ToArray();
                }
                else
                {
                    decompressedFiles = PrsCompDecomp.Decompress(decryptedFiles, uncompressedSize);
                }
            }
            else
            {
                decompressedFiles = decryptedFiles;
            }

            List <int> pointers = new List <int>((int)pointerLength);

            if (pointerLength > 0)
            {
                fileToLoad.Seek(pointerLoc + offset, SeekOrigin.Begin);
                for (int i = 0; i < pointerLength; i++)
                {
                    pointers.Add(fileLoader.ReadInt32());
                }
            }

            List <RawFile> files = new List <RawFile>(numFiles);

            for (int i = 0; i < numFiles; i++)
            {
                RawFile tempFile = new RawFile();
                tempFile.filename   = groupHeaders[i].fileName;
                tempFile.subHeader  = groupHeaders[i].subHeader;
                tempFile.chunkSize  = groupHeaders[i].chunkSize;
                tempFile.fileOffset = groupHeaders[i].filePosition;

                tempFile.fileContents = new byte[groupHeaders[i].fileSize];
                Array.Copy(decompressedFiles, groupHeaders[i].filePosition, tempFile.fileContents, 0, groupHeaders[i].fileSize);
                if (tempFile.fileContents.Length > 0)
                {
                    tempFile.fileheader = new String(ASCIIEncoding.ASCII.GetChars(tempFile.fileContents, 0, 4));
                }
                if (groupHeaders[i].pointerSize > 0)
                {
                    tempFile.pointers = pointers.GetRange((int)groupHeaders[i].pointerPosition / 4, (int)groupHeaders[i].pointerSize / 4);
                }
                files.Add(tempFile);
            }
            toRet.encryptionKey = decryptKey;
            toRet.encrypted     = decryptKey != 0;
            toRet.compressed    = compressedSize != 0;
            toRet.chunkID       = formatName;
            toRet.versionNumber = (short)fileVersion;
            toRet.fileContents  = files;
            return(toRet);
        }
Exemple #4
0
        public byte[] SaveFile(bool discardChanges)
        {
            //First, combine all the files.
            MemoryStream groupFileStream   = new MemoryStream();
            MemoryStream groupHeaderStream = new MemoryStream();
            BinaryWriter groupHeaderWriter;

            if (bigEndian)
            {
                groupHeaderWriter = new BigEndianBinaryWriter(groupHeaderStream);
            }
            else
            {
                groupHeaderWriter = new BinaryWriter(groupHeaderStream);
            }
            int  paddingAmount = versionNumber == 0x1002 ? 0x3F : 0x7FF;
            uint mask          = versionNumber == 0x1002 ? 0xFFFFFFC0 : 0xFFFFF800;

            if (this.chunkID.StartsWith("NML"))
            {
                groupHeaderStream.Seek(0x30, SeekOrigin.Begin);
            }
            else if (this.chunkID.StartsWith("TML"))
            {
                groupHeaderStream.Seek(0x20, SeekOrigin.Begin);
            }

            NblLoader.FileHeader[] headers    = new NblLoader.FileHeader[this.fileContents.Count];
            List <RawFile>         savedFiles = new List <RawFile>(this.fileContents);
            List <int>             pointers   = new List <int>();
            //Annoying, this one has to be a running tally, can't do it any other way.
            ushort filenamelength = 0;

            for (int i = 0; i < fileContents.Count; i++)
            {
                //Figure out whether to take the cached copy or the original
                if (this.loadedFileCache.ContainsKey(fileContents[i].filename) && !discardChanges)
                {
                    savedFiles[i]           = loadedFileCache[fileContents[i].filename].ToRawFile((uint)groupFileStream.Position);
                    savedFiles[i].chunkSize = fileContents[i].chunkSize;
                }
                else if (savedFiles[i].fileOffset != (uint)groupFileStream.Position)
                {
                    savedFiles[i].RebaseFile((uint)groupFileStream.Position);
                }
                //Let's not use a FileHeader any more. Just put all the data straight into the file.
                //Guessing on identifier--this SHOULD be true, generally, but...?
                //This needs to be stored in the file class.
                string identifier = "STD\0";
                if (this.chunkID.StartsWith("TML"))
                {
                    identifier = "NNVR";
                }
                else if (savedFiles[i].subHeader != null && savedFiles[i].subHeader[0] == 0x4E) //'N'--so hopefully just NXIF or NUIF
                {
                    identifier = Path.GetExtension(savedFiles[i].filename).Substring(1).ToUpper().PadRight(4, '\0');
                }
                groupHeaderWriter.Write(ASCIIEncoding.ASCII.GetBytes(identifier));
                groupHeaderWriter.Write(savedFiles[i].chunkSize);
                groupHeaderWriter.Write((int)0); //"unknown1"
                groupHeaderWriter.Write((int)0); //"unknown2"
                groupHeaderWriter.Write(ASCIIEncoding.ASCII.GetBytes(savedFiles[i].filename.PadRight(0x20, '\0')));
                groupHeaderWriter.Write(savedFiles[i].fileOffset);
                groupHeaderWriter.Write(savedFiles[i].fileContents.Length);
                groupHeaderWriter.Write(pointers.Count * 4);
                groupHeaderWriter.Write(savedFiles[i].pointers.Count * 4);
                if (savedFiles[i].subHeader == null)
                {
                    groupHeaderWriter.Write(new byte[0x20]);
                }
                else
                {
                    groupHeaderWriter.Write(savedFiles[i].subHeader);
                }

                //Update filename length (include \0 terminator).
                if (this.chunkID.StartsWith("NML"))
                {
                    filenamelength += (ushort)(savedFiles[i].filename.Length + 1);
                }

                //Now put the data into the file pieces.
                groupFileStream.Write(savedFiles[i].fileContents, 0, savedFiles[i].fileContents.Length);
                //Padding out to nearest 0x10
                groupFileStream.Seek((int)(groupFileStream.Position + 0x1F) & 0xFFFFFFE0, SeekOrigin.Begin);
                pointers.AddRange(savedFiles[i].pointers);
            }
            int headerLength = (int)groupHeaderStream.Position;

            groupHeaderStream.Seek((groupHeaderStream.Position + paddingAmount) & mask, SeekOrigin.Begin);
            int uncompressedSize = (int)groupFileStream.Position;

            byte[] rawData;
            if (compressed)
            {
                if (versionNumber == 0x1002) // PSP2 files use Deflate.
                {
                    groupFileStream.Seek(0, SeekOrigin.Begin);
                    MemoryStream compressedStream = new MemoryStream();
                    using (DeflateStream ds = new DeflateStream(compressedStream, CompressionMode.Compress))
                    {
                        groupFileStream.CopyTo(ds);
                    }
                    rawData = compressedStream.ToArray();
                }
                else //PSU uses PRS.
                {
                    rawData = PrsCompDecomp.compress(groupFileStream.ToArray());
                }
            }
            else
            {
                rawData = groupFileStream.ToArray();
            }
            int fileLength = rawData.Length;

            groupHeaderWriter.Write(rawData);
            //Write out pointers (if applicable)
            groupHeaderStream.Seek((groupHeaderStream.Position + paddingAmount) & mask, SeekOrigin.Begin);
            for (int i = 0; i < pointers.Count; i++)
            {
                groupHeaderWriter.Write(pointers[i]);
            }
            groupHeaderWriter.Write(new byte[((groupHeaderStream.Position + paddingAmount) & mask) - groupHeaderStream.Position]);

            //Now fill in the header (leaving the space if necessary).
            groupHeaderStream.Seek(0, SeekOrigin.Begin);
            groupHeaderWriter.Write(ASCIIEncoding.ASCII.GetBytes(this.chunkID));
            groupHeaderWriter.Write(this.versionNumber);
            groupHeaderWriter.Write(filenamelength);
            groupHeaderWriter.Write(headerLength);
            groupHeaderWriter.Write(this.fileContents.Count);
            groupHeaderWriter.Write(uncompressedSize);
            if (compressed)
            {
                groupHeaderWriter.Write(rawData.Length);
            }
            else
            {
                groupHeaderWriter.Write((int)0);
            }
            groupHeaderWriter.Write(pointers.Count * 4);
            groupHeaderWriter.Write((int)0); //Still enforcing no encryption.

            return(groupHeaderStream.ToArray());
        }
Exemple #5
0
        private void decryptNMLBToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                byte[] fileContents = File.ReadAllBytes(openFileDialog1.FileName);

                MemoryStream fileStream = new MemoryStream(fileContents);
                fileStream.Seek(3, SeekOrigin.Begin);
                byte endian = (byte)fileStream.ReadByte();
                fileStream.Seek(0, SeekOrigin.Begin);
                BinaryReader fileLoader;
                bool         bigEndian = false;
                if (endian == 0x42)
                {
                    fileLoader = new BigEndianBinaryReader(fileStream);
                    bigEndian  = true;
                }
                else
                {
                    fileLoader = new BinaryReader(fileStream);
                }

                string formatName          = new String(fileLoader.ReadChars(4));
                ushort fileVersion         = fileLoader.ReadUInt16();
                ushort chunkFilenameLength = fileLoader.ReadUInt16();
                uint   headerSize          = fileLoader.ReadUInt32();
                uint   nmllCount           = fileLoader.ReadUInt32();
                uint   uncompressedSize    = fileLoader.ReadUInt32();
                uint   compressedSize      = fileLoader.ReadUInt32();
                uint   pointerLength       = fileLoader.ReadUInt32() / 4;
                uint   blowfishKey         = fileLoader.ReadUInt32();
                uint   tmllHeaderSize      = fileLoader.ReadUInt32();
                uint   tmllDataSizeUncomp  = fileLoader.ReadUInt32();
                uint   tmllDataSizeComp    = fileLoader.ReadUInt32();
                uint   tmllCount           = fileLoader.ReadUInt32();
                uint   tmllHeaderLoc       = 0;

                uint pointerLoc = 0;

                uint size = compressedSize == 0 ? uncompressedSize : compressedSize;

                uint nmllDataLoc = (uint)((headerSize + 0x7FF) & 0xFFFFF800);
                pointerLoc = (uint)(nmllDataLoc + size + 0x7FF) & 0xFFFFF800;
                if (tmllCount > 0)
                {
                    tmllHeaderLoc = (pointerLoc + pointerLength * 4 + 0x7FF) & 0xFFFFF800;
                }

                BlewFish fish = new BlewFish(blowfishKey, bigEndian);

                for (int i = 0; i < nmllCount; i++)
                {
                    int    headerLoc = 0x40 + i * 0x60;
                    byte[] toDecrypt = new byte[0x30];
                    Array.Copy(fileContents, headerLoc, toDecrypt, 0, 0x30);
                    toDecrypt = fish.decryptBlock(toDecrypt);
                    Array.Copy(toDecrypt, 0, fileContents, headerLoc, 0x30);
                }

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < tmllCount; i++)
                {
                    uint   headerLoc = (uint)(tmllHeaderLoc + 0x30 + i * 0x60);
                    byte[] toDecrypt = new byte[0x30];
                    Array.Copy(fileContents, headerLoc, toDecrypt, 0, 0x30);
                    toDecrypt = fish.decryptBlock(toDecrypt);
                    Array.Copy(toDecrypt, 0, fileContents, headerLoc, 0x30);

                    sb.Append(ASCIIEncoding.ASCII.GetString(toDecrypt, 0, 0x20).Split('\0')[0] + "\t");
                    //sb.Append(BitConverter.ToUInt16(fileContents, (int)(headerLoc + 0x4C)) + "\t");
                    //sb.Append(BitConverter.ToUInt16(fileContents, (int)(headerLoc + 0x4E)) + "\n");
                }

                fileStream.Seek(nmllDataLoc, SeekOrigin.Begin);
                byte[] encryptedNmll    = fileLoader.ReadBytes((int)size);
                byte[] decryptedNmll    = fish.decryptBlock(encryptedNmll);
                byte[] decompressedNmll = compressedSize != 0 ? PrsCompDecomp.Decompress(decryptedNmll, uncompressedSize) : decryptedNmll;

                File.WriteAllText(openFileDialog1.FileName + ".tml.list", sb.ToString());
                File.WriteAllBytes(openFileDialog1.FileName + ".decrypt", fileContents);
                File.WriteAllBytes(openFileDialog1.FileName + ".encryptNmll", encryptedNmll);
                File.WriteAllBytes(openFileDialog1.FileName + ".decryptNmll", decryptedNmll);
                File.WriteAllBytes(openFileDialog1.FileName + ".decompressNmll", decompressedNmll);
            }
        }