//------------------------------------------------------------------------
// JPEGヘッダーの解釈
// X68版から、ヘッダー読み込みに特化したもの
//------------------------------------------------------------------------

#include "jpeg.h"
#include "libs.h"
#import "gConsole.h"
#include <stdio.h>

#define	BUFSZ	2048

//------------------------------------------------------------------------

static int fgetw(FILE *fp)
// 単純16bit入力
// return : >=0:読み込み値 , EOF:error
{
int c;
	c=fgetc(fp)<<8;
	c|=fgetc(fp);
	return(ferror(fp)? EOF:c);
}

//------------------------------------------------------------------------

static int SkipSegment(FILE *fp,int *size,UByte buff[BUFSZ],int fdisp,int fcomm)
// 処理しないセグメントを読み飛ばす
{
int sz1,sz,c;
	c=fgetw(fp); // マーカーの読みだし
	switch (c) {
		case EOF: // エラー
			return(EOF);
		default: // その他のセグメント
			if ((c&0xff00)!=0xff00) return(EOF); // マーカーがおかしい
			if (fdisp) {
				if (c==APP0) nslog(@"APP0");
				else nslog(@"MAKER=$%04x",c);
			}
		case COM:// コメントセグメントは複数回出てくることもある
			*size=sz1=fgetw(fp)-2; // テーブル長
			do { // 本体
				if (sz1>BUFSZ) sz=BUFSZ; else sz=sz1;
				if (fread(buff,1,sz,fp)!=sz) {
					nslog(@"ファイルが読めません");
					return(EOF-1); // エラー
				}
				if (c==COM && fcomm) { // コメント表示
					int i;
					for (i=0;i<sz;i++) {
						if (buff[i]!=0) nslog(@"%c",buff[i]);
					}
				}
				sz1-=sz;
			} while (sz1>0);
			if (c==COM && fcomm) nslog(@"");
			break;
		case SOF15:
		case SOF14:
		case SOF13:
			nslog(@"基本DCT以外:SOF%d",13+c-SOF13);
			c=SOF13;
			goto L2;
		case SOF11:
		case SOF10:
		case SOF9:
			nslog(@"基本DCT以外:SOF%d",9+c-SOF9);
			c=SOF9;
			goto L2;
		case SOF7:
		case SOF6:
		case SOF5:
			nslog(@"基本DCT以外:SOF%d",5+c-SOF5);
			c=SOF5;
			goto L2;
		case SOF3:
		case SOF2:
		case SOF1:// ＤＣＴフレームヘッダー
			nslog(@"基本DCT以外:SOF%d",c-SOF1);
			c=SOF1;
		case SOF0:// 基本ＤＣＴフレームヘッダー
			// 最初のフレームヘッダーに基本情報が入っているようである
			nslog(@"基本DCT");
		L2:;
		case SOS: // スキャンヘッダー
		case DRI: // リスタートインターバル
		case DQT: // 量子化テーブル　：複数回来ることもある
		case DHT: // ハフマンテーブル：複数回来ることもある
			*size=fgetw(fp)-2; // テーブル長
		case SOI: // 全体の先頭（これにはサイズはない）
			break;
	}
	return(c); // >=0
}

//------------------------------------------------------------------------

