internal static void GetHFS0Managed(string inFile, ref hfs0_header header, ref List <hfs0_file_entry> entries, ref List <string> stringTable) { // TODO Check file integrity FileStream fs = new FileStream(inFile, FileMode.Open, FileAccess.Read); BinaryReader br = new BinaryReader(fs); header = Utils.FromBinaryReader <hfs0_header>(br); int offset = HFS0_HEADER_LENGTH; // Deserialize structs for (int i = 0; i < header.NumberOfFiles; i++) { fs.Seek(offset, SeekOrigin.Begin); hfs0_file_entry entry = Utils.FromBinaryReader <hfs0_file_entry>(br); entries.Add(entry); offset += HFS0_ENTRY_LENGTH; } // Parse string table for (int i = 0; i < header.NumberOfFiles; i++) { var entry = entries[i]; fs.Seek(offset + entry.StringTableOffset, SeekOrigin.Begin); byte b = 0x0; List <byte> stringBytes = new List <byte>(); while ((b = br.ReadByte()) > 0) { stringBytes.Add(b); } stringTable.Add(Encoding.ASCII.GetString(stringBytes.ToArray())); } br.Close(); fs.Close(); }
internal static bool BuildHFS0(string inDir, string outFile, string multiplier) //internal static bool BuildHFS0(string inDir, string outFile) { Console.WriteLine("Building {0} from folder {1}...", outFile, inDir); int vmultiplier = Int32.Parse(multiplier); int secuhash = 0x200 * vmultiplier; //Console.WriteLine("Round secuhash {0}", vmultiplier); 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); } int length_input = 0; int file_number = 0; List <string> inputFiles = new List <string>(); foreach (string file in Directory.GetFiles(inDir)) { inputFiles.Add(Path.GetFileName(file)); //length_input = length_input + 1 + Path.GetFileName(file).Length; //file_number = file_number + 1; } //Console.WriteLine("Length of string of files {0}", length_input); //Console.WriteLine("Number of files {0}", file_number); //float n_lines = 1+(4*file_number)+(length_input/16); //Console.WriteLine("Number of lines {0}", n_lines); //float mult = (n_lines/32); //int round_mult_up = (int)Math.Ceiling(mult); //Console.WriteLine("Multiplier {0}", mult); //Console.WriteLine("Round multiplier {0}", round_mult_up); //int secuhash2 = 0x200 * round_mult_up; // 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 (inputFiles.Count < 3) { fileEntry.HashedSize = 0x200; } else if (fileEntry.Size <= 0x200) { fileEntry.HashedSize = 0x200; } else if (fileEntry.Size <= 0x128800) { fileEntry.HashedSize = 0x200; } else if (header.NumberOfFiles < 5) { fileEntry.HashedSize = Convert.ToUInt32(secuhash); } else 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 = Program.SHA256.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); }