Exemplo n.º 1
0
        //SAVE ----------------------------------------------------------------------
        public static bool SaveXml(string inFileName, string outDir)
        {
            byte[]        inFile = File.ReadAllBytes(inFileName);
            XmlTextWriter writer = new XmlTextWriter(outDir, null);

            writer.Formatting = Formatting.Indented;

            writer.WriteStartElement("PACK");
            writer.WriteStartElement("SARC");
            //SARC header 0x00 - 0x13
            if (inFile[0] != 'S' || inFile[1] != 'A' || inFile[2] != 'R' || inFile[3] != 'C')
            {
                return(false);
            }
            int    pos = 4;                                     //0x04
            ushort hdr = Makeu16(inFile[pos], inFile[pos + 1]); //SARC Header length

            writer.WriteElementString("HeaderLengthBytes", hdr.ToString());
            pos += 2;                                           //0x06
            ushort bom = Makeu16(inFile[pos], inFile[pos + 1]); //Byte Order Mark

            writer.WriteElementString("ByteOrderMark", "0x" + bom.ToString("X"));
            if (bom != 65279) //Check 0x06 for Byte Order Mark (if not 0xFEFF)
            {
                return(false);
            }
            pos += 2; //0x08
            uint fileSize = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]);

            writer.WriteElementString("FileSizeBytes", Convert.ToString(fileSize));
            pos += 4;                                                                                  //0x0C
            uint dataOffset = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]); //Data offset start position

            writer.WriteElementString("DataTableOffset", "0x" + dataOffset.ToString("X"));
            pos += 4;                                                                               //0x10
            uint unknown = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]); //unknown, always 0x01?

            writer.WriteElementString("Unknown", "0x" + unknown.ToString("X"));
            pos += 4;                 //0x14
            writer.WriteEndElement(); //</SARC>

            writer.WriteStartElement("SFAT");
            //SFAT header 0x14 - 0x1F
            if (inFile[pos] != 'S' || inFile[pos + 1] != 'F' || inFile[pos + 2] != 'A' || inFile[pos + 3] != 'T')
            {
                return(false);
            }
            pos += 4;                                            //0x18
            ushort hdr2 = Makeu16(inFile[pos], inFile[pos + 1]); //SFAT Header length

            writer.WriteElementString("HeaderLengthBytes", hdr2.ToString());
            pos += 2;                                                 //0x1A
            ushort nodeCount = Makeu16(inFile[pos], inFile[pos + 1]); //Node Cluster count

            writer.WriteElementString("NodeCount", Convert.ToString(nodeCount));
            pos += 2;                                                                             //0x1C
            uint hashr = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]); //Hash multiplier, always 0x65

            writer.WriteElementString("HashMultiplier", "0x" + hashr.ToString("X"));
            pos += 4; //0x20
            SarcNode[] nodes   = new SarcNode[nodeCount];
            SarcNode   tmpnode = new SarcNode();

            for (int i = 0; i < nodeCount; i++) //Node cluster
            {
                writer.WriteStartElement("NodeInfo" + i);
                tmpnode.hash = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]);
                writer.WriteElementString("Hash", "0x" + (tmpnode.hash).ToString("X"));
                pos            += 4;                                                                     //0x?4
                tmpnode.unknown = inFile[pos];                                                           //unknown, always 0x01? (not used in this case)
                writer.WriteElementString("Unknown", "0x" + (tmpnode.unknown).ToString("X"));
                pos           += 1;                                                                      //0x?5
                tmpnode.offset = Makeu32(0, inFile[pos], inFile[pos + 1], inFile[pos + 2]);              //Node SFNT filename offset divided by 4
                writer.WriteElementString("FileNameOffset", "0x" + ((tmpnode.offset * 4) + hdr + hdr2 + (nodeCount * 0x10) + 8).ToString("X"));
                pos          += 3;                                                                       //0x?8
                tmpnode.start = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]); //Start Data offset position
                writer.WriteElementString("DataStartOffset", "0x" + (tmpnode.start + dataOffset).ToString("X"));
                pos        += 4;                                                                         //0x?C
                tmpnode.end = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]);   //End Data offset position
                writer.WriteElementString("DataEndOffset", "0x" + (tmpnode.end + dataOffset).ToString("X"));
                pos     += 4;                                                                            //0x?0
                nodes[i] = tmpnode;                                                                      //Store node data into array
                writer.WriteEndElement();                                                                //</NodeInfo>
            }
            writer.WriteEndElement();                                                                    //</SFAT>

            writer.WriteStartElement("SFNT");
            if (inFile[pos] != 'S' || inFile[pos + 1] != 'F' || inFile[pos + 2] != 'N' || inFile[pos + 3] != 'T')
            {
                return(false);
            }
            pos += 4;                                            //0x?4
            ushort hdr3 = Makeu16(inFile[pos], inFile[pos + 1]); //SFNT Header length

            writer.WriteElementString("HeaderLength", hdr3.ToString("X"));
            pos += 2;                                            //0x?6
            ushort unk2 = Makeu16(inFile[pos], inFile[pos + 1]); //unknown, always 0x00?

            writer.WriteElementString("Unknown", unk2.ToString("X"));
            pos += 2;                 //0x?8
            writer.WriteEndElement(); //</SFNT>

            string[] fileNames = new string[nodeCount];
            string   tempName;

            for (int i = 0; i < nodeCount; i++) //Get file names for each node
            {
                tempName = "";                  //reset for each file
                while (inFile[pos] != 0)
                {
                    tempName = tempName + ((char)inFile[pos]).ToString(); //Build temp string for each letter
                    pos     += 1;
                }
                while (inFile[pos] == 0) //ignore every 0 byte, because why bother calculating the SFNT header offset anyway?
                {
                    pos += 1;
                }
                fileNames[i] = tempName; //Take built string and store it in the array
                writer.WriteElementString("NodeFile" + i, tempName);
            }


            for (int i = 0; i < nodeCount; i++) //Write files based from node information
            {
                writer.WriteStartElement("NodeHexData" + i);
                writer.WriteBinHex(inFile, (int)(nodes[i].start + dataOffset), (int)(nodes[i].end - nodes[i].start));
                writer.WriteEndElement(); //</NodeData>
            }


            writer.WriteEndElement(); //</PACKfile>
            writer.Close();
            GC.Collect();
            return(true);
        } //--------------------------------------------------------------------------------------------------------------------------------------------
