rendered paste bodyusing System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace NBHTool
{
public class NBH
{
/* some small byte helpers i used while reving it */
public class ByteHelpers
{
public static string ByteArrayToString(byte[] b_in)
{
string temp = "";
foreach (byte b in b_in)
temp += (char)b;
return temp;
}
public static string ByteArrayToHexString(byte[] b_in)
{
string temp = "";
foreach (byte b in b_in)
temp += string.Format("{0:x2} ", b);
return temp;
}
public static int LongIntToDecimal(byte[] b_in)
{
return b_in[0] + b_in[1] * 256 + b_in[2] * 65536 + b_in[3] * 16777216;
}
}
/* nbh rom class used to extract RNB rom from NBH rom
* to create a NBH rom from a RNB rom */
public class NBHRom
{
/* NBH file identifier */
const string s_nbhident = "R000FF\n";
string s_file;
public delegate void debugPrint(string function, params object[] arg);
debugPrint DebugPrint;
/* NBHBlock: reads and writes signed blocks */
public class NBHBlock
{
public byte[] b_blocksize;
public byte[] b_signaturesize;
public int b_flag;
public byte[] b_block;
public byte[] b_signature;
private FileStream fs_nbhstream;
public NBHBlock(FileStream fs_nbh)
{
fs_nbhstream = fs_nbh;
b_blocksize = new byte[4];
b_signaturesize = new byte[4];
b_flag = new byte();
}
public void ReadBlock()
{
/*
* block:
*
* [ 4byte blocksize ][4byte signaturesize][1byte flag][ x-bytes block][ x-bytes signature]
* the last block has flag == 2, and only contains a signature, probably for the whole file.
*/
fs_nbhstream.Read(b_blocksize, 0, 4);
fs_nbhstream.Read(b_signaturesize, 0, 4);
b_flag = fs_nbhstream.ReadByte();
int blocksize = ByteHelpers.LongIntToDecimal(b_blocksize);
int signaturesize = ByteHelpers.LongIntToDecimal(b_signaturesize);
/*
Console.WriteLine("blocksize: {0} signaturesize: {1} flag: {2}",
blocksize, signaturesize, b_flag);
*/
b_block = new byte[blocksize];
fs_nbhstream.Read(b_block, 0, blocksize);
b_signature = new byte[signaturesize];
fs_nbhstream.Read(b_signature, 0, signaturesize);
}
/* returns true if there is more to write, false if this was the last byte */
public bool WriteBlock(FileStream fs_source, string signature)
{
Int32 i_blocksize = 65536;
const Int32 i_sigsize = 128;
byte b_flag = 1;
if (fs_source.Length == fs_source.Position)
{
i_blocksize = 0;
b_flag = 2;
}
else if (fs_source.Length - fs_source.Position < i_blocksize)
{
i_blocksize = (Int32)(fs_source.Length - fs_source.Position);
}
/*
* block:
*
* [ 4byte blocksize ][4byte signaturesize][1byte flag][ x-bytes block][ x-bytes signature]
* the last block has flag == 2, and only contains a signature, probably for the whole file.
*/
byte[] b_block = new byte[i_blocksize];
int b_read = 0;
if ((b_read = fs_source.Read(b_block, 0, b_block.Length)) != i_blocksize)
throw new Exception("critical error reading from rnb file");
byte[] b_signature = new byte[i_sigsize];
Encoding.ASCII.GetBytes(signature, 0, signature.Length, b_signature, 0);
byte[] b_bytes = new byte[4]; /* used for block headers */
b_bytes = BitConverter.GetBytes(i_blocksize); /* blocksize */
fs_nbhstream.Write(b_bytes, 0, b_bytes.Length);
b_bytes = BitConverter.GetBytes(i_sigsize); /* signaturesize */
fs_nbhstream.Write(b_bytes, 0, b_bytes.Length);
fs_nbhstream.WriteByte(b_flag); /* flag */
fs_nbhstream.Write(b_block, 0, i_blocksize);
fs_nbhstream.Write(b_signature, 0, i_sigsize);
if (b_flag == 2)
return false;
return true;
}
}
public NBHRom(string s_filein, debugPrint debugprint)
{
s_file = s_filein;
DebugPrint = debugprint;
}
/* convert a rom to the rbh format, the rbh format is the nbh format without the signatures and the block headers */
public void ConvertToRBH(string s_fileout)
{
FileStream nbh = new FileStream(s_file, FileMode.Open, FileAccess.Read);
byte[] b_headercode = new byte[23]; /* according to xda-dev wiki 7bytes filetype+16 bytes garbage */
nbh.Read(b_headercode, 0, b_headercode.Length);
DebugPrint("headercode: {0}", ByteHelpers.ByteArrayToString(b_headercode));
FileStream rnbout = new FileStream(s_fileout, FileMode.Create, FileAccess.Write);
/* write the raw RNB format */
NBHBlock nbhblock = new NBHBlock(nbh);
do
{
nbhblock.ReadBlock();
rnbout.Write(nbhblock.b_block, 0, nbhblock.b_block.Length);
}
while (nbhblock.b_flag != 2); /* flag 2 = last block */
rnbout.Close();
nbh.Close();
}
/* convert a rbh rom to the nbh rom */
public void ConvertToNBH(string s_filein, string signature)
{
DebugPrint("Converting {0} into {1}", s_filein, s_file);
if (signature.Length > 128)
throw new Exception("signature exceeds limit");
FileStream fs_nbh = new FileStream(s_file, FileMode.Create, FileAccess.Write);
byte[] b_bytes = new byte[23];
Encoding.ASCII.GetBytes(s_nbhident, 0, s_nbhident.Length, b_bytes, 0);
fs_nbh.Write(b_bytes, 0, b_bytes.Length);
FileStream fs_in = new FileStream(s_filein, FileMode.Open, FileAccess.Read);
NBHBlock nbh_block = new NBHBlock(fs_nbh);
while (nbh_block.WriteBlock(fs_in, signature) == true)
{
#if false
if (fs_in.Position % 0xB3800 == 0)
Console.Write("\r\r\r\r\r\r\r\r\r\r\r\r\r\r{0:f2}MB of {1:f2}MB written", (double)fs_in.Position / 1024 / 1024, (double)fs_in.Length / 1024 / 1024);
#endif
}
#if false
Console.WriteLine("\r\r\r\r\r\r\r\r\r\r\r\r\r\r{0:f2}MB of {1:f2}MB written", (double)fs_in.Position / 1024 / 1024, (double)fs_in.Length / 1024 / 1024);
#else
DebugPrint("{0:f2}MB of {1:f2}MB written", (double)fs_in.Position / 1024 / 1024, (double)fs_in.Length / 1024 / 1024);
#endif
fs_nbh.Close();
fs_in.Close();
}
}
/* rnb rom class used to extract NB rom
* or to construct rnb rom from several NB roms
*/
public class RNBRom
{
public class NBRom
{
/* image types, also used for filenames */
public enum NBImageType
{
IPL = 0x100,
G3IPL = 0x101,
G4IPL = 0x102,
ATHENA_IPL = 0x103,
SPL = 0x200,
Radio = 0x300,
Windows = 0x400,
Diagnostics = 0x500,
PrimarySplash = 0x600,
SecondarySplash = 0x601,
Herm_ExtendedRom = 0x700,
SIRFBootLoader = 0x810,
ExtendedRom = 0x900
}
public NBImageType ImageType;
public long offset;
public long length;
/* only used when writing images */
public string s_fullpath;
public NBRom(int i_type)
{
ImageType = (NBImageType)i_type;
}
}
/* rnb header information
*
* 32bytes imagetype in UTF32 format
* 32bytes device type in ASCII format
* 128bytes
* 32 * 4 bytes nb image type
* 128bytes
* 32 * 4 bytes nb offset
* 128bytes
* 32 * 4 bytes nb length
*
* followed by raw nb images
*/
public string s_cid;
public string s_language;
public string s_version;
public string s_device;
public string s_imagetype;
private FileStream fs_rbh;
private List<NBRom> nbr_list;
public delegate void debugPrint(string function, params object[] arg);
debugPrint DebugPrint;
public RNBRom(debugPrint myprint)
{
DebugPrint = myprint;
nbr_list = new List<NBRom>();
}
public int RomCount()
{
if (nbr_list == null)
return 0;
return nbr_list.Count;
}
/* extraction */
public void LoadRom(string s_filename)
{
if (fs_rbh != null)
throw new IOException("please close first romhandle prior to opening another with the same object");
fs_rbh = new FileStream(s_filename, FileMode.Open, FileAccess.Read);
/* read rom type */
byte[] b_imagetype = new byte[32];
fs_rbh.Read(b_imagetype, 0, b_imagetype.Length);
s_imagetype = System.Text.Encoding.UTF32.GetString(b_imagetype);
DebugPrint("imagetype: {0}", s_imagetype);
/* read device type */
fs_rbh.Read(b_imagetype, 0, b_imagetype.Length);
s_device = System.Text.Encoding.ASCII.GetString(b_imagetype);
DebugPrint("devicetype: {0}", s_device);
/* read rom types */
byte[] b_romtype = new byte[4];
for (int i = 0; i < 128; i += 4)
{
fs_rbh.Read(b_romtype, 0, b_romtype.Length);
int i_romtype = ByteHelpers.LongIntToDecimal(b_romtype);
if (i_romtype != 0)
{
NBRom nbr_rom = new NBRom(i_romtype);
nbr_list.Add(nbr_rom);
DebugPrint("found rom: {0} (0x{1:x2})", nbr_rom.ImageType, (int)nbr_rom.ImageType);
}
}
DebugPrint("numer of roms in nbh: {0}", nbr_list.Count);
/* read rom offests */
byte[] b_romoffset = new byte[4];
for (int i = 0; i < 128; i += 4)
{
fs_rbh.Read(b_romoffset, 0, b_romoffset.Length);
int i_offset = ByteHelpers.LongIntToDecimal(b_romoffset);
int rom_no = i / 4;
if (i_offset != 0 && rom_no < nbr_list.Count)
{
nbr_list[rom_no].offset = i_offset;
DebugPrint("found offset: {0} (0x{1:x2})", nbr_list[rom_no].ImageType, (int)nbr_list[rom_no].offset);
}
}
/* read rom lengths */
byte[] b_romlength = new byte[4];
for (int i = 0; i < 128; i += 4)
{
fs_rbh.Read(b_romlength, 0, b_romlength.Length);
int i_length = ByteHelpers.LongIntToDecimal(b_romlength);
int rom_no = i / 4;
if (i_length != 0 && rom_no < nbr_list.Count)
{
nbr_list[rom_no].length = i_length;
DebugPrint("found length: {0} (0x{1:x2})", nbr_list[rom_no].ImageType, (int)nbr_list[rom_no].length);
}
}
}
public void CloseRom()
{
nbr_list = new List<NBRom>();
fs_rbh.Close();
fs_rbh = null;
}
public void ExtractNBH(string s_outdir)
{
if (fs_rbh == null)
throw new Exception("no filehandle to rbh rom");
if (nbr_list.Count == 0)
throw new Exception("please load the rom prior to extracting it");
if (s_outdir.EndsWith("\\") == false)
s_outdir += "\\";
for (int i = 0; i < nbr_list.Count; i++)
{
FileStream fs_out = new FileStream(s_outdir + nbr_list[i].ImageType + ".nb", FileMode.Create, FileAccess.Write);
DebugPrint("Creating: {0}\n", fs_out.Name);
fs_rbh.Seek(nbr_list[i].offset, SeekOrigin.Begin);
int peeksize = 65536;
for (long bytesleft = nbr_list[i].length; bytesleft >= 0; bytesleft -= peeksize)
{
byte[] bytes;
if (bytesleft < peeksize)
{
bytes = new byte[bytesleft];
fs_rbh.Read(bytes, 0, bytes.Length);
fs_out.Write(bytes, 0, bytes.Length);
break;
}
bytes = new byte[peeksize];
fs_rbh.Read(bytes, 0, bytes.Length);
fs_out.Write(bytes, 0, bytes.Length);
}
fs_out.Close();
}
}
/* creation */
private long GetTotalRomSize()
{
long size = 0;
foreach (NBRom nbr in nbr_list)
size += nbr.length;
return size;
}
public void AddRom(string s_fullpath, NBRom.NBImageType nbi_type)
{
NBRom nbr_add = new NBRom((int)nbi_type);
try
{
FileStream fs_rom = new FileStream(s_fullpath, FileMode.Open, FileAccess.Read);
nbr_add.length = fs_rom.Length;
nbr_add.offset = 0x200 + GetTotalRomSize();
fs_rom.Close();
}
catch (Exception e)
{
throw new Exception(string.Format("Couldn't open {0}: {1}", s_fullpath, e.Message));
}
nbr_add.s_fullpath = s_fullpath;
this.nbr_list.Add(nbr_add);
DebugPrint("added rom: {0} type: {1}", s_fullpath, nbi_type);
}
public void SetHeaderInfo(string cid, string language, string version, string device)
{
s_cid = cid;
s_language = language;
s_version = version;
s_device = device;
DebugPrint(this.ToString());
}
public void CreateRom(string s_outfile)
{
fs_rbh = new FileStream(s_outfile, FileMode.Create, FileAccess.Write);
DebugPrint("rom: {0}", s_outfile);
byte[] b_bytes = new byte[32];
string s_imagetype = "HTCIMAGE";
System.Text.UnicodeEncoding.UTF32.GetBytes(s_imagetype, 0, s_imagetype.Length, b_bytes, 0);
DebugPrint("writing imagetype: {0}", ByteHelpers.ByteArrayToHexString(b_bytes));
fs_rbh.Write(b_bytes, 0, 32);
b_bytes = new byte[32];
System.Text.Encoding.ASCII.GetBytes(this.s_device, 0, s_device.Length, b_bytes, 0);
DebugPrint("writing devicetype: {0}", ByteHelpers.ByteArrayToHexString(b_bytes));
fs_rbh.Write(b_bytes, 0, 32);
/* write rom types */
b_bytes = new byte[4];
for (int i = 0; i < 32; i++)
{
if (i >= this.nbr_list.Count)
{
b_bytes = new byte[4];
fs_rbh.Write(b_bytes, 0, 4);
continue;
}
Int32 l_type = (int)this.nbr_list[i].ImageType;
b_bytes = BitConverter.GetBytes(l_type);
fs_rbh.Write(b_bytes, 0, b_bytes.Length);
DebugPrint("writing rom type: {0} (0x{1:x2})", this.nbr_list[i].ImageType, ByteHelpers.ByteArrayToHexString(b_bytes));
}
/* write rom offsets */
b_bytes = new byte[4];
for (int i = 0; i < 32; i++)
{
if (i >= this.nbr_list.Count)
{
b_bytes = new byte[4];
fs_rbh.Write(b_bytes, 0, 4);
continue;
}
Int32 l_type = (int)this.nbr_list[i].offset;
b_bytes = BitConverter.GetBytes(l_type);
fs_rbh.Write(b_bytes, 0, b_bytes.Length);
DebugPrint("writing rom offset: {0} (0x{1:x2})", this.nbr_list[i].ImageType, ByteHelpers.ByteArrayToHexString(b_bytes));
}
/* write rom lengths */
b_bytes = new byte[4];
for (int i = 0; i < 32; i++)
{
if (i >= this.nbr_list.Count)
{
b_bytes = new byte[4];
fs_rbh.Write(b_bytes, 0, 4);
continue;
}
Int32 l_type = (int)this.nbr_list[i].length;
b_bytes = BitConverter.GetBytes(l_type);
fs_rbh.Write(b_bytes, 0, b_bytes.Length);
DebugPrint("writing rom length: {0} (0x{1:x2})", this.nbr_list[i].ImageType, ByteHelpers.ByteArrayToHexString(b_bytes));
}
/* write additional rom headers */
/* cid type */
b_bytes = new byte[32];
System.Text.Encoding.ASCII.GetBytes(this.s_cid, 0, this.s_cid.Length, b_bytes, 0);
DebugPrint("writing cid: {0}", ByteHelpers.ByteArrayToHexString(b_bytes));
fs_rbh.Write(b_bytes, 0, 32);
/* version */
b_bytes = new byte[16];
System.Text.Encoding.ASCII.GetBytes(this.s_version, 0, this.s_version.Length, b_bytes, 0);
DebugPrint("writing version: {0}", ByteHelpers.ByteArrayToHexString(b_bytes));
fs_rbh.Write(b_bytes, 0, 16);
/* language */
b_bytes = new byte[16];
System.Text.Encoding.ASCII.GetBytes(this.s_language, 0, this.s_language.Length, b_bytes, 0);
DebugPrint("writing language: {0}", ByteHelpers.ByteArrayToHexString(b_bytes));
fs_rbh.Write(b_bytes, 0, 16);
foreach (NBRom nbr in nbr_list)
{
int peeksize = 65536;
int i_bytesread = 0;
b_bytes = new byte[peeksize];
FileStream fs_nbr = new FileStream(nbr.s_fullpath, FileMode.Open, FileAccess.Read);
DebugPrint("Writing {0} into {1}", fs_nbr.Name, fs_rbh.Name);
while ((i_bytesread = fs_nbr.Read(b_bytes, 0, b_bytes.Length)) != 0)
{
fs_rbh.Write(b_bytes, 0, i_bytesread);
}
fs_nbr.Close();
}
fs_rbh.Close();
}
public override string ToString()
{
return string.Format("{0} rom: {1} {2} {3}", s_device, s_language, s_cid, s_version);
}
}
}
}