Initial revision
diff --git a/src/lzw/ftlzw.c b/src/lzw/ftlzw.c
new file mode 100644
index 0000000..888df8e
--- /dev/null
+++ b/src/lzw/ftlzw.c
@@ -0,0 +1,462 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftlzw.c                                                                */
+/*                                                                         */
+/*    FreeType support for .Z compressed files.                            */
+/*                                                                         */
+/*  This optional component relies on NetBSD's zopen().  It should mainly  */
+/*  be used to parse compressed PCF fonts, as found with many X11 server   */
+/*  distributions.                                                         */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  Albert Chin-A-Young.                                                   */
+/*                                                                         */
+/*  Based on code in src/gzip/ftgzip.c, Copyright 2004 by                  */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_DEBUG_H
+#include <string.h>
+#include <stdio.h>
+#include "zopen.h"
+
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  LZW_Err_
+#define FT_ERR_BASE    FT_Mod_Err_LZW
+
+#include FT_ERRORS_H
+
+
+#ifdef FT_CONFIG_OPTION_USE_LZW
+
+
+/***************************************************************************/
+/***************************************************************************/
+/*****                                                                 *****/
+/*****                  M E M O R Y   M A N A G E M E N T              *****/
+/*****                                                                 *****/
+/***************************************************************************/
+/***************************************************************************/
+
+/***************************************************************************/
+/***************************************************************************/
+/*****                                                                 *****/
+/*****                   F I L E   D E S C R I P T O R                 *****/
+/*****                                                                 *****/
+/***************************************************************************/
+/***************************************************************************/
+
+#define  FT_LZW_BUFFER_SIZE  4096
+
+  typedef struct FT_LZWFileRec_
+  {
+    FT_Stream   source;         /* parent/source stream        */
+    FT_Stream   stream;         /* embedding stream            */
+    FT_Memory   memory;         /* memory allocator            */
+    s_zstate_t  zstream;        /* lzw input stream            */
+
+    FT_ULong    start;          /* starting position, after .Z header */
+    FT_Byte     input[FT_LZW_BUFFER_SIZE];  /* input buffer */
+
+    FT_Byte     buffer[FT_LZW_BUFFER_SIZE]; /* output buffer */
+    FT_ULong    pos;            /* position in output          */
+    FT_Byte*    cursor;
+    FT_Byte*    limit;
+
+  } FT_LZWFileRec, *FT_LZWFile;
+
+
+  /* check and skip .Z header */
+  static FT_Error
+  ft_lzw_check_header( FT_Stream  stream )
+  {
+    FT_Error  error;
+    FT_Byte   head[2];
+
+
+    if ( FT_STREAM_SEEK( 0 )       ||
+         FT_STREAM_READ( head, 2 ) )
+      goto Exit;
+
+    /* head[0] && head[1] are the magic numbers     */
+    if ( head[0] != 0x1f ||
+         head[1] != 0x9d )
+      error = LZW_Err_Invalid_File_Format;
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  ft_lzw_file_init( FT_LZWFile  zip,
+                    FT_Stream   stream,
+                    FT_Stream   source )
+  {
+    s_zstate_t*  zstream = &zip->zstream;
+    FT_Error     error   = LZW_Err_Ok;
+
+
+    zip->stream = stream;
+    zip->source = source;
+    zip->memory = stream->memory;
+
+    zip->limit  = zip->buffer + FT_LZW_BUFFER_SIZE;
+    zip->cursor = zip->limit;
+    zip->pos    = 0;
+
+    /* check and skip .Z header */
+    {
+      stream = source;
+
+      error = ft_lzw_check_header( source );
+      if ( error )
+        goto Exit;
+
+      zip->start = FT_STREAM_POS();
+    }
+
+    /* initialize internal lzw variable */
+    zinit( zstream );
+
+    zstream->avail_in    = 0;
+    zstream->next_in     = zip->buffer;
+    zstream->zs_in_count = source->size - 2;
+
+    if ( zstream->next_in == NULL )
+      error = LZW_Err_Invalid_File_Format;
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  ft_lzw_file_done( FT_LZWFile  zip )
+  {
+    s_zstate_t*  zstream = &zip->zstream;
+
+
+    /* clear the rest */
+    zstream->next_in   = NULL;
+    zstream->next_out  = NULL;
+    zstream->avail_in  = 0;
+    zstream->avail_out = 0;
+    zstream->total_in  = 0;
+    zstream->total_out = 0;
+
+    zip->memory = NULL;
+    zip->source = NULL;
+    zip->stream = NULL;
+  }
+
+
+  static FT_Error
+  ft_lzw_file_reset( FT_LZWFile  zip )
+  {
+    FT_Stream  stream = zip->source;
+    FT_Error   error;
+
+
+    if ( !FT_STREAM_SEEK( zip->start ) )
+    {
+      s_zstate_t*  zstream = &zip->zstream;
+
+
+      zinit( zstream );
+
+      zstream->avail_in    = 0;
+      zstream->next_in     = zip->input;
+      zstream->total_in    = 0;
+      zstream->avail_out   = 0;
+      zstream->next_out    = zip->buffer;
+      zstream->total_out   = 0;
+      zstream->zs_in_count = zip->source->size - 2;
+
+      zip->limit  = zip->buffer + FT_LZW_BUFFER_SIZE;
+      zip->cursor = zip->limit;
+      zip->pos    = 0;
+    }
+
+    return error;
+  }
+
+
+  static FT_Error
+  ft_lzw_file_fill_input( FT_LZWFile  zip )
+  {
+    s_zstate_t*  zstream = &zip->zstream;
+    FT_Stream    stream  = zip->source;
+    FT_ULong     size;
+
+
+    if ( stream->read )
+    {
+      size = stream->read( stream, stream->pos, zip->input,
+                           FT_LZW_BUFFER_SIZE );
+      if ( size == 0 )
+        return LZW_Err_Invalid_Stream_Operation;
+    }
+    else
+    {
+      size = stream->size - stream->pos;
+      if ( size > FT_LZW_BUFFER_SIZE )
+        size = FT_LZW_BUFFER_SIZE;
+
+      if ( size == 0 )
+        return LZW_Err_Invalid_Stream_Operation;
+
+      FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
+    }
+    stream->pos += size;
+
+    zstream->next_in  = zip->input;
+    zstream->avail_in = size;
+
+    return LZW_Err_Ok;
+  }
+
+
+
+  static FT_Error
+  ft_lzw_file_fill_output( FT_LZWFile  zip )
+  {
+    s_zstate_t*  zstream = &zip->zstream;
+    FT_Error     error   = 0;
+
+
+    zip->cursor        = zip->buffer;
+    zstream->next_out  = zip->cursor;
+    zstream->avail_out = FT_LZW_BUFFER_SIZE;
+
+    while ( zstream->avail_out > 0 )
+    {
+      int  num_read = 0;
+
+
+      if ( zstream->avail_in == 0 )
+      {
+        error = ft_lzw_file_fill_input( zip );
+        if ( error )
+          break;
+      }
+
+      num_read = zread( zstream );
+
+      if ( num_read == -1 && zstream->zs_in_count == 0 )
+      {
+        zip->limit = zstream->next_out;
+        if ( zip->limit == zip->cursor )
+          error = LZW_Err_Invalid_Stream_Operation;
+        break;
+      }
+      else if ( num_read == -1 )
+        break;
+      else
+        zstream->avail_out -= num_read;
+    }
+
+    return error;
+  }
+
+
+  /* fill output buffer; `count' must be <= FT_LZW_BUFFER_SIZE */
+  static FT_Error
+  ft_lzw_file_skip_output( FT_LZWFile  zip,
+                           FT_ULong    count )
+  {
+    FT_Error  error = LZW_Err_Ok;
+    FT_ULong  delta;
+
+
+    for (;;)
+    {
+      delta = (FT_ULong)( zip->limit - zip->cursor );
+      if ( delta >= count )
+        delta = count;
+
+      zip->cursor += delta;
+      zip->pos    += delta;
+
+      count -= delta;
+      if ( count == 0 )
+        break;
+
+      error = ft_lzw_file_fill_output( zip );
+      if ( error )
+        break;
+    }
+
+    return error;
+  }
+
+
+  static FT_ULong
+  ft_lzw_file_io( FT_LZWFile  zip,
+                  FT_ULong    pos,
+                  FT_Byte*    buffer,
+                  FT_ULong    count )
+  {
+    FT_ULong  result = 0;
+    FT_Error  error;
+
+
+    /* Teset inflate stream if we're seeking backwards.        */
+    /* Yes, that is not too efficient, but it saves memory :-) */
+    if ( pos < zip->pos )
+    {
+      error = ft_lzw_file_reset( zip );
+      if ( error )
+        goto Exit;
+    }
+
+    /* skip unwanted bytes */
+    if ( pos > zip->pos )
+    {
+      error = ft_lzw_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
+      if ( error )
+        goto Exit;
+    }
+
+    if ( count == 0 )
+      goto Exit;
+
+    /* now read the data */
+    for (;;)
+    {
+      FT_ULong  delta;
+
+
+      delta = (FT_ULong)( zip->limit - zip->cursor );
+      if ( delta >= count )
+        delta = count;
+
+      FT_MEM_COPY( buffer, zip->cursor, delta );
+      buffer      += delta;
+      result      += delta;
+      zip->cursor += delta;
+      zip->pos    += delta;
+
+      count -= delta;
+      if ( count == 0 )
+        break;
+
+      error = ft_lzw_file_fill_output( zip );
+      if ( error )
+        break;
+    }
+
+  Exit:
+    return result;
+  }
+
+
+/***************************************************************************/
+/***************************************************************************/
+/*****                                                                 *****/
+/*****            L Z W   E M B E D D I N G   S T R E A M              *****/
+/*****                                                                 *****/
+/***************************************************************************/
+/***************************************************************************/
+
+  static void
+  ft_lzw_stream_close( FT_Stream  stream )
+  {
+    FT_LZWFile  zip    = (FT_LZWFile)stream->descriptor.pointer;
+    FT_Memory   memory = stream->memory;
+
+
+    if ( zip )
+    {
+      /* finalize lzw file descriptor */
+      ft_lzw_file_done( zip );
+
+      FT_FREE( zip );
+
+      stream->descriptor.pointer = NULL;
+    }
+  }
+
+
+  static FT_ULong
+  ft_lzw_stream_io( FT_Stream  stream,
+                    FT_ULong   pos,
+                    FT_Byte*   buffer,
+                    FT_ULong   count )
+  {
+    FT_LZWFile  zip = (FT_LZWFile)stream->descriptor.pointer;
+
+
+    return ft_lzw_file_io( zip, pos, buffer, count );
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stream_OpenLZW( FT_Stream  stream,
+                     FT_Stream  source )
+  {
+    FT_Error    error;
+    FT_Memory   memory = source->memory;
+    FT_LZWFile  zip;
+
+
+    FT_ZERO( stream );
+    stream->memory = memory;
+
+    if ( !FT_NEW( zip ) )
+    {
+      error = ft_lzw_file_init( zip, stream, source );
+      if ( error )
+      {
+        FT_FREE( zip );
+        goto Exit;
+      }
+
+      stream->descriptor.pointer = zip;
+    }
+
+    stream->size  = 0x7FFFFFFFL;  /* don't know the real size! */
+    stream->pos   = 0;
+    stream->base  = 0;
+    stream->read  = ft_lzw_stream_io;
+    stream->close = ft_lzw_stream_close;
+
+  Exit:
+    return error;
+  }
+
+#include "zopen.c"
+
+
+#else  /* !FT_CONFIG_OPTION_USE_LZW */
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stream_OpenLZW( FT_Stream  stream,
+                      FT_Stream  source )
+  {
+    FT_UNUSED( stream );
+    FT_UNUSED( source );
+
+    return LZW_Err_Unimplemented_Feature;
+  }
+
+
+#endif /* !FT_CONFIG_OPTION_USE_LZW */
+
+
+/* END */
diff --git a/src/lzw/rules.mk b/src/lzw/rules.mk
new file mode 100644
index 0000000..73ce718
--- /dev/null
+++ b/src/lzw/rules.mk
@@ -0,0 +1,70 @@
+#
+# FreeType 2 LZW support configuration rules
+#
+
+
+# Copyright 2004 by
+# Albert Chin-A-Young.
+#
+# Based on src/lzw/rules.mk, Copyright 2002 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+
+# LZW driver directory
+#
+LZW_DIR := $(SRC_DIR)/lzw
+
+
+# compilation flags for the driver
+#
+LZW_COMPILE := $(FT_COMPILE) $I$(subst /,$(COMPILER_SEP),$(LZW_DIR))
+
+
+# LZW support sources (i.e., C files)
+#
+LZW_DRV_SRC := $(LZW_DIR)/ftlzw.c \
+               $(LZW_DIR)/zopen.c
+
+# LZW support headers
+#
+LZW_DRV_H := $(LZW_DIR)/zopen.h
+
+
+# LZW driver object(s)
+#
+#   LZW_DRV_OBJ_M is used during `multi' builds
+#   LZW_DRV_OBJ_S is used during `single' builds
+#
+LZW_DRV_OBJ_M := $(OBJ_DIR)/ftlzw.$O
+LZW_DRV_OBJ_S := $(OBJ_DIR)/ftlzw.$O
+
+# LZW support source file for single build
+#
+LZW_DRV_SRC_S := $(LZW_DIR)/ftlzw.c
+
+
+# LZW support - single object
+#
+$(LZW_DRV_OBJ_S): $(LZW_DRV_SRC_S) $(LZW_DRV_SRC) $(FREETYPE_H) $(LZW_DRV_H)
+	$(LZW_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(LZW_DRV_SRC_S))
+
+
+# LZW support - multiple objects
+#
+$(OBJ_DIR)/%.$O: $(LZW_DIR)/%.c $(FREETYPE_H) $(LZW_DRV_H)
+	$(LZW_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(LZW_DRV_OBJ_S)
+DRV_OBJS_M += $(LZW_DRV_OBJ_M)
+
+
+# EOF
diff --git a/src/lzw/zopen.c b/src/lzw/zopen.c
new file mode 100644
index 0000000..76715ae
--- /dev/null
+++ b/src/lzw/zopen.c
@@ -0,0 +1,399 @@
+/*	$NetBSD: zopen.c,v 1.8 2003/08/07 11:13:29 agc Exp $	*/
+
+/*-
+ * Copyright (c) 1985, 1986, 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis and James A. Woods, derived from original
+ * work by Spencer Thomas and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ *
+ * Copyright (c) 2004
+ *	Albert Chin-A-Young.
+ *
+ * Modified to work with FreeType's PCF driver.
+ *
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)zopen.c	8.1 (Berkeley) 6/27/93";
+#else
+static char rcsid[] = "$NetBSD: zopen.c,v 1.8 2003/08/07 11:13:29 agc Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*-
+ * fcompress.c - File compression ala IEEE Computer, June 1984.
+ *
+ * Compress authors:
+ *		Spencer W. Thomas	(decvax!utah-cs!thomas)
+ *		Jim McKie		(decvax!mcvax!jim)
+ *		Steve Davies		(decvax!vax135!petsd!peora!srd)
+ *		Ken Turkowski		(decvax!decwrl!turtlevax!ken)
+ *		James A. Woods		(decvax!ihnp4!ames!jaw)
+ *		Joe Orost		(decvax!vax135!petsd!joe)
+ *
+ * Cleaned up and converted to library returning I/O streams by
+ * Diomidis Spinellis <dds@doc.ic.ac.uk>.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if 0
+static char_type magic_header[] =
+	{ 0x1f, 0x9d };		/* 1F 9D */
+#endif
+
+#define	BIT_MASK	0x1f		/* Defines for third byte of header. */
+#define	BLOCK_MASK	0x80
+
+/*
+ * Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
+ * a fourth header byte (for expansion).
+ */
+#define	INIT_BITS 9			/* Initial number of bits/code. */
+
+#define	MAXCODE(n_bits)	((1 << (n_bits)) - 1)
+
+/* Definitions to retain old variable names */
+#define	fp		zs->zs_fp
+#define	state		zs->zs_state
+#define	n_bits		zs->zs_n_bits
+#define	maxbits		zs->zs_maxbits
+#define	maxcode		zs->zs_maxcode
+#define	maxmaxcode	zs->zs_maxmaxcode
+#define	htab		zs->zs_htab
+#define	codetab		zs->zs_codetab
+#define	hsize		zs->zs_hsize
+#define	free_ent	zs->zs_free_ent
+#define	block_compress	zs->zs_block_compress
+#define	clear_flg	zs->zs_clear_flg
+#define	offset		zs->zs_offset
+#define	in_count	zs->zs_in_count
+#define	buf_len		zs->zs_buf_len
+#define	buf		zs->zs_buf
+#define	stackp		zs->u.r.zs_stackp
+#define	finchar		zs->u.r.zs_finchar
+#define	code		zs->u.r.zs_code
+#define	oldcode		zs->u.r.zs_oldcode
+#define	incode		zs->u.r.zs_incode
+#define	roffset		zs->u.r.zs_roffset
+#define	size		zs->u.r.zs_size
+#define	gbuf		zs->u.r.zs_gbuf
+
+/*
+ * To save much memory, we overlay the table used by compress() with those
+ * used by decompress().  The tab_prefix table is the same size and type as
+ * the codetab.  The tab_suffix table needs 2**BITS characters.  We get this
+ * from the beginning of htab.  The output stack uses the rest of htab, and
+ * contains characters.  There is plenty of room for any possible stack
+ * (stack used to be 8000 characters).
+ */
+
+#define	htabof(i)	htab[i]
+#define	codetabof(i)	codetab[i]
+
+#define	tab_prefixof(i)	codetabof(i)
+#define	tab_suffixof(i)	((char_type *)(htab))[i]
+#define	de_stack	((char_type *)&tab_suffixof(1 << BITS))
+
+#define	CHECK_GAP 10000		/* Ratio check interval. */
+
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define	FIRST	257		/* First free entry. */
+#define	CLEAR	256		/* Table clear output code. */
+
+/*-
+ * Algorithm from "A Technique for High Performance Data Compression",
+ * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
+ *
+ * Algorithm:
+ * 	Modified Lempel-Ziv method (LZW).  Basically finds common
+ * substrings and replaces them with a variable size code.  This is
+ * deterministic, and can be done on the fly.  Thus, the decompression
+ * procedure needs no input table, but tracks the way the table was built.
+ */
+
+#if 0
+static int
+zclose(s_zstate_t *zs)
+{
+	free(zs);
+	return (0);
+}
+#endif
+
+/*-
+ * Output the given code.
+ * Inputs:
+ * 	code:	A n_bits-bit integer.  If == -1, then EOF.  This assumes
+ *		that n_bits =< (long)wordsize - 1.
+ * Outputs:
+ * 	Outputs code to the file.
+ * Assumptions:
+ *	Chars are 8 bits long.
+ * Algorithm:
+ * 	Maintain a BITS character long buffer (so that 8 codes will
+ * fit in it exactly).  Use the VAX insv instruction to insert each
+ * code in turn.  When the buffer fills up empty it and start over.
+ */
+
+static char_type rmask[9] =
+	{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
+
+/*
+ * Decompress read.  This routine adapts to the codes in the file building
+ * the "string" table on-the-fly; requiring no table to be stored in the
+ * compressed file.  The tables used herein are shared with those of the
+ * compress() routine.  See the definitions above.
+ */
+static int
+zread(s_zstate_t *zs)
+{
+	unsigned int count;
+
+	if (in_count == 0)
+		return -1;
+	if (zs->avail_out == 0)
+		return 0;
+
+	count = zs->avail_out;
+	switch (state) {
+	case S_START:
+		state = S_MIDDLE;
+		break;
+	case S_MIDDLE:
+		goto middle;
+	case S_EOF:
+		goto eof;
+	}
+
+	maxbits = *(zs->next_in);	/* Set -b from file. */
+	zs->avail_in--;
+	zs->next_in++;
+	zs->total_in++;
+	in_count--;
+	block_compress = maxbits & BLOCK_MASK;
+	maxbits &= BIT_MASK;
+	maxmaxcode = 1L << maxbits;
+	if (maxbits > BITS) {
+		return -1;
+	}
+	/* As above, initialize the first 256 entries in the table. */
+	maxcode = MAXCODE(n_bits = INIT_BITS);
+	for (code = 255; code >= 0; code--) {
+		tab_prefixof(code) = 0;
+		tab_suffixof(code) = (char_type) code;
+	}
+	free_ent = block_compress ? FIRST : 256;
+
+	finchar = oldcode = getcode(zs);
+	if (oldcode == -1)		/* EOF already? */
+		return 0;		/* Get out of here */
+
+	/* First code must be 8 bits = char. */
+	*(zs->next_out)++ = (unsigned char)finchar;
+	zs->total_out++;
+	count--;
+	stackp = de_stack;
+
+	while ((code = getcode(zs)) > -1) {
+		if ((code == CLEAR) && block_compress) {
+			for (code = 255; code >= 0; code--)
+				tab_prefixof(code) = 0;
+			clear_flg = 1;
+			free_ent = FIRST - 1;
+			if ((code = getcode(zs)) == -1)
+				/* O, untimely death! */
+				break;
+		}
+		incode = code;
+
+		/* Special case for KwKwK string. */
+		if (code >= free_ent) {
+			*stackp++ = finchar;
+			code = oldcode;
+		}
+
+		/* Generate output characters in reverse order. */
+		while (code >= 256) {
+			*stackp++ = tab_suffixof(code);
+			code = tab_prefixof(code);
+		}
+		*stackp++ = finchar = tab_suffixof(code);
+
+		/* And put them out in forward order.  */
+middle:		
+		if (stackp == de_stack)
+			continue;
+
+		do {
+			if (count-- == 0) {
+				return zs->avail_out;
+			}
+			*(zs->next_out)++ = *--stackp;
+			zs->total_out++;
+		} while (stackp > de_stack);
+
+		/* Generate the new entry. */
+		if ((code = free_ent) < maxmaxcode) {
+			tab_prefixof(code) = (unsigned short) oldcode;
+			tab_suffixof(code) = finchar;
+			free_ent = code + 1;
+		}
+
+		/* Remember previous code. */
+		oldcode = incode;
+	}
+	/* state = S_EOF; */
+eof:	return (zs->avail_out - count);
+}
+
+/*-
+ * Read one code from the standard input.  If EOF, return -1.
+ * Inputs:
+ * 	stdin
+ * Outputs:
+ * 	code or -1 is returned.
+ */
+static code_int
+getcode(s_zstate_t *zs)
+{
+	code_int gcode;
+	int r_off, bits;
+	char_type *bp;
+
+	bp = gbuf;
+	if (clear_flg > 0 || roffset >= size || free_ent > maxcode) {
+		/*
+		 * If the next entry will be too big for the current gcode
+		 * size, then we must increase the size.  This implies reading
+		 * a new buffer full, too.
+		 */
+		if (free_ent > maxcode) {
+			n_bits++;
+			if (n_bits == maxbits)	/* Won't get any bigger now. */
+				maxcode = maxmaxcode;
+			else
+				maxcode = MAXCODE(n_bits);
+		}
+		if (clear_flg > 0) {
+			maxcode = MAXCODE(n_bits = INIT_BITS);
+			clear_flg = 0;
+		}
+		if ( zs->avail_in < (unsigned int)n_bits && in_count > (long)n_bits ) {
+			memcpy (buf, zs->next_in, zs->avail_in);
+			buf_len = zs->avail_in;
+			zs->avail_in = 0;
+			return -1;
+		}
+		if (buf_len) {
+			memcpy (gbuf, buf, buf_len);
+			memcpy (gbuf + buf_len, zs->next_in,
+				n_bits - buf_len);
+			zs->next_in += n_bits - buf_len;
+			zs->avail_in -= n_bits - buf_len;
+			buf_len = 0;
+			zs->total_in += n_bits;
+			size = n_bits;
+			in_count -= n_bits;
+		} else {
+			if (in_count > n_bits) {
+				memcpy (gbuf, zs->next_in, n_bits);
+				zs->next_in += n_bits;
+				zs->avail_in -= n_bits;
+				zs->total_in += n_bits;
+				size = n_bits;
+				in_count -= n_bits;
+			} else {
+				memcpy (gbuf, zs->next_in, in_count);
+				zs->next_in += in_count;
+				zs->avail_in -= in_count;
+				zs->total_in += in_count;
+				size = in_count;
+				in_count = 0;
+			}
+		}
+		roffset = 0;
+		/* Round size down to integral number of codes. */
+		size = (size << 3) - (n_bits - 1);
+	}
+	r_off = roffset;
+	bits = n_bits;
+
+	/* Get to the first byte. */
+	bp += (r_off >> 3);
+	r_off &= 7;
+
+	/* Get first part (low order bits). */
+	gcode = (*bp++ >> r_off);
+	bits -= (8 - r_off);
+	r_off = 8 - r_off;	/* Now, roffset into gcode word. */
+
+	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
+	if (bits >= 8) {
+		gcode |= *bp++ << r_off;
+		r_off += 8;
+		bits -= 8;
+	}
+
+	/* High order bits. */
+	gcode |= (*bp & rmask[bits]) << r_off;
+	roffset += n_bits;
+
+	return (gcode);
+}
+
+static void
+zinit(s_zstate_t *zs)
+{
+	memset(zs, 0, sizeof (s_zstate_t));
+
+	maxbits = BITS;			/* User settable max # bits/code. */
+	maxmaxcode = 1 << maxbits;	/* Should NEVER generate this code. */
+	hsize = HSIZE;			/* For dynamic table sizing. */
+	free_ent = 0;			/* First unused entry. */
+	block_compress = BLOCK_MASK;
+	clear_flg = 0;
+	state = S_START;
+	roffset = 0;
+	size = 0;
+}
diff --git a/src/lzw/zopen.h b/src/lzw/zopen.h
new file mode 100644
index 0000000..483b47e
--- /dev/null
+++ b/src/lzw/zopen.h
@@ -0,0 +1,114 @@
+/*	$NetBSD: zopen.c,v 1.8 2003/08/07 11:13:29 agc Exp $	*/
+
+/*-
+ * Copyright (c) 1985, 1986, 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis and James A. Woods, derived from original
+ * work by Spencer Thomas and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ *
+ * Copyright (c) 2004
+ *	Albert Chin-A-Young.
+ *
+ * Modified to work with FreeType's PCF driver.
+ *
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)zopen.c	8.1 (Berkeley) 6/27/93";
+#else
+static char rcsid[] = "$NetBSD: zopen.c,v 1.8 2003/08/07 11:13:29 agc Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+
+#define	BITS		16		/* Default bits. */
+#define	HSIZE		69001		/* 95% occupancy */
+
+/* A code_int must be able to hold 2**BITS values of type int, and also -1. */
+typedef long code_int;
+typedef long count_int;
+
+typedef unsigned char char_type;
+
+typedef enum {
+	S_START, S_MIDDLE, S_EOF
+} zs_enum;
+
+typedef struct {
+	unsigned char *next_in;
+	unsigned int avail_in;
+	unsigned long total_in;
+
+	unsigned char *next_out;
+	unsigned int avail_out;
+	unsigned long total_out;
+
+	zs_enum zs_state;		/* State of computation */
+	int zs_n_bits;			/* Number of bits/code. */
+	int zs_maxbits;			/* User settable max # bits/code. */
+	code_int zs_maxcode;		/* Maximum code, given n_bits. */
+	code_int zs_maxmaxcode;		/* Should NEVER generate this code. */
+	count_int zs_htab [HSIZE];
+	unsigned short zs_codetab [HSIZE];
+	code_int zs_hsize;		/* For dynamic table sizing. */
+	code_int zs_free_ent;		/* First unused entry. */
+	/*
+	 * Block compression parameters -- after all codes are used up,
+	 * and compression rate changes, start over.
+	 */
+	int zs_block_compress;
+	int zs_clear_flg;
+	int zs_offset;
+	long zs_in_count;		/* Remaining uncompressed bytes. */
+	char_type zs_buf_len;
+	char_type zs_buf[BITS];		/* Temporary buffer if we need
+					   to read more to accumulate
+					   n_bits. */
+	union {
+		struct {
+			char_type *zs_stackp;
+			int zs_finchar;
+			code_int zs_code, zs_oldcode, zs_incode;
+			int zs_roffset, zs_size;
+			char_type zs_gbuf[BITS];
+		} r;			/* Read parameters */
+	} u;
+} s_zstate_t;
+
+static code_int getcode(s_zstate_t *);
+#if 0
+static int      zclose(s_zstate_t *);
+#endif
+static void     zinit(s_zstate_t *);
+static int      zread(s_zstate_t *);