// ＡＣ成分のハフマン符号化＆０のランレングス圧縮＆ジグザグ変換
// OnMemory版は#define ONMEM

#include "_jpeglib.h"
#include "jpeg.h"

int m(HuffAC(JDATA(p),short suv[],HUFFMAN hufftbl[ACLEN][ACBIT]))
// suv : Y/U/Vいずれかの成分の量子化ブロックデータ（全部）
// hufftbl : HuffAC_Y/HuffAC_UVのいずれか
{
int len;  // ０の数
int ret=0; // =0はWarning回避のため
int i;
short dat; // 0でないデータ
unshort ZRL,ZRLlen;
	// ACハフマンテーブルの特殊値（可変）
	ZRL   =hufftbl[15][0].code;
	ZRLlen=hufftbl[15][0].len; // ZRL記録に必要なビット数
	//printf("ZRL:");
	//print0b(ZRLlen,ZRL);
	//printf("\n");
	
	len=0;
	for (i=1;i<JWV*JWU;i++) { // i=0はDCなので飛ばす
		dat=suv[_zigzag[i]];
		if (dat==0) { // ０の数を数える
			len++; // 数えるだけ
		} else { // 0でないデータ
			unshort ac; // 0でないデータ(signedにするとbit15が符号になり誤動作する)
			int bits=16; // 符号化に必要なビット数
			
			// 16個以上０が続いていた時はZRLを出力する
			while (len>=16) {
				//printf("[ZRL]");
				ret=m(BitOut(p,ZRL,ZRLlen));
				#ifndef ONMEM
				if (ret) return(ret);
				#endif
				len-=16;
			}
			
			// 符号化に必要なビット数を求める
			if (dat<0) { // 値が負の時の処理
				// 16-上位から数え０のビットが出てくるまでのビット数
				dat--; // さらに-1してから
				ac=dat;
				//printf("ddc=%d:%b,",ac,ac);
				while ((signed short)(ac)<0) { // bit15=1
					ac<<=1;
					bits--;
				}
				//printf("-(%d)",bits);
			} else { // 値が正の時の処理
				// 16-上位から数え１のビットが出てくるまでのビット数
				ac=dat;
				//printf("ddc=%d:%b,",ac,ac);
				while ((signed short)(ac)>=0) { // bit15=0
					ac<<=1;
					bits--;
				}
				//printf("+(%d)",bits);
			}
			// 値をそのままハフマン符号化
			//printf("Huff=");
			//print0b(-hufftbl[len][bits].len,hufftbl[len][bits].code);
			ret=m(BitOut(p,hufftbl[len][bits].code,hufftbl[len][bits].len)); // 符号語を記録
			#ifndef ONMEM
			if (!ret) {
			#endif
				//printf("/Dat=");
				//print0b(-bits,dat);
				ret=m(BitOut(p,dat,bits)); // 値を記録
			#ifndef ONMEM
			}
			if (ret) return(ret);
			#endif
			//printf("\n");
			len=0; // 値を出したら0は数え直し
		}
	}
	if (len>0) { // 以後、ブロック終わりまで0が続く
		unshort EOB,EOBlen;
		EOB   =hufftbl[0][0].code;
		EOBlen=hufftbl[0][0].len;  // EOB記録に必要なビット数
		ret=m(BitOut(p,EOB,EOBlen)); // 値を記録
		//printf("EOB:");
		//print0b(EOBlen,EOB);
		//printf("\n");
	}
	return(ret);
}