// JPEGヘッダー解釈
// 一部手抜き（フレームヘッダーとスキャンヘッダーの識別番号対応をさせてない＝格納順に依存している）
int jpegHeader(FILE *fp,int *wx,int *wy,int fdisp,int fcomm)
{
int size,c;
#ifdef DEBUG
	fdisp=YES;
#endif
	UByte buff[BUFSZ];
	BOOL fframeHeader=YES;
	// SOIの確認
	if ((c=fgetw(fp))==EOF) return(PIC_READERR);
	if (c!=SOI) {
		// MACバイナリヘッダー付きJPEG対応
		// バイナリヘッダーは読み飛ばす
		while ((c=fgetc(fp))!=EOF) {
			if (c==JPGMAKHED) {
				if ((c=fgetc(fp))==EOF) break;
				if (c==(SOI&0xff)) {
					if (fdisp) nslog(@"MACバイナリヘッダー付き");
					goto HEAD;
				}
			}
		}
		nslog(@"このファイルはＪＰＥＧではありません");
		return(PIC_NO_PIC);
	}
  HEAD:;
	fseek(fp,-2,SEEK_CUR); // SOIまで戻す
	do {
	    c=SkipSegment(fp,&size,buff,fdisp,fcomm);
	    switch (c) {
		    case EOF:
				nslog(@"マーカーが異常です");
				return(PIC_DATA_ILLEGAL);

			case SOI:
				if (fdisp) nslog(@"SOI");
				nslog(@"SOI");
				break;
			
		    case SOS: // スキャンヘッダー
				nslog(@"SOS");
				#if 0
				unchar scan[]={
					 3		// 成分数(Y/U/V) / 白黒化で1
					,0,0x00	// YのハフマンテーブルはDCは0,ACは0
					,1,0x11	// UのハフマンテーブルはDCは1,ACは1（白黒時はなし）
					,2,0x11	// VのハフマンテーブルはDCは1,ACは1（白黒時はなし）
					,0		// 基本DCTでは未使用（固定値）
					,63		// 基本DCTでは未使用（固定値）
					,0		// 基本DCTでは未使用（固定値）
				};
				#endif
				if (fdisp) {
					nslog(@"スキャンヘッダー(%d)",size);
				}
		    case DRI: // リスタートインターバル定義
				nslog(@"DRI"); goto L1;
		    case DQT: // 量子化テーブル
				nslog(@"DQT"); goto L1;
		    case DHT: // ハフマンテーブル
				nslog(@"DHT");
		    	// 読み込むだけで、情報の吸い上げはしない
			L1:;
				fread(buff,size,1,fp);
				break;

			case SOF1:
			case SOF5:
			case SOF9:
			case SOF13:
				if (fdisp) nslog(@"SOF1〜15フレームヘッダー(%d)",size);
		    case SOF0:	// フレームヘッダー
				// 最初のフレームヘッダーに基本情報が入っているようである
				if (fframeHeader) {
					#if 0
					unchar frame[] = {
						 8		// サンプル精度:8bit固定
						,0,0	// line数(H,L順)
						,0,0	// １ライン数当たりのサンプル数＝xドット数(H,L順)
						,3		// 成分数:YUV=3 / 白黒化で1
						// 4:1:1の設定
						,0,0x22,0	// Yの識別子は0,サンプリングは水平2,垂直2,量子化テーブルは0
						// 白黒化では以下がない
						,1,0x11,1	// Uの識別子は1,サンプリングは水平1,垂直1,量子化テーブルは1
						,2,0x11,1	// Yの識別子は2,サンプリングは水平1,垂直1,量子化テーブルは1
					};
					#endif
					if (fdisp) nslog(@"SOFフレームヘッダー(%d)",size);
					fread(buff,size,1,fp);	// 読みは全部
					*wy=rd68w(&buff[1]); // 68フォーマット
					*wx=rd68w(&buff[3]); // 68フォーマット
					fframeHeader=NO;
				} else {
					// 2つ目以降は読みとばす
					// サイスがわからないので
#ifdef DEBUG
					for (int i=0;i<size;i++) {
						fprintf(stdout,"%02x,",fgetc(fp));
					}
					fprintf(stdout,"\n");
#else
					while (size-->0) fgetc(fp);
#endif
				}
				break;
	    } // switch
	} while (c!=SOS);
	//
	if (ferror(fp)) return(PIC_READERR);
	if (fdisp) nslog(@"データ本体位置=$%lx",ftell(fp));
	return(PIC_OK);
}

//------------------------------------------------------------------------
