Example #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);
        }
Example #2
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());
        }