Ejemplo n.º 1
0
        internal static bool BuildHFS0(string inDir, string outFile, SHA256 sha)
        {
            Console.WriteLine("Building {0} from folder {1}...", outFile, inDir);


            hfs0_header header = new hfs0_header();

            header.Magic = 0x30534648; // HFS0

            List <hfs0_file_entry> fileEntries = new List <hfs0_file_entry>();
            List <string>          stringTable = new List <string>();

            char[]       objPath = new char[256];
            FileStream   fs;
            BinaryWriter bw;

            // Opening output file
            try
            {
                fs = new FileStream(outFile, FileMode.Create, FileAccess.Write);
                bw = new BinaryWriter(fs);
            }
            catch (Exception ex)
            {
                Console.WriteLine("[ERR] Cannot create {0}.\n{1}", outFile, ex.Message);
                return(false);
            }

            // Opening input directory
            if (!Directory.Exists(inDir))
            {
                Console.WriteLine("[ERR] Input folder {0} does not exist.", inDir);
                return(false);
            }

            List <string> inputFiles = new List <string>();

            foreach (string file in Directory.GetFiles(inDir))
            {
                inputFiles.Add(Path.GetFileName(file));
            }


            // Handling root partitions for correct partition order
            if (inputFiles.Count >= 3 && inputFiles.Count <= 4 && inputFiles.Contains("secure") && inputFiles.Contains("normal") && inputFiles.Contains("update"))
            {
                if (inputFiles.Contains("logo"))
                {
                    Console.WriteLine("Treating {0} as CARD2 root hfs0", outFile);
                    inputFiles = new List <string>();
                    inputFiles.Add("update");
                    inputFiles.Add("normal");
                    inputFiles.Add("secure");
                    inputFiles.Add("logo");
                }
                else if (inputFiles.Count == 3)
                {
                    Console.WriteLine("Treating {0} as CARD1 root hfs0", outFile);
                    inputFiles = new List <string>();
                    inputFiles.Add("update");
                    inputFiles.Add("normal");
                    inputFiles.Add("secure");
                }
            }

            // Number of files in HFS0 archive
            header.NumberOfFiles = Convert.ToUInt32(inputFiles.Count);

            header.StringTableSize = 0;

            UInt64 fileEntry_relativeOffset = 0;

            // Building stringtable



            foreach (string file in inputFiles)
            {
                var absPath = Path.Combine(inDir, file);
                stringTable.Add(file);

                FileStream      inputFS       = new FileStream(absPath, FileMode.Open, FileAccess.Read);
                BinaryReader    inputFSReader = new BinaryReader(inputFS);
                hfs0_file_entry fileEntry     = new hfs0_file_entry();

                fileEntry.Offset = Convert.ToUInt64(fileEntry_relativeOffset);
                fileEntry.Size   = Convert.ToUInt64(inputFS.Length);

                UInt64 paddedSize = Convert.ToUInt64(Math.Ceiling((double)fileEntry.Size / (double)0x200) * 0x200);
                fileEntry_relativeOffset += paddedSize;



                if (fileEntry.Size > 0x200)
                {
                    fileEntry.HashedSize = 0x200;
                }
                else
                {
                    fileEntry.HashedSize = Convert.ToUInt32(fileEntry.Size);
                }

                byte[] dataToHash = new byte[fileEntry.HashedSize];
                inputFSReader.Read(dataToHash, 0, dataToHash.Length);

                inputFSReader.Close();
                inputFS.Close();

                fileEntry.StringTableOffset = header.StringTableSize;
                fileEntry.FileHash          = sha.ComputeHash(dataToHash);


                header.StringTableSize += Convert.ToUInt32(file.Length + 1);

                fileEntries.Add(fileEntry);
            }

            // Calculate padding fo alignment
            ulong bytesWrittenUntilNow       = HFS0_HEADER_LENGTH + (HFS0_ENTRY_LENGTH * header.NumberOfFiles) + header.StringTableSize;
            ulong bytesWrittenUntilNowPadded = Convert.ToUInt64(Math.Ceiling((double)bytesWrittenUntilNow / (double)0x200) * 0x200);
            ulong bytesWrittenUntilNowDif    = bytesWrittenUntilNowPadded - bytesWrittenUntilNow;

            header.StringTableSize += Convert.ToUInt32(bytesWrittenUntilNowDif);

            bw.Write(Utils.StructureToByteArray(header));
            foreach (hfs0_file_entry fileEntry in fileEntries)
            {
                bw.Write(Utils.StructureToByteArray(fileEntry));
            }
            foreach (string str in stringTable)
            {
                bw.Write(str.ToCharArray());
                bw.Write((byte)0x00);
            }
            // Fill padding
            for (ulong i = 0; i < bytesWrittenUntilNowDif; i++)
            {
                bw.Write((byte)0x0);
            }
            foreach (string file in inputFiles)
            {
                var        absPath = Path.Combine(inDir, file);
                FileStream stream  = new FileStream(absPath, FileMode.Open, FileAccess.Read);
                byte[]     buffer  = new Byte[1024 * 5];
                int        count   = 0;
                while ((count = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    bw.Write(buffer, 0, count);
                }

                ulong paddedLength = Convert.ToUInt64(Math.Ceiling((double)stream.Length / (double)0x200) * 0x200);

                ulong difference = paddedLength - Convert.ToUInt64(stream.Length);

                for (ulong i = 0; i < difference; i++)
                {
                    bw.Write((byte)0x0);
                }
                stream.Close();
            }
            bw.Close();
            fs.Close();



            Console.WriteLine("Operation successful");
            return(true);
        }