C言語でビット単位の配列を扱うのはもっとつらいよ

さて、前回のC言語でのライブラリ製作戦略*1に則りLZW圧縮機構を書きなおしていたときのことだ。
以下のようなインターフェイスにした。

///LZWの辞書状態をクリアする。
DKC_EXTERN int WINAPI dkcLZWInit(DKC_LZW *p,
ULONG option,uint32 Signature);

/**
@param ptr[in][out] dkcAllocLZW()で取得したポインタ
@param src[in] 圧縮するためのデータのバッファへのポインタ
@param ssize[in] srcのサイズ
@return edk_EndProcessでdkcAllocLZW()の第一引数で指定したサイズに到達した。
到達した場合はdkcLZWCompressOutput()を呼び出して処理結果を出力すること
*/

DKC_EXTERN int WINAPI dkcLZWCompressStep(DKC_LZW *ptr,
const BYTE *src,size_t ssize);
/**
@param pHeader[in] 内部状態を返す。NULLでもかまわない
@note
pHeaderに入ったデータを参照して今後のプロセスを決めるという戦略をとると良い。
*/

///圧縮した結果をdestに出力する。
DKC_EXTERN int WINAPI dkcLZWCompressGetState(DKC_LZW *ptr,
DKC_LZW_HEADER *pHeader);

DKC_EXTERN int WINAPI dkcLZWCompressOutput(DKC_LZW *ptr,
BYTE *dest,size_t dsize);

さて、ここでdkcLZWCompressOutput()でひとつ疑問が浮かんだ。
「LZWの圧縮した出力結果はビット単位の配列である」
盲点だった。バイト単位の配列での解決方法しか考えていなかった。
このままだと何回もdkcLZWCompressStep()を重ねると圧縮データのビットの幅がずれてしまう。
よって正常に解凍できない。
ここで、以下のアプローチを思いついた。
  • dkcLZWCompressOutput()でどこまでのビットが有効なのか値をバッファ内に一緒に出力する。(問題点:解凍時に圧縮時と同じサイズの作業バッファにしなくてはならない)
  • ビット配列を扱えるライブラリを作成する(既に作成済み)それを出力バッファとしての引数にして後はユーザーに任せる。(ユーザーが分かりにくい)
  • dkcLZWCompressOutput()にどこまでのビットが有効なのか値を出力する引数を付け加える(無難だと思う)
  • dkcLZWCompressOutput()でビット単位になっている端数は切り捨てて次の出力の時にまわす。(最後の最後でビット単位で出力しなければならなくなる。)
さて、zlibはどのような方法でアプローチしていただろうか?lzwと同じような感じ(スマン具体的に説明できない)だった覚えがあるが。
これを調べるのも価値があると思う。*2

*1:http://d.hatena.ne.jp/studiokingyo/20050908

*2:私はこのようにして一流プログラマーのプログラムコーディング思想を探求していくのである。