Пример #1
0
        public static Int64 FetchBytes(ref ChmFileInfo h, ref byte[] buf, UInt64 os, Int64 len)
        {
            Int64 readLen = 0;
            long  cur     = 0;

            if (h.fd == null)
            {
                return(readLen);
            }

            h.mutex.WaitOne();
            cur     = h.fd.Seek((long)os, SeekOrigin.Begin);
            readLen = h.fd.Read(buf, 0, (int)len);
            h.mutex.ReleaseMutex();

            return(readLen);
        }
Пример #2
0
 private ChmFile(string filename)
 {
     _h = new ChmFileInfo();
     _filename = filename;
 }
Пример #3
0
 private ChmFile(string filename)
 {
     _h        = new ChmFileInfo();
     _filename = filename;
 }
Пример #4
0
        /* decompress the block.  must have lzx_mutex. */
        public static Int64 DecompressBlock(ref ChmFileInfo h, UInt64 block, ref byte[] ubuffer)
        {
            byte[] cbuffer    = new byte[h.reset_table.block_len + 6144];
            long   cbufferpos = 0;
            UInt64 cmpStart   = 0;                                  /* compressed start  */
            Int64  cmpLen     = 0;                                  /* compressed len    */
            int    indexSlot;                                       /* cache index slot  */
            uint   lbuffer;                                         /* local buffer ptr  */
            UInt32 blockAlign = (UInt32)(block % h.reset_blkcount); /* reset intvl. aln. */
            UInt32 i;                                               /* local loop index  */

            /* let the caching system pull its weight! */
            if ((int)(block - blockAlign) <= h.lzx_last_block &&
                (int)block >= h.lzx_last_block)
            {
                blockAlign = (uint)((int)block - h.lzx_last_block);
            }

            /* check if we need previous blocks */
            if (blockAlign != 0)
            {
                /* fetch all required previous blocks since last reset */
                for (i = blockAlign; i > 0; i--)
                {
                    UInt32 curBlockIdx = (UInt32)(block - (LONGUINT64)i);

                    /* check if we most recently decompressed the previous block */
                    if (h.lzx_last_block != curBlockIdx)
                    {
                        if ((curBlockIdx % h.reset_blkcount) == 0)
                        {
                            Lzx.LZXreset(h.lzx_state);
                        }

                        indexSlot = (int)((curBlockIdx) % h.cache_num_blocks);
                        if (h.cache_blocks[indexSlot] == null)
                        {
                            h.cache_blocks[indexSlot] = new byte[h.reset_table.block_len];
                        }

                        h.cache_block_indices[indexSlot] = curBlockIdx;
                        lbuffer = (uint)indexSlot;

                        /* decompress the previous block */
                        if (!GetCmpBlockBounds(ref h, curBlockIdx, ref cmpStart, ref cmpLen) ||
                            cmpLen < 0 ||
                            cmpLen > (LONGINT64)h.reset_table.block_len + 6144 ||
                            Storage.FetchBytes(ref h, ref cbuffer, cmpStart, cmpLen) != cmpLen ||
                            Lzx.LZXdecompress(h.lzx_state, ref cbuffer, cbufferpos,
                                              ref h.cache_blocks[lbuffer], 0, (int)cmpLen,
                                              (int)h.reset_table.block_len) != Lzx.DECR_OK)
                        {
                            return((Int64)0);
                        }

                        h.lzx_last_block = (int)curBlockIdx;
                    }
                }
            }
            else
            {
                if ((block % h.reset_blkcount) == 0)
                {
                    Lzx.LZXreset(h.lzx_state);
                }
            }

            /* allocate slot in cache */
            indexSlot = (int)(block % (LONGUINT64)h.cache_num_blocks);
            if (h.cache_blocks[indexSlot] == null)
            {
                h.cache_blocks[indexSlot] = new byte[h.reset_table.block_len];
            }

            h.cache_block_indices[indexSlot] = block;
            lbuffer = (uint)indexSlot;
            ubuffer = h.cache_blocks[lbuffer];

            /* decompress the block we actually want */
            if (!GetCmpBlockBounds(ref h, block, ref cmpStart, ref cmpLen) ||
                Storage.FetchBytes(ref h, ref cbuffer, cmpStart, cmpLen) != cmpLen ||
                Lzx.LZXdecompress(h.lzx_state, ref cbuffer, cbufferpos,
                                  ref h.cache_blocks[lbuffer], 0, (int)cmpLen,
                                  (int)h.reset_table.block_len) != Lzx.DECR_OK)
            {
                return((Int64)0);
            }
            h.lzx_last_block = (int)block;

            /* XXX: modify LZX routines to return the length of the data they
             * decompressed and return that instead, for an extra sanity check.
             */
            return((Int64)h.reset_table.block_len);
        }
