public _7z_parser(string filepath)
        {
            //opens xxx.7z passed in parameter
            Console.WriteLine("[7z-parser] specified file: " + filepath);
            archive_file_reader = new BinaryReader(File.Open(filepath, FileMode.Open));
            Console.WriteLine("[7z-parser] reader opened");

            //pretty much self-explanatory, covers "SignatureHeader" section in 7zFormat.txt (line 171~188)
            read_signature_and_archive_version();
            read_StartHeader();

            //Move position of archive_file_reader
            //will be a problem when _NextHeaderOffset is bigger than "long.MaxValue - 32" but.......... it requires a sinle 1EB .7z file if I do math correctly
            //So... this program will break if you have a 1EB .7z file and I don't want to fix this in... foreseeable future
            archive_file_reader.BaseStream.Position += (long)_NextHeaderOffset;

            Property_IDs flag = (Property_IDs)archive_file_reader.ReadByte();

            if (flag == Property_IDs.kHeader)
            {
                read_Header();
            }
            else if (flag == Property_IDs.kEncodedHeader)
            {
                _Encoded_Header = read_Streams_info();
            }
            else
            {
                throw new ParseError("Expected kHeader or kEncodedHeader, but got 0x" + Util.Byte_to_hex_string((byte)flag) + "\n" +
                                     "Stream position = " + archive_file_reader.BaseStream.Position);
            }
        }
        /// <summary>
        /// covers "Header" section in 7zFormat.txt (line 435~457)
        /// </summary>
        private void read_Header()
        {
            Console.WriteLine("[7z-parser] read Header");
            Property_IDs flag = (Property_IDs)archive_file_reader.ReadByte();

            //optional ArchiveProperties
            if (flag == Property_IDs.kArchiveProperties)
            {
                _Archive_Properties = read_Archive_Properties();
                flag = (Property_IDs)archive_file_reader.ReadByte();
            }

            //optional AdditionalStreamsInfo
            if (flag == Property_IDs.kAdditionalStreamsInfo)
            {
                _Additional_Streams_Info = read_Streams_info();
                flag = (Property_IDs)archive_file_reader.ReadByte();
            }

            //optional MainStreamsInfo
            if (flag == Property_IDs.kMainStreamsInfo)
            {
                _Main_Streams_Info = read_Streams_info();
                flag = (Property_IDs)archive_file_reader.ReadByte();
            }

            //Check kEnd
            assert(flag == Property_IDs.kEnd,
                   "Expected kEnd (0x00), but got 0x" + Util.Byte_to_hex_string((byte)flag) + "\n" +
                   "Stream position (decimal) = " + archive_file_reader.BaseStream.Position);
            Console.WriteLine("[7z-parser] read Header complete");
        }
        /// <summary>
        /// covers "PackInfo" section in 7zFormat.txt (line 218~234)
        /// </summary>
        private PackInfo read_Pack_Info()
        {
            Console.WriteLine("[7z-parser] read Pack Info");

            PackInfo pack_info = new PackInfo();

            pack_info.PackPos = read_7z_UInt64();
            Console.WriteLine("PackPos = " + pack_info.PackPos);
            pack_info.NumPackStreams = read_7z_UInt64();
            Console.WriteLine("NumPackStreams = " + pack_info.NumPackStreams);

            Property_IDs flag = (Property_IDs)archive_file_reader.ReadByte();

            //handles optional PackSizes
            if (flag == Property_IDs.kSize)
            {
                Console.WriteLine("read KSize");
                pack_info.PackSizes = new ulong[pack_info.NumPackStreams];
                for (ulong i = 0; i < pack_info.NumPackStreams; i++)
                {
                    pack_info.PackSizes[i] = read_7z_UInt64();
                    Console.WriteLine("PackSizes[" + i + "] = " + pack_info.PackSizes[i]);
                }
                flag = (Property_IDs)archive_file_reader.ReadByte();
            }
            else
            {
                pack_info.PackSizes = null;
            }

            //handles optional PackStreamDigests
            if (flag == Property_IDs.kCRC)
            {
                pack_info.PackStreamDigests = new string[pack_info.NumPackStreams];
                byte[] CRC_in_bytes;
                for (ulong i = 0; i < pack_info.NumPackStreams; i++)
                {
                    CRC_in_bytes = archive_file_reader.ReadBytes(4);
                    Array.Reverse(CRC_in_bytes);
                    pack_info.PackStreamDigests[i] = Util.Bytes_to_CRC_string(CRC_in_bytes);
                }
                flag = (Property_IDs)archive_file_reader.ReadByte();
            }
            else
            {
                pack_info.PackSizes = null;
            }

            //Check kEnd
            assert(flag == Property_IDs.kEnd,
                   "Expected kEnd (0x00), but got 0x" + Util.Byte_to_hex_string((byte)flag) + "\n" +
                   "Stream position (decimal) = " + archive_file_reader.BaseStream.Position);
            Console.WriteLine("[7z-parser] read Pack Info complete");

            return(pack_info);
        }
        /// <summary>
        /// covers "Streams Info" section in 7zFormat.txt (line 341~358)
        /// </summary>
        private StreamsInfo read_Streams_info()
        {
            Console.WriteLine("[7z-parser] read Streams Info");

            StreamsInfo  streams_info = new StreamsInfo();
            Property_IDs flag         = (Property_IDs)archive_file_reader.ReadByte();

            //handles optional PackInfo
            if (flag == Property_IDs.kPackInfo)
            {
                streams_info.packInfo = read_Pack_Info();
                flag = (Property_IDs)archive_file_reader.ReadByte();
            }
            else
            {
                streams_info.packInfo = null;
            }

            //handles optional CodersInfo
            if (flag == Property_IDs.kUnPackInfo)
            {
                streams_info.codersInfo = read_Coders_Info();
                flag = (Property_IDs)archive_file_reader.ReadByte();
            }
            else
            {
                streams_info.codersInfo = null;
            }

            //handles optional PackInfo
            if (flag == Property_IDs.kSubStreamsInfo)
            {
                streams_info.subStreamsInfo = read_SubStreams_info();
                flag = (Property_IDs)archive_file_reader.ReadByte();
            }
            else
            {
                streams_info.subStreamsInfo = null;
            }
            //Check kEnd
            assert(flag == Property_IDs.kEnd,
                   "Expected kEnd (0x00), but got 0x" + Util.Byte_to_hex_string((byte)flag) + "\n" +
                   "Stream position (decimal) = " + archive_file_reader.BaseStream.Position);
            Console.WriteLine("[7z-parser] read Header complete");
            return(streams_info);
        }
        /// <summary>
        /// covers "ArchiveProperties" section in 7zFormat.txt (line 194~204)
        /// </summary>
        private List <ArchiveProperty> read_Archive_Properties()
        {
            List <ArchiveProperty> list = new List <ArchiveProperty>();

            while (true)
            {
                Property_IDs PropertyType = (Property_IDs)archive_file_reader.ReadByte();
                if (PropertyType == Property_IDs.kEnd)
                {
                    return(list);
                }
                ArchiveProperty entry = new ArchiveProperty();
                entry.PropertyType = PropertyType;
                entry.PropertyData = archive_file_reader.ReadBytes((int)read_7z_UInt64()); //might crash with big PropertySize
                Array.Reverse(entry.PropertyData);
                list.Add(entry);

                //debug message
                Console.WriteLine("[7z-parser] archive property type = " + Util.Byte_to_hex_string((byte)entry.PropertyType) +
                                  ", PropertySize = " + entry.PropertyData.Length +
                                  ", PropertyData = " + Util.Bytes_to_hex_string(entry.PropertyData));
            }
        }
        private SubStreamsInfo read_SubStreams_info()
        {
            Console.WriteLine("[7z-parser] read Sub streams info");
            Console.WriteLine("position = 0x" + archive_file_reader.BaseStream.Position.ToString("X"));
            SubStreamsInfo sub_streams_info = new SubStreamsInfo();
            Property_IDs   flag             = (Property_IDs)archive_file_reader.ReadByte();

            //handles optional NumUnPackStream
            if (flag == Property_IDs.kNumUnPackStream)
            {
                sub_streams_info.NumUnPackStreamsInFolders = new ulong[_Additional_Streams_Info.codersInfo.NumFolders];
                for (ulong i = 0; i < _Additional_Streams_Info.codersInfo.NumFolders; i++)
                {
                    sub_streams_info.NumUnPackStreamsInFolders[i] = read_7z_UInt64();
                }
                flag = (Property_IDs)archive_file_reader.ReadByte();
            }

            if (flag == Property_IDs.kSize)
            {
            }

            throw new ParseError("read_SubStreams_info() is not yet implemented");
        }
        /// <summary>
        /// covers "Coders Info" section in 7zFormat.txt (line 281~312)
        /// </summary>
        private CodersInfo read_Coders_Info()
        {
            Console.WriteLine("[7z-parser] read Coders Info");

            CodersInfo   coders_info = new CodersInfo();
            Property_IDs flag        = (Property_IDs)archive_file_reader.ReadByte();

            assert(flag == Property_IDs.kFolder,
                   "Expected kFolder (0x0B), but got 0x" + Util.Byte_to_hex_string((byte)flag) + "\n" +
                   "Stream position (decimal) = " + archive_file_reader.BaseStream.Position);

            //read NumFolders (line 288 in 7zFormat.txt)
            coders_info.NumFolders = read_7z_UInt64();

            //read External (line 289~296 in 7zFormat.txt)
            coders_info.External = archive_file_reader.ReadBoolean();
            Console.WriteLine("External = " + coders_info.External.ToString());
            if (!coders_info.External)
            {
                coders_info.Folders = new Folder[coders_info.NumFolders];
                Console.WriteLine("position = 0x" + archive_file_reader.BaseStream.Position.ToString("X"));
                for (ulong i = 0; i < coders_info.NumFolders; i++)
                {
                    coders_info.Folders[i] = read_Folder();
                }
                Console.WriteLine("position = 0x" + archive_file_reader.BaseStream.Position.ToString("X"));
            }
            else
            {
                coders_info.Folders         = new Folder[0];
                coders_info.DataStreamIndex = read_7z_UInt64();
            }

            //kCodersUnPackSize (line 299 in 7zFormat.txt)
            flag = (Property_IDs)archive_file_reader.ReadByte();
            assert(flag == Property_IDs.kCodersUnPackSize,
                   "Expected kCodersUnPackSize (0x0C), but got 0x" + Util.Byte_to_hex_string((byte)flag) + "\n" +
                   "Stream position (decimal) = " + archive_file_reader.BaseStream.Position);

            //read UnPackSize (line 300~302 in 7zFormat.txt)
            coders_info.UnPackSizes = new List <ulong>();
            foreach (Folder f in coders_info.Folders)
            {
                for (ulong i = 0; i < f.NumOutStreams; i++)
                {
                    coders_info.UnPackSizes.Add(read_7z_UInt64());
                    Console.WriteLine("UnPackSizes: " + coders_info.UnPackSizes.Last());
                }
            }

            //kCRC (line 306 in 7zFormat.txt)
            flag = (Property_IDs)archive_file_reader.ReadByte();
            if (flag == Property_IDs.kCRC)
            {
                coders_info.UnPackDigests = new string[coders_info.NumFolders];
                byte[] CRCbytes;
                for (ulong i = 0; i < coders_info.NumFolders; i++)
                {
                    CRCbytes = archive_file_reader.ReadBytes(4);
                    Array.Reverse(CRCbytes);
                    coders_info.UnPackDigests[i] = Util.Bytes_to_CRC_string(CRCbytes);
                }
                flag = (Property_IDs)archive_file_reader.ReadByte();
            }
            else
            {
                coders_info.UnPackDigests = null;
            }

            //Check kEnd
            assert(flag == Property_IDs.kEnd,
                   "Expected kEnd (0x00), but got 0x" + Util.Byte_to_hex_string((byte)flag) + "\n" +
                   "Stream position (decimal) = " + archive_file_reader.BaseStream.Position);
            Console.WriteLine("[7z-parser] read Coders Info complete");
            return(coders_info);
        }