Exemplo n.º 2
0
        public static bool Extract(byte[] inFile, string outDir, bool autoDecode, bool nodeDecode, string inFileName)
        {
            //SARC header 0x00 - 0x13
            if (("" + ((char)inFile[0]) + ((char)inFile[1]) + ((char)inFile[2]) + ((char)inFile[3])) != "SARC")
            {
                if (inFile[0] == 'Y' && inFile[1] == 'a' && inFile[2] == 'z' && inFile[3] == '0')
                {
                    if (autoDecode)
                    {
                        string outFile = Yaz0.DecodeOutputFileRename(inFileName);
                        Yaz0.Decode(inFileName, outFile);
                        return(Extract(outFile, outDir, autoDecode)); //recursively run the code again
                    }
                    else
                    {
                        lerror = "Yaz0 file encoded, please decode it first";
                        return(false);
                    }
                }
                else
                {
                    lerror = "Not a SARC archive! Missing SARC header at 0x00" + "\n" + "( Your file header is: " + ((char)inFile[0]) + ((char)inFile[1]) + ((char)inFile[2]) + ((char)inFile[3]) + " )";
                    return(false);
                }
            }
            int    pos = 4;                                     //0x04
            ushort hdr = Makeu16(inFile[pos], inFile[pos + 1]); //SARC Header length

            pos += 2;                                           //0x06
            ushort bom = Makeu16(inFile[pos], inFile[pos + 1]); //Byte Order Mark

            if (bom != 65279)                                   //Check 0x06 for Byte Order Mark (if not 0xFEFF)
            {
                if (bom == 65518)
                {
                    lerror = "Unable to support Little Endian! (Byte Order Mark 0x06)";
                }
                else
                {
                    lerror = "Unknown SARC header (Byte Order Mark 0x06)";
                }
                return(false);
            }
            pos += 2; //0x08
            uint fileSize = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]);

            pos += 4;                                                                                  //0x0C
            uint dataOffset = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]); //Data offset start position

            pos += 4;                                                                                  //0x10
            uint unknown = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]);    //unknown, always 0x01?

            pos += 4;                                                                                  //0x14

            //SFAT header 0x14 - 0x1F
            if (inFile[pos] != 'S' || inFile[pos + 1] != 'F' || inFile[pos + 2] != 'A' || inFile[pos + 3] != 'T')
            {
                lerror = "Unknown file table! (Missing SFAT header at 0x14)";
                return(false);
            }
            pos += 4;                                                                             //0x18
            ushort hdr2 = Makeu16(inFile[pos], inFile[pos + 1]);                                  //SFAT Header length

            pos += 2;                                                                             //0x1A
            ushort nodeCount = Makeu16(inFile[pos], inFile[pos + 1]);                             //Node Cluster count

            pos += 2;                                                                             //0x1C
            uint hashr = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]); //Hash multiplier, always 0x65

            pos += 4;                                                                             //0x20

            SarcNode[] nodes   = new SarcNode[nodeCount];
            SarcNode   tmpnode = new SarcNode();

            for (int i = 0; i < nodeCount; i++) //Node cluster
            {
                tmpnode.hash    = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]);
                pos            += 4;                                                                       //0x?4
                tmpnode.unknown = inFile[pos];                                                             //unknown, always 0x01? (not used in this case)
                pos            += 1;                                                                       //0x?5
                tmpnode.offset  = Makeu32(0, inFile[pos], inFile[pos + 1], inFile[pos + 2]);               //Node SFNT filename offset divided by 4 (not used)
                pos            += 3;                                                                       //0x?8
                tmpnode.start   = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]); //Start Data offset position
                pos            += 4;                                                                       //0x?C
                tmpnode.end     = Makeu32(inFile[pos], inFile[pos + 1], inFile[pos + 2], inFile[pos + 3]); //End Data offset position
                pos            += 4;                                                                       //0x?0
                nodes[i]        = tmpnode;                                                                 //Store node data into array
            }

            if (inFile[pos] != 'S' || inFile[pos + 1] != 'F' || inFile[pos + 2] != 'N' || inFile[pos + 3] != 'T')
            {
                string posOffset = "0x" + pos.ToString("X");
                lerror = "Unknown file name table! (Missing SFNT header at " + posOffset + ")";
                return(false);
            }
            pos += 4;                                            //0x?4
            ushort hdr3 = Makeu16(inFile[pos], inFile[pos + 1]); //SFNT Header length, always 0x08

            pos += 2;                                            //0x?6
            ushort unk2 = Makeu16(inFile[pos], inFile[pos + 1]); //unknown, always 0x00?

            pos += 2;                                            //0x?8

            string[] fileNames = new string[nodeCount];
            string   tempName;

            for (int i = 0; i < nodeCount; i++) //Get file names for each node
            {
                tempName = "";                  //reset for each file
                while (inFile[pos] != 0)
                {
                    tempName = tempName + ((char)inFile[pos]).ToString(); //Build temp string for each letter
                    pos     += 1;
                }
                while (inFile[pos] == 0) //ignore every 0 byte, because why bother calculating the SFNT header offset anyway?
                {
                    pos += 1;
                }
                fileNames[i] = tempName; //Take built string and store it in the array
            }

            if (!System.IO.Directory.Exists(outDir))
            {
                System.IO.Directory.CreateDirectory(outDir);                                      //folder creation
            }
            System.IO.StreamWriter stream;

            for (int i = 0; i < nodeCount; i++) //Write files based from node information
            {
                MakeDirExist(System.IO.Path.GetDirectoryName(outDir + "/" + fileNames[i]));
                stream = new System.IO.StreamWriter(outDir + "/" + fileNames[i]);
                stream.BaseStream.Write(inFile, (int)(nodes[i].start + dataOffset), (int)(nodes[i].end - nodes[i].start)); //Write
                stream.Close();
                stream.Dispose();
                if (nodeDecode)
                {
                    Yaz0.Decode(outDir + "/" + fileNames[i], Yaz0.DecodeOutputFileRename(outDir + "/" + fileNames[i]));
                }
            }
            GC.Collect();
            return(true);
        } //--------------------------------------------------------------------------------------------------------------------------------------------