Пример #5
0
        /* get the bounds of a compressed block.  return 0 on failure */
        public static bool GetCmpBlockBounds(ref ChmFileInfo h, UInt64 block,
                                             ref UInt64 start, ref Int64 len)
        {
            byte[] buffer = new byte[8];
            uint   remain;
            uint   pos = 0;

            /* for all but the last block, use the reset table */
            if (block < h.reset_table.block_count - 1)
            {
                /* unpack the start address */
                pos    = 0;
                remain = 8;
                if (Storage.FetchBytes(ref h, ref buffer,
                                       (UInt64)h.data_offset
                                       + (UInt64)h.rt_unit.start
                                       + (UInt64)h.reset_table.table_offset
                                       + (UInt64)block * 8,
                                       remain) != remain ||
                    !Unmarshal.ToUInt64(ref buffer, ref pos, ref remain, ref start))
                {
                    return(false);
                }

                /* unpack the end address */
                pos    = 0;
                remain = 8;
                if (Storage.FetchBytes(ref h, ref buffer,
                                       (UInt64)h.data_offset
                                       + (UInt64)h.rt_unit.start
                                       + (UInt64)h.reset_table.table_offset
                                       + (UInt64)block * 8 + 8,
                                       remain) != remain ||
                    !Unmarshal.ToInt64(ref buffer, ref pos, ref remain, ref len))
                {
                    return(false);
                }
            }

            /* for the last block, use the span in addition to the reset table */
            else
            {
                /* unpack the start address */
                pos    = 0;
                remain = 8;
                if (Storage.FetchBytes(ref h, ref buffer,
                                       (UInt64)h.data_offset
                                       + (UInt64)h.rt_unit.start
                                       + (UInt64)h.reset_table.table_offset
                                       + (UInt64)block * 8,
                                       remain) != remain ||
                    !Unmarshal.ToUInt64(ref buffer, ref pos, ref remain, ref start))
                {
                    return(false);
                }

                len = (Int64)h.reset_table.compressed_len;
            }

            /* compute the length and absolute start address */
            len   -= (Int64)start;
            start += h.data_offset + h.cn_unit.start;

            return(true);
        }
Пример #6
0
        /* grab a region from a compressed block */
        public static Int64 DecompressRegion(ref ChmFileInfo h, ref byte[] buf, ulong bufpos, UInt64 start, Int64 len)
        {
            UInt64 nBlock, nOffset;
            UInt64 nLen;
            UInt64 gotLen;

            byte[] ubuffer = null;

            if (len <= 0)
            {
                return((Int64)0);
            }

            /* figure out what we need to read */
            nBlock  = start / h.reset_table.block_len;
            nOffset = start % h.reset_table.block_len;
            nLen    = (LONGUINT64)len;
            if (nLen > (h.reset_table.block_len - nOffset))
            {
                nLen = h.reset_table.block_len - nOffset;
            }

            /* if block is cached, return data from it. */
            h.lzx_mutex.WaitOne();
            h.cache_mutex.WaitOne();
            if (h.cache_block_indices[nBlock % (LONGUINT64)h.cache_num_blocks] == nBlock &&
                h.cache_blocks[nBlock % (LONGUINT64)h.cache_num_blocks] != null)
            {
                Array.Copy(
                    h.cache_blocks[nBlock % (LONGUINT64)h.cache_num_blocks],
                    (int)nOffset,
                    buf,
                    (int)bufpos,
                    (long)nLen);
                h.cache_mutex.ReleaseMutex();
                h.lzx_mutex.ReleaseMutex();

                return((Int64)nLen);
            }
            h.cache_mutex.ReleaseMutex();

            /* data request not satisfied, so... start up the decompressor machine */
            if (!h.lzx_init)
            {
                int window_size = ffs(h.window_size) - 1;
                h.lzx_last_block = -1;
                h.lzx_state      = Lzx.LZXinit(window_size);
                h.lzx_init       = true;
            }

            /* decompress some data */
            gotLen = (UInt64)DecompressBlock(ref h, nBlock, ref ubuffer);
            if (gotLen < nLen)
            {
                nLen = gotLen;
            }
            Array.Copy(ubuffer, (int)nOffset, buf, (int)bufpos, (int)nLen);
            h.lzx_mutex.ReleaseMutex();

            return((Int64)nLen);
        }