/* close an ITS archive */ public void Close() { if (_h.fd != null) { _h.fd.Close(); } _h.fd = null; if (_h.lzx_state != null) { Lzx.LZXteardown(_h.lzx_state); } _h.lzx_state = null; _h.cache_blocks = null; _h.cache_block_indices = null; }
/* 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); }
/* 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); }