summaryrefslogtreecommitdiff
path: root/docview/src/lzwdecompress.pas
diff options
context:
space:
mode:
authorGraeme Geldenhuys <graemeg@gmail.com>2013-04-10 00:09:29 +0100
committerGraeme Geldenhuys <graemeg@gmail.com>2013-04-10 00:09:29 +0100
commitd24464c8646ffd19e9b02de93626dd20054e2da5 (patch)
treeafaaf3caa81c9d15084d03be62b3f8f57d3444d8 /docview/src/lzwdecompress.pas
parentde7e463e6210c28b56ba853ec2c2fdfd404a7a1f (diff)
parent6fa2f7ef71b16815e64e6ff547c9fcd6562be87b (diff)
downloadfpGUI-d24464c8646ffd19e9b02de93626dd20054e2da5.tar.xz
Merge branch 'release-1.0'
Diffstat (limited to 'docview/src/lzwdecompress.pas')
-rw-r--r--docview/src/lzwdecompress.pas263
1 files changed, 263 insertions, 0 deletions
diff --git a/docview/src/lzwdecompress.pas b/docview/src/lzwdecompress.pas
new file mode 100644
index 00000000..0ebba38c
--- /dev/null
+++ b/docview/src/lzwdecompress.pas
@@ -0,0 +1,263 @@
+{
+ fpGUI - Free Pascal GUI Toolkit
+
+ Copyright (C) 2006 - 2013 See the file AUTHORS.txt, included in this
+ distribution, for details of the copyright.
+
+ See the file COPYING.modifiedLGPL, included in this distribution,
+ for details about redistributing fpGUI.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Description:
+ LZW decompression code for uncompressing IPF bitmaps.
+}
+
+unit LZWDecompress;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ SysUtils, types;
+
+procedure LZWDecompressBlock( pbInput: pByte;
+ number_bytes: LongWord;
+ pbOutput: PBYTE;
+ Var bytesOut: LongWord;
+ Var FinalCode: byte );
+
+Implementation
+
+(*
+/********************************************************************
+ * *
+ * LZW decompression *
+ * *
+ *******************************************************************/
+
+/*
+ * This is based on code (W) by Peter Fitzsimmons, pfitz@ican.net.
+ * His liner notes in the original:
+ * has its roots in a June 1990
+ * DDJ article "LZW REVISITED", by Shawn M. Regan
+ * --=>revision history<=--
+ * 1 lzw.c 21-Aug-96,2:24:36,`PLF' ;
+ * 2 lzw.c 24-Aug-96,2:27:24,`PLF' wip
+ *
+ * The code has been modified to take the input not from an
+ * open file, but from any memory region. For this, a double
+ * pointer is used, which must be passed to LZWDecompressBlock.
+ * I've also added a few comments for clarity.
+ *
+ * Ported to Sibyl Pascal by Aaron Lawrence
+ * Variables renamed etc to make things clearer.
+ */
+*)
+// -- Stuff for LZW decompression -- */
+const INIT_BITS = 9;
+const MAX_BITS = 12; //PLF Tue 95-10-03 02:16:56*/
+const HASHING_SHIFT = MAX_BITS - 8;
+
+{if MAX_BITS == 15
+const TABLE_SIZE 36768
+#elif MAX_BITS == 14
+const TABLE_SIZE 18041
+#elif MAX_BITS == 13
+const TABLE_SIZE 9029
+#else}
+// For max_bits = 12:
+const TABLE_SIZE = 5021;
+
+const CLEAR_TABLE = 256;
+const TERMINATOR = 257;
+const FIRST_CODE = 258;
+
+function MaxValNBits( N: word ): word;
+begin
+ Result:= ( 1 shl n ) - 1;
+end;
+
+var
+ prefix_code: array[ 0..TABLE_SIZE ] of longword;
+ append_character: array[ 0..TABLE_SIZE ] of Byte;
+ decode_stack: array[ 0..10000 ] of byte;
+ bitsPerCode: longint;
+ maxDictionaryCode: longint;
+
+(*
+ * decode_string:
+ *
+ *)
+function decode_string( buffer: PByte; code: longword ): PByte;
+var
+ i: longint;
+begin
+ i:= 0;
+
+ while Code > 255 do
+ begin
+ buffer^:= append_character[ Code ];
+ inc( Buffer );
+ code:= prefix_code[ code ];
+
+ inc( i );
+ if i > High( decode_stack ) then
+ assert( false, 'Out of space decompressing bitmap!' );
+ end;
+
+ buffer^ := code;
+ Result:= buffer;
+end;
+
+(*
+ * input_code:
+ * this function reads in bytes from the input
+ * stream.
+ *)
+
+var
+ bytes_out: longword = 0;
+ input_bit_count: longword = 0;
+ input_bit_buffer: longword = 0;
+
+// I think this simply reads the next bitsPerCode bits of the input data
+// returning the resulting code.
+function input_code( var pbInput: PBYTE; bytes_to_read: longword ): longword;
+var
+ return_value: longword;
+begin
+ while input_bit_count <= 24 do
+ begin
+ if bytes_out <= bytes_to_read then
+ begin
+ input_bit_buffer:= input_bit_buffer
+ or
+ ( ( longword( pbInput^ ) shl (24 - input_bit_count) ) );
+ inc( pbInput );
+ end
+ else
+ input_bit_buffer:= input_bit_buffer
+ or
+ ( longword( 0 ) shl ( 24 - input_bit_count ) );
+ inc( bytes_out );
+ inc( input_bit_count, 8 );
+ end;
+
+ return_value:= input_bit_buffer shr (32 - bitsPerCode);
+ input_bit_buffer:= input_bit_buffer shl bitsPerCode;
+ dec( input_bit_count, bitsPerCode );
+
+ if bytes_out > bytes_to_read then
+ begin
+ // flush static vars and quit */
+ bytes_out:= 0;
+ input_bit_count:= 0;
+ input_bit_buffer:= 0;
+ Result:= TERMINATOR;
+ end
+ else
+ Result:= return_value;
+end;
+
+// LZWDecompressBlock:
+// this takes one of the INF bitmap blocks
+// and decompresses it using LZW algorithms.
+
+procedure LZWDecompressBlock( pbInput: pByte;
+ number_bytes: LongWord;
+ pbOutput: PBYTE;
+ Var bytesOut: LongWord;
+ Var FinalCode: byte );
+var
+ nextAvailableCode: LongWord;
+ currentCode: LongWord;
+ lastCode: LongWord;
+ character: longword;
+ clear_flag: boolean;
+ theString: pByte;
+begin
+ clear_flag:= true;
+
+ nextAvailableCode:= FIRST_CODE;
+ bitsPerCode:= INIT_BITS;
+ maxDictionaryCode:= MaxValNBits( bitsPerCode );
+
+ bytesOut:= 0;
+ input_bit_count:= 0;
+ input_bit_buffer:= 0;
+
+ // read the first code from input
+ currentCode:= input_code( pbInput, number_bytes );
+ while currentCode <> TERMINATOR do
+ begin
+ if clear_flag then
+ begin
+ clear_flag:= false;
+ lastCode:= currentCode;
+ character:= currentCode;
+
+ pbOutput^:= currentCode;
+ inc( pbOutput );
+ FinalCode:= currentCode;
+ inc( BytesOut );
+ end
+ else if currentCode = CLEAR_TABLE then
+ begin
+ clear_flag:= true;
+ nextAvailableCode:= FIRST_CODE;
+ bitsPerCode:= INIT_BITS;
+ maxDictionaryCode:= MaxValNBits( bitsPerCode );
+ end
+ else
+ begin
+ if currentCode >= nextAvailableCode then
+ begin
+ decode_stack[ 0 ]:= character;
+ theString:= decode_string( Addr( decode_stack[ 1 ] ),
+ lastCode );
+ end
+ else
+ theString:= decode_string( Addr( decode_stack[ 0 ] ),
+ currentCode );
+
+ character:= longword( theString^ );
+ while theString >= Addr( decode_stack[ 0 ] ) do
+ begin
+ FinalCode:= theString^;
+
+ pbOutput^:= theString^;
+ inc( pbOutput );
+ dec( TheString );
+
+ inc( BytesOut );
+ end;
+
+ if nextAvailableCode <= maxDictionaryCode then
+ begin
+ prefix_code[ nextAvailableCode ]:= lastCode;
+ append_character[ nextAvailableCode ]:= character;
+
+ inc( nextAvailableCode );
+
+ if ( nextAvailableCode = maxDictionaryCode ) and ( bitsPerCode < MAX_BITS ) then
+ begin
+ // expand dictionary
+ inc( bitsPerCode );
+ maxDictionaryCode:= MaxValNBits( bitsPerCode );
+ end;
+ end;
+
+ lastCode:= currentCode;
+ end;
+
+ // Read next code from input
+ currentCode:= input_code( pbInput, number_bytes );
+ end;
+end;
+
+
+End.