All pastes #389929 Raw Edit

Anonymous

public text v1 · immutable
·published 2007-03-11 01:32 UTC
rendered paste body
using 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);
            }
        }

    }
}