Пример #1
0
 public void AppendNode(InfoNode i, RootInfoNode super)
 {
     _AppendNode(i, super);
 }
Пример #2
0
 public void Write(RootInfoNode root, Stream sout)
 {
     throw new NotImplementedException();
 }
Пример #3
0
 public void AddRootNode(RootInfoNode i)
 {
     main.tree.Nodes.Add(i);
 }
Пример #4
0
        private void tree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            hbMain.Highlights.Clear();
            contextTreeDump.Enabled = false;
            if (e.Node.Level == 0)
            {
                if (!(e.Node is RootInfoNode))
                {
                    return;
                }

                RootInfoNode rin = (RootInfoNode)e.Node;
                if (!File.Exists(rin.FilePath))
                {
                    throw new FileNotFoundException();
                }

                hbMain.ReadFile(rin.FilePath);
                fileloaded = rin.FilePath;

                double h = rnd.NextDouble();
                int    r, g, b;
                foreach (InfoNode inode in e.Node.Nodes)
                {
                    HSV.ToRGB(h * 360, 1.00d, 1d, out r, out g, out b);
                    hbMain.Highlights.Add(new HexBoxLib.Highlight((int)inode.DataStart, (int)inode.DataEnd, Color.FromArgb(r, g, b)));

                    //do
                    //{
                    h += Root.GOLDEN_RATIO;
                    h %= 1;
                    //} while (h > 0.15 && h < 0.525);
                }

                hbMain.Invalidate();

                Bridge.ShowInfo(rin.IType, rin.Info);
            }
            else
            {
                if (!(e.Node is InfoNode))
                {
                    return;
                }
                InfoNode inode = (InfoNode)e.Node;

                if (inode.IType == InfoType.Binary || inode.IType == InfoType.BinaryMainFocus)
                {
                    contextTreeDump.Enabled = true;
                }

                /* Get root node */
                TreeNode root   = this.tree.SelectedNode;
                TreeNode uncomp = null;
                while (root.Level > 0)
                {
                    root = root.Parent;
                    if (uncomp == null && root is InfoNode && ((InfoNode)root).IType == InfoType.BinaryMainFocus)
                    {
                        uncomp = root;
                    }
                }

                if (uncomp != null)
                {
                    this.hbMain.ReadBytes((byte[])((InfoNode)uncomp).Info);
                }
                else
                {
                    this.hbMain.ReadFile(((RootInfoNode)root).FilePath);
                }
                //TreeNode root = e.Node;
                //do
                //{
                //    root = root.Parent;
                //} while (root.Level > 0);

                //if (!(root is RootInfoNode)) return;

                //RootInfoNode rin = (RootInfoNode)root;
                //if (fileloaded != rin.FilePath)
                //{
                //    if (!File.Exists(rin.FilePath)) throw new FileNotFoundException();

                //    hbMain.ReadFile(rin.FilePath);
                //    fileloaded = rin.FilePath;
                //}

                Color ghost = Color.FromArgb(0xDD, 0xDD, 0xDD);
                foreach (InfoNode irn in inode.Parent.Nodes)
                {
                    hbMain.Highlights.Add(new HexBoxLib.Highlight((int)irn.DataStart, (int)irn.DataEnd, ghost));
                }

                hbMain.Highlights.Add(new HexBoxLib.Highlight((int)inode.DataStart, (int)inode.DataEnd, inode.HighlightColor));
                hbMain.ScrollTo((int)(inode.DataStart >> 4));
                hbMain.Invalidate();

                Bridge.ShowInfo(inode.IType, inode.Info);
            }
        }
