/// <summary>Decompress the LZW-compressed <see cref="Stream"/> <paramref name="source"/> into the <paramref name="output"/>, returning the number of bytes decompressed.</summary> /// <param name="source">The <see cref="Stream"/> to decompress from.</param> /// <param name="output">The byte array to write into.</param> /// <param name="start">The first byte offset in <paramref name="output"/> to write into.</param> /// <param name="count">The number of bytes in <paramref name="source"/> to write to at a maximum.</param> /// <returns>The number of bytes written.</returns> public static int Decompress(Stream source, byte[] output, int start, int count) { var bits = new BitStream(source); int offset = start, end = start + count; int tokenBits = 9; // Number of bits in a token. int endToken = 0x1FF; // Last token to cause an increase in the bits. int currentToken = 0x0102; // First undefined token. int[] tokenOffsets = new int[4096]; // Indexes into output for each token. int[] tokenLengths = new int[4096]; // Byte length of each token. while (offset < end) { int token = bits.ReadLSB(tokenBits); if (token == 0x101) { break; } else if (token == 0x100) { tokenBits = 9; endToken = 0x1FF; currentToken = 0x0102; } else { int tokenLength; // Size of the token in bytes. if (token > 0xFF) { if (token >= currentToken) throw new InvalidDataException("LZW decompression encountered out-of-range token."); tokenLength = tokenLengths[token] + 1; int writeLength = tokenLength; int tokenOffset = tokenOffsets[token]; if (end - offset < writeLength) writeLength = end - offset; for (int index = 0; index < writeLength; index++) output[offset++] = output[tokenOffset++]; } else { tokenLength = 1; output[offset++] = (byte)token; } if (currentToken > endToken && tokenBits < 12) { tokenBits++; endToken = (endToken << 1) + 1; } if (currentToken <= endToken) { tokenOffsets[currentToken] = offset - tokenLength; tokenLengths[currentToken] = tokenLength; currentToken++; } } } return offset - start; }
/// <summary>Decompress the LZW-compressed <see cref="Stream"/> <paramref name="source"/> into the <paramref name="output"/>, returning the number of bytes decompressed.</summary> /// <param name="source">The <see cref="Stream"/> to decompress from.</param> /// <param name="output">The byte array to write into.</param> /// <param name="start">The first byte offset in <paramref name="output"/> to write into.</param> /// <param name="count">The number of bytes in <paramref name="source"/> to write to at a maximum.</param> /// <returns>The number of bytes written.</returns> public static int Decompress(Stream source, byte[] output, int start, int count) { var bits = new BitStream(source); int offset = start, end = start + count; int tokenBits = 9; // Number of bits in a token. int endToken = 0x1FF; // Last token to cause an increase in the bits. int currentToken = 0x0102; // First undefined token. int[] tokenOffsets = new int[4096]; // Indexes into output for each token. int[] tokenLengths = new int[4096]; // Byte length of each token. while (offset < end) { int token = bits.ReadLSB(tokenBits); if (token == 0x101) { break; } else if (token == 0x100) { tokenBits = 9; endToken = 0x1FF; currentToken = 0x0102; } else { int tokenLength; // Size of the token in bytes. if (token > 0xFF) { if (token >= currentToken) { throw new InvalidDataException("LZW decompression encountered out-of-range token."); } tokenLength = tokenLengths[token] + 1; int writeLength = tokenLength; int tokenOffset = tokenOffsets[token]; if (end - offset < writeLength) { writeLength = end - offset; } for (int index = 0; index < writeLength; index++) { output[offset++] = output[tokenOffset++]; } } else { tokenLength = 1; output[offset++] = (byte)token; } if (currentToken > endToken && tokenBits < 12) { tokenBits++; endToken = (endToken << 1) + 1; } if (currentToken <= endToken) { tokenOffsets[currentToken] = offset - tokenLength; tokenLengths[currentToken] = tokenLength; currentToken++; } } } return(offset - start); }