/// <summary>
        /// Parses the pice table and creates a list of PieceDescriptors.
        /// </summary>
        /// <param name="fib">The FIB</param>
        /// <param name="tableStream">The 0Table or 1Table stream</param>
        public PieceTable(FileInformationBlock fib, VirtualStream tableStream)
        {
            //Read the bytes of complex file information
            byte[] bytes = new byte[fib.lcbClx];
            tableStream.Read(bytes, 0, (int)fib.lcbClx, (int)fib.fcClx);

            this.Pieces = new List <PieceDescriptor>();
            this.FileCharacterPositions = new Dictionary <int, int>();
            this.CharacterPositions     = new Dictionary <int, int>();

            int  pos  = 0;
            bool goon = true;

            while (goon)
            {
                try
                {
                    byte type = bytes[pos];

                    //check if the type of the entry is a piece table
                    if (type == 2)
                    {
                        Int32 lcb = System.BitConverter.ToInt32(bytes, pos + 1);

                        //read the piece table
                        byte[] piecetable = new byte[lcb];
                        Array.Copy(bytes, pos + 5, piecetable, 0, piecetable.Length);

                        //count of PCD _entries
                        int n = (lcb - 4) / 12;

                        //and n piece descriptors
                        for (int i = 0; i < n; i++)
                        {
                            //read the CP
                            int   indexCp = i * 4;
                            Int32 cp      = System.BitConverter.ToInt32(piecetable, indexCp);

                            //read the next CP
                            int   indexCpNext = (i + 1) * 4;
                            Int32 cpNext      = System.BitConverter.ToInt32(piecetable, indexCpNext);

                            //read the PCD
                            int    indexPcd = ((n + 1) * 4) + (i * 8);
                            byte[] pcdBytes = new byte[8];
                            Array.Copy(piecetable, indexPcd, pcdBytes, 0, 8);
                            PieceDescriptor pcd = new PieceDescriptor(pcdBytes);
                            pcd.cpStart = cp;
                            pcd.cpEnd   = cpNext;

                            //add pcd
                            this.Pieces.Add(pcd);

                            //add positions
                            Int32 f     = (Int32)pcd.fc;
                            Int32 multi = 1;
                            if (pcd.encoding == Encoding.Unicode)
                            {
                                multi = 2;
                            }
                            for (int c = pcd.cpStart; c < pcd.cpEnd; c++)
                            {
                                if (!this.FileCharacterPositions.ContainsKey(c))
                                {
                                    this.FileCharacterPositions.Add(c, f);
                                }
                                if (!this.CharacterPositions.ContainsKey(f))
                                {
                                    this.CharacterPositions.Add(f, c);
                                }

                                f += multi;
                            }
                        }
                        int maxCp = this.FileCharacterPositions.Count;
                        this.FileCharacterPositions.Add(maxCp, fib.fcMac);
                        this.CharacterPositions.Add(fib.fcMac, maxCp);

                        //piecetable was found
                        goon = false;
                    }
                    //entry is no piecetable so goon
                    else if (type == 1)
                    {
                        Int16 cb = System.BitConverter.ToInt16(bytes, pos + 1);
                        pos = pos + 1 + 2 + cb;
                    }
                    else
                    {
                        goon = false;
                    }
                }
                catch (Exception)
                {
                    goon = false;
                }
            }
        }
        public List <char> GetChars(Int32 fcStart, Int32 fcEnd, VirtualStream wordStream)
        {
            List <char> chars = new List <char>();

            for (int i = 0; i < this.Pieces.Count; i++)
            {
                PieceDescriptor pcd = this.Pieces[i];

                //get the FC end of this piece
                Int32 pcdFcEnd = pcd.cpEnd - pcd.cpStart;
                if (pcd.encoding == Encoding.Unicode)
                {
                    pcdFcEnd *= 2;
                }
                pcdFcEnd += (Int32)pcd.fc;

                if (pcdFcEnd < fcStart)
                {
                    //this piece is before the requested range
                    continue;
                }
                else if (fcStart >= pcd.fc && fcEnd > pcdFcEnd)
                {
                    //requested char range starts at this piece
                    //read from fcStart to pcdFcEnd

                    //get count of bytes
                    int    cb    = pcdFcEnd - fcStart;
                    byte[] bytes = new byte[cb];

                    //read all bytes
                    wordStream.Read(bytes, 0, cb, (Int32)fcStart);

                    //get the chars
                    char[] plainChars = pcd.encoding.GetString(bytes).ToCharArray();

                    //add to list
                    foreach (char c in plainChars)
                    {
                        chars.Add(c);
                    }
                }
                else if (fcStart <= pcd.fc && fcEnd >= pcdFcEnd)
                {
                    //the full piece is part of the requested range
                    //read from pc.fc to pcdFcEnd

                    //get count of bytes
                    int    cb    = pcdFcEnd - (Int32)pcd.fc;
                    byte[] bytes = new byte[cb];

                    //read all bytes
                    wordStream.Read(bytes, 0, cb, (Int32)pcd.fc);

                    //get the chars
                    char[] plainChars = pcd.encoding.GetString(bytes).ToCharArray();

                    //add to list
                    foreach (char c in plainChars)
                    {
                        chars.Add(c);
                    }
                }
                else if (fcStart < pcd.fc && fcEnd >= pcd.fc && fcEnd <= pcdFcEnd)
                {
                    //requested char range ends at this piece
                    //read from pcd.fc to fcEnd

                    //get count of bytes
                    int    cb    = fcEnd - (Int32)pcd.fc;
                    byte[] bytes = new byte[cb];

                    //read all bytes
                    wordStream.Read(bytes, 0, cb, (Int32)pcd.fc);

                    //get the chars
                    char[] plainChars = pcd.encoding.GetString(bytes).ToCharArray();

                    //add to list
                    foreach (char c in plainChars)
                    {
                        chars.Add(c);
                    }

                    break;
                }
                else if (fcStart >= pcd.fc && fcEnd <= pcdFcEnd)
                {
                    //requested chars are completly in this piece
                    //read from fcStart to fcEnd

                    //get count of bytes
                    int    cb    = fcEnd - fcStart;
                    byte[] bytes = new byte[cb];

                    //read all bytes
                    wordStream.Read(bytes, 0, cb, (Int32)fcStart);

                    //get the chars
                    char[] plainChars = pcd.encoding.GetString(bytes).ToCharArray();

                    //set the list
                    chars = new List <char>(plainChars);

                    break;
                }
                else if (fcEnd < pcd.fc)
                {
                    //this piece is beyond the requested range
                    break;
                }
            }
            return(chars);
        }