Пример #5
0
        const int JFIF_BUFFER_SIZE = 1024 * 512; //512KB
        public bool Read(RootInfoNode root, Stream stream)
        {
            root.Info  = root.FilePath;
            root.IType = InfoType.ImageFile;

            byte[] buffer = new byte[JFIF_BUFFER_SIZE];
            byte[] tbb = new byte[2];
            int    toread = 0;
            int    read, i;
            int    pos = 0;
            bool   markerpending = false, EOI = false;
            byte   lastmarker    = 0x00;
            int    lastmarkerend = 0;
            int    skip          = 0;

            while (!EOI && (read = stream.Read(buffer, 0, JFIF_BUFFER_SIZE)) > 0)
            {
                if (skip >= JFIF_BUFFER_SIZE)
                {
                    skip -= JFIF_BUFFER_SIZE;
                    continue;
                }

                for (i = skip, skip = 0, pos = (int)stream.Position - read; !EOI && i < read; i++, pos++)
                {
                    if (toread > 0)
                    {
                        tbb[--toread] = buffer[i];
                        //toread--;

                        if (toread > 0)
                        {
                            continue;
                        }

                        int length = (int)BitConverter.ToUInt16(tbb, 0);
                        if (length < 1)
                        {
                            continue;
                        }
                        skip = length - 2;
                        i   += skip + 1;
                        pos += skip + 1;

                        if (i >= read)
                        {
                            break;            //Should have seen that coming
                        }
                        if ((lastmarker & 0xF0) == 0xE0)
                        {
                            Bridge.AppendNode(new InfoNode("APP" + (lastmarker & 0x0F), "block", InfoType.Generic, new GenericInfo("APP" + (lastmarker & 0x0F), "TODO."), ((lastmarker & 0x0F) < 2 ? DataType.Critical : DataType.Metadata), lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if (lastmarker == 0xDA)
                        {
                            Bridge.AppendNode(new InfoNode("SOS", "block", InfoType.Generic, new GenericInfo("SOS", "Marks the start of image data stream."), DataType.Critical, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if (lastmarker == 0xDB)
                        {
                            Bridge.AppendNode(new InfoNode("DQT", "block", InfoType.Generic, new GenericInfo("DQT", "Quantization table definition."), DataType.Critical, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if (lastmarker == 0xDC)
                        {
                            Bridge.AppendNode(new InfoNode("DNL", "block", InfoType.Generic, new GenericInfo("DNL", "Defines number of lines."), DataType.Critical, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if (lastmarker == 0xDD)
                        {
                            Bridge.AppendNode(new InfoNode("DRI", "block", InfoType.Generic, new GenericInfo("DRI", "Restart interoperability definition."), DataType.Critical, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if (lastmarker == 0xDE)
                        {
                            Bridge.AppendNode(new InfoNode("DHP", "block", InfoType.Generic, new GenericInfo("DHP", "Hierarchical progression definition."), DataType.Critical, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if (lastmarker == 0xDF)
                        {
                            Bridge.AppendNode(new InfoNode("EXP", "block", InfoType.Generic, new GenericInfo("EXP", "Expand reference components."), DataType.Critical, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if (lastmarker == 0xC0)
                        {
                            Bridge.AppendNode(new InfoNode("SOF", "block", InfoType.Generic, new GenericInfo("SOF", "Parameter data relating to frame."), DataType.Critical, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if (lastmarker == 0xC4)
                        {
                            Bridge.AppendNode(new InfoNode("DHT", "block", InfoType.Generic, new GenericInfo("DHT", "Huffman table definition."), DataType.Critical, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if (lastmarker == 0xCC)
                        {
                            Bridge.AppendNode(new InfoNode("DAC", "block", InfoType.Generic, new GenericInfo("DAC", "Arithmetic coding condition(s) definition."), DataType.Critical, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if ((lastmarker & 0xF0) == 0xC0)
                        {
                            Bridge.AppendNode(new InfoNode("SOF" + (lastmarker & 0x0F), "block", InfoType.Generic, new GenericInfo("SOF" + (lastmarker & 0x0F), "Start Of Frame; Parameter data relating to frame."), DataType.Critical, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                        else if (lastmarker == 0xFE)
                        {
                            Bridge.AppendNode(new InfoNode("COM", "block", InfoType.Generic, new GenericInfo("COM", "Comment definition."), DataType.Ancillary, lastmarkerend - 1, lastmarkerend += length), root);
                        }
                    }
                    else if (markerpending)
                    {
                        if (lastmarkerend > 0 && buffer[i] != 0x00 && buffer[i] != 0xFF && (buffer[i] < 0xD0 || buffer[i] > 0xD7) && lastmarkerend != i - 2)
                        {
                            if (lastmarker == 0xDA)
                            {
                                Bridge.AppendNode(new InfoNode("Image data", "block-purple", InfoType.Generic, new GenericInfo("Image Data", "Contains the primary image data."), DataType.Critical, lastmarkerend + 1, pos - 2), root);
                            }
                            else
                            {
                                Bridge.AppendNode(new InfoNode("Unmarked data", "block-orange", InfoType.Generic, new GenericInfo("Unmarked Data", "This data could not be accounted for, typically useless."), DataType.Useless, lastmarkerend + 1, pos - 2), root);
                            }
                        }

                        if (buffer[i] == 0xD8)
                        {
                            Bridge.AppendNode(new InfoNode("SOI", "block", InfoType.Generic, new GenericInfo("SOI", "Start Of Image marker."), DataType.Critical, pos - 1, pos), root);
                        }
                        else if (buffer[i] == 0x01)
                        {
                            Bridge.AppendNode(new InfoNode("TEM", "block", InfoType.Generic, new GenericInfo("TEM", "Temporary marker."), DataType.Useless, pos - 1, pos), root);
                        }
                        else if (buffer[i] >= 0x02 && buffer[i] <= 0xBF)
                        {
                            Bridge.AppendNode(new InfoNode("RES", "block", InfoType.Generic, new GenericInfo("RES", "Reserved marker."), DataType.Useless, pos - 1, pos), root);
                        }
                        else if (buffer[i] == 0xD9)
                        {
                            Bridge.AppendNode(new InfoNode("EOI", "block", InfoType.Generic, new GenericInfo("EOI", "End Of Image marker."), DataType.Critical, pos - 1, pos), root);
                            EOI = true;
                        }
                        else if (
                            (buffer[i] & 0xF0) == 0xE0 ||
                            (buffer[i] & 0xF0) == 0xC0 ||
                            buffer[i] == 0xDA ||
                            buffer[i] == 0xDB ||
                            buffer[i] == 0xDC ||
                            buffer[i] == 0xDD ||
                            buffer[i] == 0xDE ||
                            buffer[i] == 0xDF ||
                            buffer[i] == 0xFE)
                        {
                            toread = 2;
                        }
                        else if (buffer[i] == 0x00 || buffer[i] == 0xFF || (buffer[i] >= 0xD0 && buffer[i] <= 0xD7))
                        {
                            markerpending = false;
                            continue;
                        }
                        else
                        {
                            Bridge.AppendNode(new InfoNode("UNK", InfoType.Generic, new GenericInfo("UNK", "Unknown JPEG marker, not defined in standard."), DataType.Useless, pos - 1, pos), root);
                        }


                        lastmarker    = buffer[i];
                        lastmarkerend = pos;

                        markerpending = false;
                        continue;
                    }

                    if (buffer[i] != 0xFF)
                    {
                        continue;
                    }
                    else
                    {
                        markerpending = true;
                    }
                }
            }

            if (!EOI)
            {
                return(false);
            }

            if (pos < stream.Length)
            {
                Bridge.AppendNode(
                    new InfoNode("EOF", "block-orange",
                                 InfoType.Generic,
                                 new GenericInfo("EOF", "End Of File data; serves no function or purpose."),
                                 DataType.Useless,
                                 pos, stream.Length - 1),
                    root);
            }

            foreach (InfoNode n in root.Nodes)
            {
                if (n.DataStart + 1 == n.DataEnd || n.ImageKey != "block")
                {
                    continue;
                }
                Bridge.AppendNode(new InfoNode("Marker ID", "binary", InfoType.None, null, DataType.Critical, n.DataStart, n.DataStart + 1), n);
                Bridge.AppendNode(new InfoNode("Data length", "int", InfoType.None, null, DataType.Critical, n.DataStart + 2, n.DataStart + 3), n);
                if (n.DataStart + 3 == n.DataEnd)
                {
                    continue;
                }

                int  datalength = (int)((n.DataEnd + 1) - (n.DataStart + 4));
                long datastart  = n.DataStart + 4;

                byte[] datab;

                if (n.Text.StartsWith("APP"))
                {
                    datab = ReadData(stream, n.DataStart + 4, datalength);

                    int nullpos = 0;
                    for (; nullpos < datab.Length; nullpos++)
                    {
                        if (datab[nullpos] == 0x00)
                        {
                            break;
                        }
                    }

                    if (nullpos < datab.Length - 1)
                    {
                        string appname = Encoding.ASCII.GetString(datab, 0, nullpos);
                        Bridge.AppendNode(new InfoNode("Application name", "str", InfoType.Generic, new GenericInfo("Application Name", appname), DataType.Critical, datastart, datastart + nullpos), n);

                        int dbegin  = (int)(datastart + nullpos + 1);
                        int pointer = nullpos + 1;
                        if (appname == "Exif" && datalength >= 14)
                        {
                            if (datab[pointer++] != 0x00)
                            {
                                Bridge.AppendNode(new InfoNode("Error", "error", InfoType.Generic, new GenericInfo("Error", "Incorrect EXIF identifier."), DataType.Error, dbegin, n.DataEnd), n);
                                continue;
                            }

                            char EndianA = (char)datab[pointer++];
                            char EndianB = (char)datab[pointer++];

                            if (EndianA != EndianB || (EndianA != 'I' && EndianA != 'M'))
                            {
                                Bridge.AppendNode(new InfoNode("Error", "error", InfoType.Generic, new GenericInfo("Error", "Could not parse byte order."), DataType.Error, dbegin, n.DataEnd), n);
                                continue;
                            }

                            bool bigendian = EndianA == 'M';

                            int the_answer_to_life_the_universe_and_everything = (bigendian ? datab[pointer++] << 0x08 | datab[pointer++] : datab[pointer++] | datab[pointer++] << 0x08);

                            if (the_answer_to_life_the_universe_and_everything != 42) //Should be impossible...
                            {
                                Bridge.AppendNode(new InfoNode("Error", "error", InfoType.Generic, new GenericInfo("Error", "Incorrect TIFF magic number (should be 42)."), DataType.Error, dbegin, n.DataEnd), n);
                                continue;
                            }

                            int zoffset = (bigendian ?
                                           datab[pointer++] << 0x18 | datab[pointer++] << 0x10 | datab[pointer++] << 0x08 | datab[pointer++] :
                                           datab[pointer++] | datab[pointer++] << 0x08 | datab[pointer++] << 0x10 | datab[pointer++] << 0x18);

                            InfoNode tiff = new InfoNode("TIFF header", "info", InfoType.None, null, DataType.Critical, dbegin + 1, dbegin + 8);
                            Bridge.AppendNode(tiff, n);

                            Bridge.AppendNode(new InfoNode("Byte order", "str", InfoType.None, null, DataType.Critical, dbegin + 1, dbegin + 2), tiff);
                            Bridge.AppendNode(new InfoNode("TIFF magic number", "int", InfoType.None, null, DataType.Critical, dbegin + 3, dbegin + 4), tiff);
                            Bridge.AppendNode(new InfoNode("Offset to 0th IFD", "int", InfoType.None, null, DataType.Critical, dbegin + 5, dbegin + 8), tiff);
                        }
                        else
                        {
                            Bridge.AppendNode(new InfoNode("Application data", "binary", InfoType.None, null, DataType.Critical, dbegin, n.DataEnd), n);
                        }

                        continue;
                    }
                }

                Bridge.AppendNode(new InfoNode("Marker data", "binary", InfoType.None, null, DataType.Critical, n.DataStart + 4, n.DataEnd), n);
            }

            return(true);
        }
Пример #6
0
        public bool Read(RootInfoNode root, Stream stream)
        {
            InfoNode header = null;

            Bridge.AppendNode(
                (header = new InfoNode("CMMM Header", "info",
                                       InfoType.Generic,
                                       new GenericInfo("CMMM Header", "Contains information about the file type version and cache type."),
                                       DataType.Critical,
                                       0x00, 0x17)),
                root);

            stream.Seek(0x04, SeekOrigin.Begin);

            byte[] buffer = new byte[4];
            stream.Read(buffer, 0, 4);
            int version = BitConverter.ToInt32(buffer, 0);

            stream.Read(buffer, 0, 4);
            int ctype = BitConverter.ToInt32(buffer, 0);

            stream.Seek(0x0C, SeekOrigin.Current); //Skip three 32bit integers

            Bridge.AppendNode(new InfoNode("Magic number", "str", InfoType.Generic, new GenericInfo("Magic Number", "Contains only the string 'CMMM'."), DataType.Critical, 0x00, 0x03), header);
            const char VSC = '*';

            Bridge.AppendNode(new InfoNode("Version", "int", InfoType.Generic, new GenericInfo("Version", String.Format("Identifies the file format version.\r\n\r\n{0} 0x15 = Windows 7\r\n{1} 0x1F = Windows 8.1\r\n{2} 0x20 = Windows 10", (version == 0x15 ? VSC : ' '), (version == 0x1F ? VSC : ' '), (version == 0x20 ? VSC : ' '))), DataType.Critical, 0x04, 0x07), header);

            Bridge.AppendNode(new InfoNode("Cache type", "int", InfoType.None, null, DataType.Critical, 0x08, 0x0B), header);
            Bridge.AppendNode(new InfoNode("Unknown int 1", "unknown", InfoType.Generic, new GenericInfo("Unknown 32-bit Integer 1", "There's a lot of speculation over this integer being the header size or being a pointer to the first entry (available or not), I've never seen it anything other than zero"), DataType.Critical, 0x0C, 0x0F), header);
            Bridge.AppendNode(new InfoNode("First available entry", "intptr", InfoType.None, null, DataType.Critical, 0x10, 0x13), header);
            Bridge.AppendNode(new InfoNode("Unknown int 2", "unknown", InfoType.None, null, DataType.Critical, 0x14, 0x17), header);

            int entrylen, stringlen, paddinglen, datalen, seek, databegin, dataend, entrybegin;

            byte[] cbuffer = new byte[0x0C];
            long   tempseek;

            while (stream.Read(buffer, 0, 4) == 4 && CompareBytes(buffer, CMMM))
            {
                entrybegin = (int)(stream.Position - 4);
                if (stream.Read(buffer, 0, 4) != 4)
                {
                    throw new Exception("Data ended earlier than expected.");
                }
                entrylen = BitConverter.ToInt32(buffer, 0);

                tempseek = stream.Position;
                if (stream.Seek(0x08, SeekOrigin.Current) != tempseek + 0x08) //Skip CRC64 hash
                {
                    throw new Exception("Data ended earlier than expected.");
                }

                if (version == 0x14)
                {
                    tempseek = stream.Position;
                    if (stream.Seek(0x08, SeekOrigin.Current) != tempseek + 0x08) //Skip extension
                    {
                        throw new Exception("Data ended earlier than expected.");
                    }
                }

                if (stream.Read(cbuffer, 0, 0x0C) != 0x0C)
                {
                    throw new Exception("Data ended earlier than expected.");
                }
                stringlen  = BitConverter.ToInt32(cbuffer, 0x00);
                paddinglen = BitConverter.ToInt32(cbuffer, 0x04);
                datalen    = BitConverter.ToInt32(cbuffer, 0x08);

                tempseek = stream.Position;
                seek     = (version >= 0x1F ? 0x0C : 0x04) + 0x10;
                if (stream.Seek(seek, SeekOrigin.Current) != tempseek + seek) //Skip unknown integers and two CRC64 checksums
                {
                    throw new Exception("Data ended earlier than expected.");
                }

                byte[] uidb = new byte[stringlen];
                if (stream.Read(uidb, 0, stringlen) != stringlen)
                {
                    throw new Exception("Data ended earlier than expected.");
                }
                string uniqueid = Encoding.Unicode.GetString(uidb);

                if (uniqueid.Length == 0 || uniqueid[0] == '\0')
                {
                    uniqueid = "NULL";
                }

                tempseek = stream.Position;
                if (stream.Seek(paddinglen, SeekOrigin.Current) != tempseek + paddinglen) //Skip padding
                {
                    throw new Exception("Data ended earlier than expected.");
                }

                tempseek  = stream.Position;
                seek      = (entrybegin + entrylen) - (int)stream.Position;
                databegin = (int)stream.Position;
                if (stream.Seek(seek, SeekOrigin.Current) != tempseek + seek) //Skip data
                {
                    throw new Exception("Data ended earlier than expected.");
                }
                dataend = (int)stream.Position - 1;

                if (datalen > 0)
                {
                    Bridge.AppendNode(
                        new InfoNode(uniqueid, "block",
                                     InfoType.Delegate,
                                     new object[] {
                        (Action <object[]>) delegate(object[] data) {
                            string path = ((string)data[2]);
                            int begin   = ((int)data[0]);
                            int len     = ((int)data[1]);

                            byte[] imgdata = new byte[len];
                            using (FileStream nfs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
                            {
                                nfs.Seek(begin, SeekOrigin.Begin);
                                nfs.Read(imgdata, 0, len);
                            }

                            Bridge.ShowInfo(InfoType.ImageStream, new MemoryStream(imgdata, false));
                        },
                        new object[3] {
                            databegin, datalen, root.FilePath
                        }
                    },
                                     DataType.Ancillary,
                                     entrybegin, dataend),
                        root);
                }
                else
                {
                    Bridge.AppendNode(
                        new InfoNode(uniqueid, "block-orange",
                                     InfoType.None,
                                     null,
                                     DataType.Ancillary,
                                     entrybegin, dataend),
                        root);
                }
            }

            if (stream.Position < stream.Length)
            {
                Bridge.AppendNode(
                    new InfoNode("EOF", "block-orange",
                                 InfoType.Generic,
                                 new GenericInfo("EOF", "End Of File data; serves no function or purpose."),
                                 DataType.Useless,
                                 stream.Position - 4, stream.Length - 1),
                    root);
            }

            return(true);
        }
Пример #7
0
        private void LoadFile(string file)
        {
            List <int> valid = new List <int>();

            byte[] magicbuffer = new byte[0x10];
            int    read        = 0;

            FileStream fs    = null;
            string     fname = Path.GetFileName(file);

            try
            {
                try
                {
                    fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
                }
                catch (IOException ex)
                {
                    if (!ex.Message.Contains("used by another process"))
                    {
                        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }

                    if (MessageBox.Show("The file could not be write-locked, would you like to make a temporary copy and read that instead?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != System.Windows.Forms.DialogResult.Yes)
                    {
                        return;
                    }

                    byte[]        hash = NayukiSHA256.Calculate(Encoding.ASCII.GetBytes(file));
                    StringBuilder sb   = new StringBuilder(hash.Length * 2);
                    foreach (byte b in hash)
                    {
                        sb.Append(b.ToString("X2"));
                    }

                    string newf = Root.LocalAppData + sb.ToString() + ".temp";
                    File.Copy(file, newf);
                    file = newf;

                    fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
                }

                if (fs.Length < 1)
                {
                    return;
                }
                if ((read = fs.Read(magicbuffer, 0, magicbuffer.Length)) < 1)
                {
                    return;
                }

                for (int i = 0; i < Root.ModuleAttribs.Count; i++)
                {
                    if (fs.Length < Root.ModuleAttribs[i].MinFileSize)
                    {
                        continue;
                    }

                    if (Root.ModuleAttribs[i].Magic != null && Root.ModuleAttribs[i].Magic.Length > 0 && Root.ModuleAttribs[i].Magic.Length <= magicbuffer.Length)
                    {
                        int j = 0;
                        for (; j < Root.ModuleAttribs[i].Magic.Length; j++)
                        {
                            if (Root.ModuleAttribs[i].Magic[j] != magicbuffer[j])
                            {
                                break;
                            }
                        }

                        if (j < Root.ModuleAttribs[i].Magic.Length)
                        {
                            continue;
                        }
                    }

                    fs.Seek(0, SeekOrigin.Begin);
                    if (Root.Modules[i].CanRead(fs))
                    {
                        valid.Add(i);
                    }
                }

                this.Invoke((Action) delegate
                {
                    if (valid.Count < 1)
                    {
                        MessageBox.Show("No modules that were able to read the specified file could be found.", "Unsupported Format", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                    else if (valid.Count > 1)
                    {
                        MessageBox.Show("More than one applicable module.", "NYI", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                    else
                    {
                        fs.Seek(0, SeekOrigin.Begin);
                        RootInfoNode root = new RootInfoNode(fname, file, Root.Modules[valid[0]])
                        {
                            ImageKey = "file", SelectedImageKey = "file"
                        };
                        Root.Modules[valid[0]].Read(root, fs);

                        tree.BeginUpdate();
                        Bridge.AddRootNode(root);
                        tree.EndUpdate();
                    }
                });
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                    fs.Dispose();
                }
            }
        }
Пример #8
0
        public bool Read(RootInfoNode root, Stream stream)
        {
            Bridge.AppendNode(
                new InfoNode("CMMM Header",
                             InfoType.Generic,
                             new GenericInfo("CMMM Header", "Contains information about the file type version and cache type."),
                             DataType.Critical,
                             0x00, 0x17),
                root);

            stream.Seek(0x04, SeekOrigin.Begin);

            byte[] buffer = new byte[4];
            stream.Read(buffer, 0, 4);
            int version = BitConverter.ToInt32(buffer, 0);

            stream.Read(buffer, 0, 4);
            int ctype = BitConverter.ToInt32(buffer, 0);

            stream.Seek(0x0C, SeekOrigin.Current); //Skip three 32bit integers

            int entrylen, stringlen, paddinglen, datalen, seek, databegin, dataend, entrybegin;

            byte[] cbuffer = new byte[0x0C];
            long   tempseek;

            while (stream.Read(buffer, 0, 4) == 4 && CompareBytes(buffer, CMMM))
            {
                entrybegin = (int)(stream.Position - 4);
                if (stream.Read(buffer, 0, 4) != 4)
                {
                    throw new Exception("Data ended earlier than expected.");
                }
                entrylen = BitConverter.ToInt32(buffer, 0);

                tempseek = stream.Position;
                if (stream.Seek(0x08, SeekOrigin.Current) != tempseek + 0x08) //Skip CRC64 hash
                {
                    throw new Exception("Data ended earlier than expected.");
                }

                if (version == 0x14)
                {
                    tempseek = stream.Position;
                    if (stream.Seek(0x08, SeekOrigin.Current) != tempseek + 0x08) //Skip extension
                    {
                        throw new Exception("Data ended earlier than expected.");
                    }
                }

                if (stream.Read(cbuffer, 0, 0x0C) != 0x0C)
                {
                    throw new Exception("Data ended earlier than expected.");
                }
                stringlen  = BitConverter.ToInt32(cbuffer, 0x00);
                paddinglen = BitConverter.ToInt32(cbuffer, 0x04);
                datalen    = BitConverter.ToInt32(cbuffer, 0x08);

                tempseek = stream.Position;
                seek     = (version == 0x1F ? 0x0C : 0x04) + 0x10;
                if (stream.Seek(seek, SeekOrigin.Current) != tempseek + seek) //Skip unknown integers and two CRC64 checksums
                {
                    throw new Exception("Data ended earlier than expected.");
                }

                byte[] uidb = new byte[stringlen];
                if (stream.Read(uidb, 0, stringlen) != stringlen)
                {
                    throw new Exception("Data ended earlier than expected.");
                }
                string uniqueid = Encoding.Unicode.GetString(uidb);

                if (uniqueid.Length == 0 || uniqueid[0] == '\0')
                {
                    uniqueid = "NULL";
                }

                tempseek = stream.Position;
                if (stream.Seek(paddinglen, SeekOrigin.Current) != tempseek + paddinglen) //Skip padding
                {
                    throw new Exception("Data ended earlier than expected.");
                }

                tempseek  = stream.Position;
                seek      = (entrybegin + entrylen) - (int)stream.Position;
                databegin = (int)stream.Position;
                if (stream.Seek(seek, SeekOrigin.Current) != tempseek + seek) //Skip data
                {
                    throw new Exception("Data ended earlier than expected.");
                }
                dataend = (int)stream.Position - 1;

                if (datalen > 0)
                {
                    Bridge.AppendNode(
                        new InfoNode(uniqueid,
                                     InfoType.Delegate,
                                     new object[] {
                        (Action <object[]>) delegate(object[] data) {
                            string path = ((string)data[2]);
                            int begin   = ((int)data[0]);
                            int len     = ((int)data[1]);

                            byte[] imgdata = new byte[len];
                            using (FileStream nfs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
                            {
                                nfs.Seek(begin, SeekOrigin.Begin);
                                nfs.Read(imgdata, 0, len);
                            }

                            Bridge.ShowInfo(InfoType.ImageStream, new MemoryStream(imgdata, false));
                        },
                        new object[3] {
                            databegin, datalen, root.FilePath
                        }
                    },
                                     DataType.Ancillary,
                                     entrybegin, dataend),
                        root);
                }
                else
                {
                    Bridge.AppendNode(
                        new InfoNode(uniqueid,
                                     InfoType.None,
                                     null,
                                     DataType.Ancillary,
                                     entrybegin, dataend),
                        root);
                }
            }

            if (stream.Position < stream.Length)
            {
                Bridge.AppendNode(
                    new InfoNode("EOF",
                                 InfoType.Generic,
                                 new GenericInfo("EOF", "End Of File data; serves no function or purpose."),
                                 DataType.Useless,
                                 stream.Position - 4, stream.Length - 1),
                    root);
            }

            return(true);
        }
Пример #9
0
 public void Write(RootInfoNode root, Stream sout)
 {
     Bridge.SimpleWrite(root, sout);
 }
Пример #10
0
        public bool Read(RootInfoNode root, Stream stream)
        {
            root.Info  = root.FilePath;
            root.IType = InfoType.ImageFile;

            //root.ImageKey = root.SelectedImageKey = "image";

            Bridge.AppendNode(
                new InfoNode("Magic number", "binary",
                             InfoType.Generic,
                             new GenericInfo("Magic Number", "An array of bytes that allows programs to determine that the specific file is a PNG."),
                             DataType.Critical,
                             0x00, 0x07),
                root);

            stream.Seek(0x08, SeekOrigin.Begin);

            byte[] buffer = new byte[4];
            string name = null;
            uint   length = 0;
            long   start, end;
            bool   Ancillary, Private, STC;

            do
            {
                start = stream.Position;
                if (stream.Read(buffer, 0, 4) != 4)
                {
                    throw new Exception("Data ended earlier than expected.");
                }
                length = (uint)buffer[0] << 0x18 | (uint)buffer[1] << 0x10 | (uint)buffer[2] << 0x08 | (uint)buffer[3];
                //length = BitConverter.ToUInt32(buffer, 0); //Big endian

                if (stream.Read(buffer, 0, 4) != 4)
                {
                    throw new Exception("Data ended earlier than expected.");
                }
                name      = Encoding.ASCII.GetString(buffer);
                Ancillary = (buffer[0] & 0x20) == 0x20;
                Private   = (buffer[1] & 0x20) == 0x20;
                STC       = (buffer[3] & 0x20) == 0x20;


                if (stream.Seek(length, SeekOrigin.Current) != start + length + 4 + 4)
                {
                    throw new Exception("Data ended earlier than expected.");
                }

                if (stream.Read(buffer, 0, 4) != 4) //CRC32r
                {
                    throw new Exception("Data ended earlier than expected.");
                }

                end = stream.Position - 1;

                StringBuilder sb    = new StringBuilder();
                DataType      dtype = (Ancillary ? DataType.Metadata : DataType.Critical);
                switch (name)
                {
                case "IHDR":
                    sb.AppendLine("The IHDR chunk contains the header data of a PNG file. It contains information about the width, height, but depth, colour type, compression method, filter method, and interlacing method of the image."); break;

                case "PLTE":
                    sb.AppendLine("The PLTE chunk contains an array of up to 256 8-bit RGB colours used for simple images that contain less than 256 colours in total."); break;

                case "IDAT":
                    sb.AppendLine("The IDAT chunk typically contains the compressed image data. There may be more than one IDAT chunk, and if the image has been fully rendered before reaching a new IDAT chunk it will be ignored."); break;

                case "IEND":
                    sb.AppendLine("The IEND chunk marks the end of a PNG file or data stream. It typically has no contents."); break;

                case "tRNS":
                    sb.AppendLine("The tRNS chunk specifies a 16-bit RGB colour to be used as a completely transparent colour in truecolor images, a 16-bit grey color to be used as a completely transparent colour in greyscale images, or contains an array of up to 256 bytes controlling the alpha value of palette entries with the same index.");
                    dtype = DataType.Ancillary;
                    break;

                case "cHRM":
                    sb.AppendLine("The cHRM chunk specifies chromatic data. If an sRGB or iCCP chunk is also present it will override a cHRM chunk.");
                    dtype = DataType.Ancillary;
                    break;

                case "gAMA":
                    sb.AppendLine("The gAMA chunk controls the image gamma. It should contain a single 4 byte unsigned integer, representing gamma times 100,000.");
                    dtype = DataType.Ancillary;
                    break;

                case "iCCP":
                    sb.AppendLine("The iCCP chunk contains an embedded ICC profile. The data includes a null-terminated string representing the profile's name, followed by a single byte for the compression method, and finally the compressed ICC profile.");
                    dtype = DataType.Ancillary;
                    break;

                case "sRGB":
                    sb.AppendLine("The sRGB chunk specifies that the image samples conform to the sRGB colour space and contains a single byte specifying a rendering intent defined in ICC-1 and ICC-1A.");
                    dtype = DataType.Ancillary;
                    break;

                case "sBIT":
                    sb.AppendLine("The sBIT chunk specifies the original the original amount of significant bits of the image. Its size in bytes should be equal to the amount of channels in the image.");
                    dtype = DataType.Ancillary;
                    break;

                case "tEXt":
                    sb.AppendLine("The tEXT chunk is a metadata chunk that contains a null-terminated keyword of up to 80 characters (including the null character) followed by an arbitrary amount of Latin-1 text data defined in ISO-8859-1."); break;

                case "zTXt":
                    sb.AppendLine("The zTXt chunk is a metadata chunk that contains a null-terminated keyword of up to 80 characters (including the null character) followed by a single byte specifying a compression method (currently only 0x00 is used, standardized as the same compression used for IDAT data), then followed by an arbitrary amount of compressed data."); break;

                case "iTXt":
                    sb.AppendLine("The iTXt chunk is a metadata chunk that contains used to contain text data of an arbitrary encoding which may or may not be compressed."); break;

                case "hIST":
                    sb.AppendLine("The hIST chunk is a metadata chunk that contains information about the frequency of palette colours, it contains an array of 16-bit integers and an entry for each palette entry."); break;

                case "pHYs":
                    sb.AppendLine("The pHYs chunk specifies the intended pixel size or aspect ratio for displaying the image, its contents should be exactly 9 bytes in length.");
                    dtype = DataType.Ancillary;
                    break;

                case "sPLT":
                    sb.AppendLine("The sPLT chunk specifies a suggested palette and contains a null-terminated palette name of up to 80 characters (including the null character) followed by a single byte specifying the bit depth, followed by an array, each entry contains an RGBA color as well as a 16-bit integer for frequency.");
                    dtype = DataType.Ancillary;
                    break;

                case "bKGD":
                    sb.AppendLine("The bKGD chunk specifies a suggested background color to display the image against.");
                    dtype = DataType.Ancillary;
                    break;

                case "tIME":
                    sb.AppendLine("The tIME chunk is a metadata chunk that contains the last modification time of the image. It consists of a 16-bit integer for the year, followed by a byte each for the month, day, hour, minute, and second."); break;

                default:
                    sb.AppendLine("Unknown chunk type.");
                    break;
                }

                sb.AppendLine(Ancillary ? "\r\nThis chunk is ancillary." : "\r\nThis chunk is critical.");
                sb.AppendLine(Private ? "This chunk is a private chunk." : "This chunk is a public chunk.");
                sb.AppendLine(STC ? "This chunk is safe to copy." : "This chunk is not safe to copy.");
                sb.Append(String.Format("This chunk has a CRC32 of {0:X2}{1:X2}{2:X2}{3:X2}", buffer[0], buffer[1], buffer[2], buffer[3]));

                Bridge.AppendNode(
                    new InfoNode(name, (name == "IDAT" ? "block-purple" : "block"),
                                 InfoType.Generic,
                                 new GenericInfo(name + " Chunk", sb.ToString()),
                                 dtype,
                                 start, end),
                    root);
            } while (name != "IEND");

            if (stream.Position < stream.Length)
            {
                Bridge.AppendNode(
                    new InfoNode("EOF", "block-orange",
                                 InfoType.Generic,
                                 new GenericInfo("EOF", "End Of File data; serves no function or purpose to the PNG image."),
                                 DataType.Useless,
                                 stream.Position, stream.Length - 1),
                    root);
            }

            byte colortype = 0xFF;

            foreach (InfoNode n in root.Nodes)
            {
                if (n.Text == "Magic number")
                {
                    continue;
                }

                int datastart  = (int)(n.DataStart + 8);
                int datalength = (int)((n.DataEnd - 4) - datastart + 1);

                Bridge.AppendNode(new InfoNode("Chunk length", "int", InfoType.None, null, DataType.Critical, n.DataStart, n.DataStart + 3), n);
                Bridge.AppendNode(new InfoNode("Chunk name", "str", InfoType.None, null, DataType.Critical, n.DataStart + 4, n.DataStart + 7), n);

                if (datalength < 1)
                {
                    Checksum(n);
                    continue;
                }

                #region IHDR
                if (n.Text == "IHDR")
                {
                    if (datalength != 0x0D)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", "Could not parse header information. IHDR chunk must have a length of 0x0D (13 decimal)."),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    stream.Seek(datastart, SeekOrigin.Begin);
                    byte[] hdrb = new byte[0x0D];
                    stream.Read(hdrb, 0, 0x0D);

                    uint   xdim  = (uint)hdrb[0] << 0x18 | (uint)hdrb[1] << 0x10 | (uint)hdrb[2] << 0x08 | (uint)hdrb[3];
                    uint   ydim  = (uint)hdrb[4] << 0x18 | (uint)hdrb[5] << 0x10 | (uint)hdrb[6] << 0x08 | (uint)hdrb[7];
                    string ctype = null;
                    colortype = hdrb[0x09];
                    switch (colortype)
                    {
                    case 0x00:
                        ctype = "a greyscale image in which each pixel contains a single white sample";
                        break;

                    case 0x02:
                        ctype = "a truecolor image in which each pixel contans a red, green, and blue sample";
                        break;

                    case 0x03:
                        ctype = "an indexed-color image in which each pixel is a pointer to a palette entry";
                        break;

                    case 0x04:
                        ctype = "a greyscale image with an alpha channel in which each pixel contains a white, and alpha sample";
                        break;

                    case 0x06:
                        ctype = "a truecolor image with an alpha channel in which each pixel contains a red, green, blue, and alpha sample";
                        break;
                    }

                    InfoNode nin = new InfoNode("Header information", "info",
                                                InfoType.None, null,
                                                //InfoType.Generic,
                                                //new GenericInfo(
                                                //    "Header Information",
                                                //    String.Format("The image has a width of {0} and a height of {1}.\r\nIt has a bitdepth of {2} bits per sample.\r\nIt is {3}.\r\nThe image data is compressed using {4} compression algorithm.\r\nA filter method of '{5}' is specified.\r\nThe image {6} interlaced.",
                                                //        xdim,
                                                //        ydim,
                                                //        hdrb[0x08],
                                                //        ctype,
                                                //        hdrb[0x0A] == 0 ? "the DEFLATE" : "an unknown",
                                                //        hdrb[0x0B],
                                                //        hdrb[0x0C] == 0 ? "is not" : "is")
                                                //),
                                                DataType.Critical,
                                                n.DataStart + 8, n.DataEnd - 4);
                    Bridge.AppendNode(nin, n);

                    Bridge.AppendNode(new InfoNode("Image width", "int", InfoType.Generic, new GenericInfo("Image Width", xdim.ToString() + "px"), DataType.Critical, n.DataStart + 8, n.DataStart + 11), nin);
                    Bridge.AppendNode(new InfoNode("Image height", "int", InfoType.Generic, new GenericInfo("Image Height", ydim.ToString() + "px"), DataType.Critical, n.DataStart + 12, n.DataStart + 15), nin);
                    Bridge.AppendNode(new InfoNode("Bit depth", "byte", InfoType.Generic, new GenericInfo("Bit Depth", hdrb[0x08].ToString() + " bits per sample"), DataType.Critical, n.DataStart + 16, n.DataStart + 16), nin);
                    Bridge.AppendNode(new InfoNode("Color type", "byte", InfoType.Generic, new GenericInfo("Color Type", "This is " + ctype), DataType.Critical, n.DataStart + 17, n.DataStart + 17), nin);
                    Bridge.AppendNode(new InfoNode("Compression method", "byte", InfoType.Generic, new GenericInfo("Compression Method", String.Format("This image uses {0} compression algorithm.", hdrb[0x0A] == 0 ? "the DEFLATE" : "an unknown")), DataType.Critical, n.DataStart + 18, n.DataStart + 18), nin);
                    Bridge.AppendNode(new InfoNode("Filter type", "byte", InfoType.Generic, new GenericInfo("Filter Type", hdrb[0x0B].ToString()), DataType.Critical, n.DataStart + 19, n.DataStart + 19), nin);
                    Bridge.AppendNode(new InfoNode("Interlacing method", "byte", InfoType.Generic, new GenericInfo("Interlacing Method", String.Format("This image is{0} interlaced.", hdrb[0x0C] == 0 ? " not" : "")), DataType.Critical, n.DataStart + 20, n.DataStart + 20), nin);
                }
                #endregion
                #region tEXt
                else if (n.Text == "tEXt")
                {
                    stream.Seek(datastart, SeekOrigin.Begin);
                    //this should never realistically be needed
                    byte[]        tb = new byte[0x100];
                    int           remaining = datalength, read = 0;
                    bool          istext = false;
                    StringBuilder key    = new StringBuilder();
                    StringBuilder text   = new StringBuilder();
                    while (remaining > 0)
                    {
                        read       = stream.Read(tb, 0, remaining > 0x100 ? 0x100 : remaining);
                        remaining -= read;

                        if (istext)
                        {
                            text.Append(Encoding.ASCII.GetString(tb, 0, read));
                        }
                        else
                        {
                            for (int i = 0; i < read; i++)
                            {
                                if (tb[i] == 0x00)
                                {
                                    istext = true;
                                    if (i > 0)
                                    {
                                        key.Append(Encoding.ASCII.GetString(tb, 0, i));
                                    }
                                    if (i < read - 1)
                                    {
                                        text.Append(Encoding.ASCII.GetString(tb, i + 1, read - i - 1));
                                    }
                                }
                            }
                            if (istext)
                            {
                                continue;
                            }
                            key.Append(Encoding.ASCII.GetString(tb, 0, read));
                        }
                    }

                    Bridge.AppendNode(
                        new InfoNode("Standard text information", "info",
                                     InfoType.Generic,
                                     new GenericInfo(key.ToString(), text.ToString()),
                                     DataType.Critical,
                                     n.DataStart + 8, n.DataEnd - 4),
                        n);
                }
                #endregion
                #region tIME
                else if (n.Text == "tIME")
                {
                    if (datalength != 0x07)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", "Could not parse time information. tIME chunk must have a length of 0x07."),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    stream.Seek(datastart, SeekOrigin.Begin);
                    byte[] tb = new byte[0x07];
                    stream.Read(tb, 0, 0x07);

                    //ushort year = (ushort);
                    DateTime time = new DateTime((tb[0] << 0x08 | tb[1]), tb[2], tb[3], tb[4], tb[5], tb[6], DateTimeKind.Utc);
                    //DateTime ltime = time.ToLocalTime(); //Thanks a lot imagemagick for completely ignoring the PNG standard and using the local time instead of UTC

                    Bridge.AppendNode(
                        new InfoNode("Last modification time information", "info",
                                     InfoType.Generic,
                                     new GenericInfo(
                                         "Last Modification Time",
                                         String.Format("The last modification time of this image has been specified as {0} UTC.\r\n\r\nFormatted (F): {1}",
                                                       time.ToString("yyyy-MM-dd h:mm:sstt"),
                                                       time.ToString("F"))
                                         ),
                                     DataType.Critical,
                                     n.DataStart + 8, n.DataEnd - 4),
                        n);
                }
                #endregion
                #region gAMA
                else if (n.Text == "gAMA")
                {
                    if (datalength != 0x04)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", "Could not parse gamma information. gAMA chunk must have a length of 0x04."),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    stream.Seek(datastart, SeekOrigin.Begin);
                    byte[] gamab = new byte[0x04];
                    stream.Read(gamab, 0, 0x04);

                    uint ydim = (uint)gamab[0] << 0x18 | (uint)gamab[1] << 0x10 | (uint)gamab[2] << 0x08 | (uint)gamab[3];

                    float gamma = ydim / 100000f;

                    Bridge.AppendNode(
                        new InfoNode("Gamma information", "info",
                                     InfoType.Generic,
                                     new GenericInfo("Gamma Information", String.Format("This chunk specifies the desired image gamma at '{0}'.", gamma)),
                                     DataType.Critical,
                                     n.DataStart + 8, n.DataEnd - 4),
                        n);
                }
                #endregion
                #region PLTE
                else if (n.Text == "PLTE")
                {
                    if (datalength > 0x300 || datalength % 3 != 0)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", "Could not parse palette information. PLTE chunk must have a length less than 0x300 an divisible by three."),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    stream.Seek(datastart, SeekOrigin.Begin);
                    byte[] paletteb = new byte[datalength];
                    stream.Read(paletteb, 0, datalength);

                    List <ListViewItem> entries = new List <ListViewItem>();
                    int index = 0;
                    for (int i = 0; i < datalength; index++)
                    {
                        int r = paletteb[i++];
                        int g = paletteb[i++];
                        int b = paletteb[i++];

                        System.Windows.Forms.ListViewItem lvi = new System.Windows.Forms.ListViewItem(index.ToString())
                        {
                            BackColor = Color.FromArgb(r, g, b)
                        };
                        lvi.SubItems.Add(r.ToString());
                        lvi.SubItems.Add(g.ToString());
                        lvi.SubItems.Add(b.ToString());
                        lvi.ForeColor = r * 0.299 + g * 0.587 + b * 0.114 <= 186 ? Color.White : Color.Black;
                        entries.Add(lvi);
                    }

                    Bridge.AppendNode(
                        new InfoNode("Color palette", "info",
                                     InfoType.Table,
                                     new TableInfo(View.Details, new string[] { "Index", "Red", "Green", "Blue" }, entries.ToArray())
                    {
                        ResizeStyle = ColumnHeaderAutoResizeStyle.HeaderSize
                    },
                                     DataType.Critical,
                                     n.DataStart + 8, n.DataEnd - 4),
                        n);
                }
                #endregion
                #region cHRM
                else if (n.Text == "cHRM")
                {
                    if (datalength != 0x20)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", "Could not parse chromatic information. cHRM chunk must have a length of 0x20."),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    stream.Seek(datastart, SeekOrigin.Begin);
                    byte[] chrmb = new byte[0x20];
                    stream.Read(chrmb, 0, 0x20);

                    uint
                        uwx = (uint)chrmb[0x00] << 0x18 | (uint)chrmb[0x01] << 0x10 | (uint)chrmb[0x02] << 0x08 | (uint)chrmb[0x03],
                        uwy = (uint)chrmb[0x04] << 0x18 | (uint)chrmb[0x05] << 0x10 | (uint)chrmb[0x06] << 0x08 | (uint)chrmb[0x07],
                        urx = (uint)chrmb[0x08] << 0x18 | (uint)chrmb[0x09] << 0x10 | (uint)chrmb[0x0A] << 0x08 | (uint)chrmb[0x0B],
                        ury = (uint)chrmb[0x0C] << 0x18 | (uint)chrmb[0x0D] << 0x10 | (uint)chrmb[0x0E] << 0x08 | (uint)chrmb[0x0F],
                        ugx = (uint)chrmb[0x10] << 0x18 | (uint)chrmb[0x11] << 0x10 | (uint)chrmb[0x12] << 0x08 | (uint)chrmb[0x13],
                        ugy = (uint)chrmb[0x14] << 0x18 | (uint)chrmb[0x15] << 0x10 | (uint)chrmb[0x16] << 0x08 | (uint)chrmb[0x17],
                        ubx = (uint)chrmb[0x18] << 0x18 | (uint)chrmb[0x19] << 0x10 | (uint)chrmb[0x1A] << 0x08 | (uint)chrmb[0x1B],
                        uby = (uint)chrmb[0x1C] << 0x18 | (uint)chrmb[0x1D] << 0x10 | (uint)chrmb[0x1E] << 0x08 | (uint)chrmb[0x1F];

                    float
                        wx = (uwx > 0 ? uwx / 100000f : 0),
                        wy = (uwy > 0 ? uwy / 100000f : 0),
                        rx = (urx > 0 ? urx / 100000f : 0),
                        ry = (ury > 0 ? ury / 100000f : 0),
                        gx = (ugx > 0 ? ugx / 100000f : 0),
                        gy = (ugy > 0 ? ugy / 100000f : 0),
                        bx = (ubx > 0 ? ubx / 100000f : 0),
                        by = (uby > 0 ? uby / 100000f : 0);

                    InfoNode cn = new InfoNode("Chromatic information", "info",
                                               InfoType.Table,
                                               new TableInfo(View.Details, new string[] { "Key", "Value" }, new ListViewItem[] {
                        new ListViewItem(new string[] { "White X", wx.ToString() }),
                        new ListViewItem(new string[] { "White Y", wy.ToString() }),
                        new ListViewItem(new string[] { "Red X", rx.ToString() }),
                        new ListViewItem(new string[] { "Red Y", ry.ToString() }),
                        new ListViewItem(new string[] { "Green X", gx.ToString() }),
                        new ListViewItem(new string[] { "Green Y", gy.ToString() }),
                        new ListViewItem(new string[] { "Blue X", bx.ToString() }),
                        new ListViewItem(new string[] { "Blue Y", by.ToString() })
                    }),
                                               DataType.Critical,
                                               n.DataStart + 8, n.DataEnd - 4);

                    Bridge.AppendNode(
                        cn,
                        n);

                    Bridge.AppendNode(new InfoNode("White X", "int", InfoType.None, null, DataType.Critical, n.DataStart + 0x08, n.DataStart + 0x0B), cn);
                    Bridge.AppendNode(new InfoNode("White Y", "int", InfoType.None, null, DataType.Critical, n.DataStart + 0x0C, n.DataStart + 0x0F), cn);
                    Bridge.AppendNode(new InfoNode("Red X", "int", InfoType.None, null, DataType.Critical, n.DataStart + 0x10, n.DataStart + 0x13), cn);
                    Bridge.AppendNode(new InfoNode("Red Y", "int", InfoType.None, null, DataType.Critical, n.DataStart + 0x14, n.DataStart + 0x17), cn);
                    Bridge.AppendNode(new InfoNode("Green X", "int", InfoType.None, null, DataType.Critical, n.DataStart + 0x18, n.DataStart + 0x1B), cn);
                    Bridge.AppendNode(new InfoNode("Green Y", "int", InfoType.None, null, DataType.Critical, n.DataStart + 0x1C, n.DataStart + 0x1F), cn);
                    Bridge.AppendNode(new InfoNode("Blue X", "int", InfoType.None, null, DataType.Critical, n.DataStart + 0x20, n.DataStart + 0x23), cn);
                    Bridge.AppendNode(new InfoNode("Blue Y", "int", InfoType.None, null, DataType.Critical, n.DataStart + 0x24, n.DataStart + 0x27), cn);
                }
                #endregion
                #region sBIT
                else if (n.Text == "sBIT")
                {
                    if (datalength < 0x01 || datalength > 0x04)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", "Could not parse significant bits information. sBIT chunk must have a length between 0x01 and 0x04."),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    stream.Seek(datastart, SeekOrigin.Begin);
                    byte[] sbitb = new byte[datalength];
                    stream.Read(sbitb, 0, datalength);

                    InfoNode sn = new InfoNode("Significant bits information", "info",
                                               InfoType.None,
                                               null,
                                               DataType.Critical,
                                               n.DataStart + 8, n.DataEnd - 4);

                    Bridge.AppendNode(
                        sn,
                        n);

                    if (datalength < 3)
                    {
                        Bridge.AppendNode(new InfoNode("Significant greyscale bits", "byte", InfoType.Generic, new GenericInfo("Significant Greyscale Bits", sbitb[0].ToString() + " bits"), DataType.Critical, n.DataStart + 8, n.DataStart + 8), sn);
                        if (datalength == 2)
                        {
                            Bridge.AppendNode(new InfoNode("Significant alpha bits", "byte", InfoType.Generic, new GenericInfo("Significant Alpha Bits", sbitb[1].ToString() + " bits"), DataType.Critical, n.DataStart + 9, n.DataStart + 9), sn);
                        }
                    }
                    else
                    {
                        Bridge.AppendNode(new InfoNode("Significant red bits", "byte", InfoType.Generic, new GenericInfo("Significant Red Bits", sbitb[0].ToString() + " bits"), DataType.Critical, n.DataStart + 8, n.DataStart + 8), sn);
                        Bridge.AppendNode(new InfoNode("Significant green bits", "byte", InfoType.Generic, new GenericInfo("Significant Green Bits", sbitb[1].ToString() + " bits"), DataType.Critical, n.DataStart + 9, n.DataStart + 9), sn);
                        Bridge.AppendNode(new InfoNode("Significant blue bits", "byte", InfoType.Generic, new GenericInfo("Significant Blue Bits", sbitb[2].ToString() + " bits"), DataType.Critical, n.DataStart + 10, n.DataStart + 10), sn);
                        if (datalength == 4)
                        {
                            Bridge.AppendNode(new InfoNode("Significant alpha bits", "byte", InfoType.Generic, new GenericInfo("Significant Alpha Bits", sbitb[3].ToString() + " bits"), DataType.Critical, n.DataStart + 11, n.DataStart + 11), sn);
                        }
                    }
                }
                #endregion
                #region sRGB
                else if (n.Text == "sRGB")
                {
                    if (datalength != 0x01)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", "Could not parse rendering intent information. gAMA chunk must have a length of 0x01."),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    stream.Seek(datastart, SeekOrigin.Begin);
                    byte[] srgbb = new byte[0x01];
                    stream.Read(srgbb, 0, 0x01);

                    string intent = "";
                    switch (srgbb[0])
                    {
                    case 0x00:
                        intent = "perceptual";
                        break;

                    case 0x01:
                        intent = "relative colorimetric";
                        break;

                    case 0x02:
                        intent = "saturation";
                        break;

                    case 0x03:
                        intent = "absolute colorimetric";
                        break;
                    }

                    Bridge.AppendNode(
                        new InfoNode("Rendering intent information", "info",
                                     InfoType.Generic,
                                     new GenericInfo("Rendering Intent", String.Format("This chunk specifies the desired rendering intent (defined in the sRGB standard) to be '{0}'.", intent)),
                                     DataType.Critical,
                                     n.DataStart + 8, n.DataEnd - 4),
                        n);
                }
                #endregion
                #region iCCP
                else if (n.Text == "iCCP")
                {
                    stream.Seek(datastart, SeekOrigin.Begin);
                    //this should never realistically be needed
                    byte[]        tb = new byte[0x100];
                    int           remaining = datalength, read = 0;
                    StringBuilder key      = new StringBuilder();
                    int           offset   = 0;
                    bool          finished = false;
                    while (remaining > 0)
                    {
                        read       = stream.Read(tb, 0, remaining > 0x100 ? 0x100 : remaining);
                        remaining -= read;

                        for (int i = 0; i < read; i++)
                        {
                            offset++;
                            if (tb[i] == 0x00)
                            {
                                if (i > 0)
                                {
                                    key.Append(Encoding.ASCII.GetString(tb, 0, i));
                                }
                                finished = true;
                                break;
                            }
                        }
                        if (finished)
                        {
                            break;
                        }
                        key.Append(Encoding.ASCII.GetString(tb, 0, read));
                    }

                    InfoNode iccpn = new InfoNode("ICC profile", "info",
                                                  InfoType.None,
                                                  null,
                                                  DataType.Critical,
                                                  n.DataStart + 8, n.DataEnd - 4);

                    Bridge.AppendNode(
                        iccpn,
                        n);

                    //StringBuilder profile = new StringBuilder();

                    stream.Seek(datastart + offset + 3, SeekOrigin.Begin);

                    int    profilelen = (int)(n.DataEnd) - (datastart + offset);
                    byte[] pb         = new byte[profilelen];
                    stream.Read(pb, 0, profilelen);

                    List <byte> outp = new List <byte>();
                    using (MemoryStream ms = new MemoryStream(pb))
                        using (System.IO.Compression.DeflateStream deflate = new System.IO.Compression.DeflateStream(ms, System.IO.Compression.CompressionMode.Decompress))
                        {
                            int    dread;
                            byte[] db = new byte[0x100];
                            while ((dread = deflate.Read(db, 0, 0x100)) > 0)
                            {
                                if (dread == 0x100)
                                {
                                    outp.AddRange(db);
                                }
                                else
                                {
                                    for (int i = 0; i < dread; i++)
                                    {
                                        outp.Add(db[i]);
                                    }
                                }
                                //profile.Append(Encoding.ASCII.GetString(db, 0, dread));
                            }
                        }

                    pb = null;

                    Bridge.AppendNode(new InfoNode("Profile name", "str", InfoType.Generic, new GenericInfo("Profile Name", key.ToString()), DataType.Critical, n.DataStart + 8, n.DataStart + 8 + offset - 1), iccpn);
                    Bridge.AppendNode(new InfoNode("Compression method", "byte", InfoType.None, null, DataType.Critical, n.DataStart + 8 + offset, n.DataStart + 8 + offset), iccpn);
                    Bridge.AppendNode(new InfoNode("ICC profile body", "binary", InfoType.Binary, outp.ToArray(), DataType.Critical, n.DataStart + 8 + offset + 1, n.DataEnd - 4), iccpn);
                }
                #endregion
                #region bKGD
                else if (n.Text == "bKGD")
                {
                    if (datalength != 0x01 && datalength != 0x02 && datalength != 0x06)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", "Could not parse background color information. bKGD chunk must have a length of either 0x01, 0x02, or 0x06."),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    stream.Seek(datastart, SeekOrigin.Begin);
                    byte[] bkgdb = new byte[datalength];
                    stream.Read(bkgdb, 0, datalength);

                    InfoNode sn = new InfoNode("Background color information", "info",
                                               InfoType.None,
                                               null,
                                               DataType.Critical,
                                               n.DataStart + 8, n.DataEnd - 4);

                    Bridge.AppendNode(
                        sn,
                        n);

                    if (datalength == 1)
                    {
                        Bridge.AppendNode(new InfoNode("Palette index", "byte", InfoType.Generic, new GenericInfo("Palette Index", bkgdb[0].ToString()), DataType.Critical, n.DataStart + 8, n.DataStart + 8), sn);
                    }
                    else if (datalength == 2)
                    {
                        int w = bkgdb[0] << 0x08 | (int)bkgdb[1];
                        Bridge.AppendNode(new InfoNode("White value", "int", InfoType.Generic, new GenericInfo("White Value", w.ToString()), DataType.Critical, n.DataStart + 8, n.DataStart + 9), sn);
                    }
                    else if (datalength == 6)
                    {
                        int r = bkgdb[0] << 0x08 | (int)bkgdb[1];
                        int g = bkgdb[2] << 0x08 | (int)bkgdb[3];
                        int b = bkgdb[4] << 0x08 | (int)bkgdb[5];
                        Bridge.AppendNode(new InfoNode("Red value", "int", InfoType.Generic, new GenericInfo("Red Value", r.ToString()), DataType.Critical, n.DataStart + 8, n.DataStart + 9), sn);
                        Bridge.AppendNode(new InfoNode("Green value", "int", InfoType.Generic, new GenericInfo("Green Value", g.ToString()), DataType.Critical, n.DataStart + 10, n.DataStart + 11), sn);
                        Bridge.AppendNode(new InfoNode("Blue value", "int", InfoType.Generic, new GenericInfo("Blue Value", b.ToString()), DataType.Critical, n.DataStart + 12, n.DataStart + 13), sn);
                    }
                }
                #endregion
                #region pHYs
                else if (n.Text == "pHYs")
                {
                    if (datalength != 0x09)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", "Could not parse physical pixel dimensions information. pHYs chunk must have a length of 0x09."),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    stream.Seek(datastart, SeekOrigin.Begin);
                    byte[] physb = new byte[0x09];
                    stream.Read(physb, 0, 0x09);

                    uint xdim = (uint)physb[0] << 0x18 | (uint)physb[1] << 0x10 | (uint)physb[2] << 0x08 | (uint)physb[3];
                    uint ydim = (uint)physb[4] << 0x18 | (uint)physb[5] << 0x10 | (uint)physb[6] << 0x08 | (uint)physb[7];

                    uint dpix = (uint)Math.Round(xdim * 0.0254);
                    uint dpiy = (uint)Math.Round(ydim * 0.0254);

                    InfoNode pn = new InfoNode("Physical pixel dimensions information", "info",
                                               InfoType.Generic,
                                               new GenericInfo("Physical Dimensions Information",
                                                               (physb[8] == 1 ?
                                                                String.Format("This chunk specifies the physical pixel dimesions as {0}dpi wide, {1}dpi tall.", dpix, dpiy)
                                :
                                                                String.Format("This chunk specifies the physical pixel aspect ratio as {0}:{1}.", xdim, ydim))),
                                               DataType.Critical,
                                               n.DataStart + 8, n.DataEnd - 4);

                    Bridge.AppendNode(
                        pn,
                        n);

                    Bridge.AppendNode(new InfoNode("Pixels per unit X", "int", InfoType.Generic, new GenericInfo("Pixels Per Unit X", xdim.ToString()), DataType.Critical, n.DataStart + 8, n.DataStart + 11), pn);
                    Bridge.AppendNode(new InfoNode("Pixels per unit Y", "int", InfoType.Generic, new GenericInfo("Pixels Per Unit X", ydim.ToString()), DataType.Critical, n.DataStart + 12, n.DataStart + 15), pn);
                    Bridge.AppendNode(new InfoNode("Unit", "byte", InfoType.Generic, new GenericInfo("Unit", physb[8] == 1 ? "Unit is one metre." : "No unit."), DataType.Critical, n.DataStart + 16, n.DataStart + 16), pn);
                }
                #endregion
                else if (n.Text == "IDAT")
                {
                    Bridge.AppendNode(new InfoNode("Image Data", "binary", InfoType.None, null, DataType.Critical, n.DataStart + 8, n.DataEnd - 4), n);
                }

                /* *
                 * Chunks that absolutely require IHDR to have already been read.
                 *
                 * The specification states that the IHDR must always be the first chunk,
                 * but we're a bit liberal with that; we're just parsing the image file,
                 * we dont actually need to display it thus we don't need it to adhere to
                 * the PNG specification we just need it to be coherent enough to read to EOF.
                 * */
                else if (colortype == 0xFF)
                {
                    Bridge.AppendNode(new InfoNode("Unknown Data", "unknown", InfoType.None, null, DataType.Critical, n.DataStart + 8, n.DataEnd - 4), n);
                    Checksum(n);
                    continue;
                }
                #region tRNS
                else if (n.Text == "tRNS")
                {
                    byte[] trnsb;
                    if (colortype == 0x03) //Indexed color
                    {
                        stream.Seek(datastart, SeekOrigin.Begin);
                        trnsb = new byte[datalength];
                        stream.Read(trnsb, 0, datalength);

                        List <ListViewItem> entries = new List <ListViewItem>();
                        for (int i = 0; i < datalength; i++)
                        {
                            entries.Add(new ListViewItem(new string[] { i.ToString(), trnsb[i].ToString() }));
                        }

                        Bridge.AppendNode(
                            new InfoNode("Transparency information (Paletted)", "info",
                                         InfoType.Table,
                                         new TableInfo(View.Details, new string[] { "Index", "Opacity" }, entries.ToArray())
                        {
                            ResizeStyle = ColumnHeaderAutoResizeStyle.HeaderSize
                        },
                                         DataType.Critical,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    int trnslen = colortype == 0x00 ? 2 : (colortype == 0x02 ? 6 : -1);

                    if (trnslen < 1)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", String.Format("Could not parse transparency information. The color type specified in the IHDR chunk is not supported.", trnslen, colortype)),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }
                    if (datalength != trnslen)
                    {
                        Bridge.AppendNode(
                            new InfoNode("Error", "error",
                                         InfoType.Generic,
                                         new GenericInfo("Error", String.Format("Could not parse transparency information. tRNS chunk must have a length of 0x{0:X2} with color type 0x{1:X2}.", trnslen, colortype)),
                                         DataType.Error,
                                         n.DataStart + 8, n.DataEnd - 4),
                            n);
                        Checksum(n);
                        continue;
                    }

                    stream.Seek(datastart, SeekOrigin.Begin);
                    trnsb = new byte[trnslen];
                    stream.Read(trnsb, 0, trnslen);

                    string body = "";
                    if (trnslen == 2)
                    {
                        uint grey = (uint)trnsb[0] << 0x08 | (uint)trnsb[1];
                        body = String.Format("transparent grey color as '{0}'", grey);
                    }
                    else if (trnslen == 6)
                    {
                        uint red   = (uint)trnsb[0] << 0x08 | (uint)trnsb[1];
                        uint green = (uint)trnsb[2] << 0x08 | (uint)trnsb[3];
                        uint blue  = (uint)trnsb[4] << 0x08 | (uint)trnsb[5];
                        body = String.Format("transparent RGB color as '{0}, {1}, {2}'", red, green, blue);
                    }
                    //uint ydim = (uint)gamab[0] << 0x18 | (uint)gamab[1] << 0x10 | (uint)gamab[2] << 0x08 | (uint)gamab[3];

                    Bridge.AppendNode(
                        new InfoNode("Transparency information", "info",
                                     InfoType.Generic,
                                     new GenericInfo("Transparency Information", String.Format("This chunk specifies the {0}.", body)),
                                     DataType.Critical,
                                     n.DataStart + 8, n.DataEnd - 4),
                        n);
                }
                #endregion
                else
                {
                    Bridge.AppendNode(new InfoNode("Unknown Data", "unknown", InfoType.None, null, DataType.Critical, n.DataStart + 8, n.DataEnd - 4), n);
                }

                Checksum(n);
            }

            return(true);
        }
Пример #11
0
        private void tree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            hexBox1.Highlights.Clear();
            if (e.Node.Level == 0)
            {
                if (!(e.Node is RootInfoNode))
                {
                    return;
                }

                RootInfoNode rin = (RootInfoNode)e.Node;
                if (!File.Exists(rin.FilePath))
                {
                    throw new FileNotFoundException();
                }

                hexBox1.ReadFile(rin.FilePath);
                fileloaded = rin.FilePath;

                double h = rnd.NextDouble();
                int    r, g, b;
                foreach (InfoNode inode in e.Node.Nodes)
                {
                    HSV.ToRGB(h * 360, 1.00d, 1d, out r, out g, out b);
                    hexBox1.Highlights.Add(new HexBoxLib.Highlight((int)inode.DataStart, (int)inode.DataEnd, Color.FromArgb(r, g, b)));

                    //do
                    //{
                    h += Root.GOLDEN_RATIO;
                    h %= 1;
                    //} while (h > 0.15 && h < 0.525);
                }

                //hexBox1.ScrollTo(0);
                hexBox1.Invalidate();

                Bridge.ShowInfo(rin.IType, rin.Info);
            }
            else
            {
                if (!(e.Node is InfoNode))
                {
                    return;
                }
                InfoNode inode = (InfoNode)e.Node;

                TreeNode root = e.Node;
                do
                {
                    root = root.Parent;
                } while (root.Level > 0);

                if (!(root is RootInfoNode))
                {
                    return;
                }

                RootInfoNode rin = (RootInfoNode)root;
                if (fileloaded != rin.FilePath)
                {
                    if (!File.Exists(rin.FilePath))
                    {
                        throw new FileNotFoundException();
                    }

                    hexBox1.ReadFile(rin.FilePath);
                    fileloaded = rin.FilePath;
                }

                Color ghost = Color.FromArgb(0xDD, 0xDD, 0xDD);
                foreach (InfoNode irn in inode.Parent.Nodes)
                {
                    hexBox1.Highlights.Add(new HexBoxLib.Highlight((int)irn.DataStart, (int)irn.DataEnd, ghost));
                }

                hexBox1.Highlights.Add(new HexBoxLib.Highlight((int)inode.DataStart, (int)inode.DataEnd, inode.HighlightColor));
                hexBox1.ScrollTo((int)(inode.DataStart >> 4));
                hexBox1.Invalidate();

                //foreach (Panel p in infopanels)
                //    p.Visible = false;

                //switch (inode.IType)
                //{
                //    case InfoType.Generic:
                //        lblInfoGenericTitle.Text = ((GenericInfo)inode.Info).Title;
                //        txtInfoGenericBody.Text = ((GenericInfo)inode.Info).Body;
                //        pInfoGeneric.Visible = true;
                //        break;
                //}

                Bridge.ShowInfo(inode.IType, inode.Info);
            }
        }
Пример #12
0
        public Main()
        {
            InitializeComponent();

            imglTree.Images.Add("null", Properties.Resources.tree_null);
            imglTree.Images.Add("file", Properties.Resources.tree_file);
            imglTree.Images.Add("image", Properties.Resources.tree_img);
            imglTree.Images.Add("info", Properties.Resources.tree_info);
            imglTree.Images.Add("error", Properties.Resources.tree_error);
            imglTree.Images.Add("binary", Properties.Resources.tree_binary);
            imglTree.Images.Add("block", Properties.Resources.tree_block_blue);          //Regular data block
            imglTree.Images.Add("block-orange", Properties.Resources.tree_block_orange); //Data block that could not be accounted for
            imglTree.Images.Add("block-red", Properties.Resources.tree_block_red);       //Data block that has been marked for deletion
            imglTree.Images.Add("block-purple", Properties.Resources.tree_block_purple); //Most significant data block(s), ie. image data
            imglTree.Images.Add("block-trueblue", Properties.Resources.tree_block_trueblue);
            imglTree.Images.Add("int", Properties.Resources.tree_int);
            imglTree.Images.Add("byte", Properties.Resources.tree_byte);
            imglTree.Images.Add("str", Properties.Resources.tree_str);
            imglTree.Images.Add("unknown", Properties.Resources.tree_unknown);

            imgInfo.Resize += delegate(object sender, EventArgs e)
            {
                if (imgInfo.Image == null)
                {
                    return;
                }

                if (imgInfo.Width > imgInfo.Image.Width &&
                    imgInfo.Height > imgInfo.Image.Height)
                {
                    imgInfo.SizeMode = PictureBoxSizeMode.CenterImage;
                }
                else
                {
                    imgInfo.SizeMode = PictureBoxSizeMode.Zoom;
                }
            };

            //tree.KeyDown += delegate
            //{
            //    RootInfoNode rin = new RootInfoNode("Generic root", "FileOptics.exe", null);
            //    Bridge.AddRootNode(rin);
            //    Bridge.AppendNode(new InfoNode("PE", InfoType.None, null, DataType.Useless, 0x00, 0x53) { HighlightColor = Color.Red }, rin);
            //};

            foreach (Control c in splitContainer2.Panel1.Controls)
            {
                if (c.Name.StartsWith("pInfo"))
                {
                    infopanels.Add((Panel)c);
                    c.Visible = false;
                    c.Dock    = DockStyle.Fill;
                }
            }

            this.Shown += delegate
            {
                this.Invoke((Action) delegate
                {
                    using (Startup start = new Startup())
                    {
                        start.ShowDialog();
                        if (start.Canceled)
                        {
                            this.Close();
                        }
                    }
                });
            };

            this.AllowDrop = true;
            this.DragOver += delegate(object sender, DragEventArgs e)
            { e.Effect = (e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.All : DragDropEffects.None); };
            this.DragDrop += delegate(object sender, DragEventArgs e)
            {
                if (!e.Data.GetDataPresent(DataFormats.FileDrop))
                {
                    return;
                }

                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

                BackgroundWorker bg = new BackgroundWorker();

                //this.BeginInvoke((Action)delegate
                bg.DoWork += delegate
                {
                    if (files.Length != 1)
                    {
                        MessageBox.Show("Please only drop one file at a time!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        return;
                    }

                    List <int> valid       = new List <int>();
                    byte[]     magicbuffer = new byte[0x10];
                    int        read        = 0;

                    FileStream fs    = null;
                    string     fname = Path.GetFileName(files[0]);
                    try
                    {
                        fs = File.Open(files[0], FileMode.Open, FileAccess.Read, FileShare.Read);
                    }
                    catch (IOException ex)
                    {
                        if (!ex.Message.Contains("used by another process"))
                        {
                            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return;
                        }

                        if (MessageBox.Show("The file could not be write-locked, would you like to make a temporary copy and read that instead?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != System.Windows.Forms.DialogResult.Yes)
                        {
                            return;
                        }

                        byte[]        hash = NayukiSHA256.Calculate(Encoding.ASCII.GetBytes(files[0]));
                        StringBuilder sb   = new StringBuilder(hash.Length * 2);
                        foreach (byte b in hash)
                        {
                            sb.Append(b.ToString("X2"));
                        }

                        string newf = Root.LocalAppData + sb.ToString() + ".temp";
                        File.Copy(files[0], newf);
                        files[0] = newf;

                        fs = File.Open(files[0], FileMode.Open, FileAccess.Read, FileShare.Read);
                    }

                    //using (FileStream fs = File.Open(files[0], FileMode.Open, FileAccess.Read, FileShare.Read))
                    try
                    {
                        if (fs.Length < 1)
                        {
                            return;
                        }
                        if ((read = fs.Read(magicbuffer, 0, magicbuffer.Length)) < 1)
                        {
                            return;
                        }

                        for (int i = 0; i < Root.ModuleAttribs.Count; i++)
                        {
                            if (fs.Length < Root.ModuleAttribs[i].MinFileSize)
                            {
                                continue;
                            }

                            if (Root.ModuleAttribs[i].Magic != null && Root.ModuleAttribs[i].Magic.Length > 0 && Root.ModuleAttribs[i].Magic.Length <= magicbuffer.Length)
                            {
                                int j = 0;
                                for (; j < Root.ModuleAttribs[i].Magic.Length; j++)
                                {
                                    if (Root.ModuleAttribs[i].Magic[j] != magicbuffer[j])
                                    {
                                        break;
                                    }
                                }

                                if (j < Root.ModuleAttribs[i].Magic.Length)
                                {
                                    continue;
                                }
                            }

                            fs.Seek(0, SeekOrigin.Begin);
                            if (Root.Modules[i].CanRead(fs))
                            {
                                valid.Add(i);
                            }
                        }

                        //StringBuilder sb = new StringBuilder();
                        //foreach (int i in valid)
                        //    sb.AppendLine(Root.ModuleAttribs[i].Name);
                        //MessageBox.Show(sb.ToString(), "Valid Modules", MessageBoxButtons.OK, MessageBoxIcon.Information);

                        this.Invoke((Action) delegate
                        {
                            if (valid.Count < 1)
                            {
                                MessageBox.Show("No modules that were able to read the specified file could be found.", "Unsupported Format", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                            }
                            else if (valid.Count > 1)
                            {
                                MessageBox.Show("More than one applicable module.", "NYI", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                            }
                            else
                            {
                                fs.Seek(0, SeekOrigin.Begin);
                                RootInfoNode root = new RootInfoNode(fname, files[0], Root.Modules[valid[0]])
                                {
                                    ImageKey = "file", SelectedImageKey = "file"
                                };
                                Root.Modules[valid[0]].Read(root, fs);
                                Bridge.AddRootNode(root);
                            }
                        });
                    }
                    finally
                    {
                        if (fs != null)
                        {
                            fs.Close();
                            fs.Dispose();
                        }
                    }
                };
                //});
                bg.RunWorkerAsync();
            };
        }