/// ＡＩＧライブラリ　FAT32アクセス関数
//	Copyright (C) 2000 by AIG-SOFT

#ifndef	__AIG_FAT32__
#define	__AIG_FAT32__	1	/* ヘッダー読み込みシンボル */

#include <stddef.h>	// size_t/SEEK_*
#include <stdio.h>	// FILE
#include "defines.h"
#include "u2stbl.h"

// 定数
#define	FAT1BYTE	(sizeof(unlong))	// 1FATの大きさ＝FAT32:32bit=unlong
#define	FATS1SEC	(fp->sec1/FAT1BYTE)	// １セクターに収まるFATの個数
#define	ENDofFATs	(0x0fffffff)		// FATリンクの最後を示すデータ

#define	SEC1MAX		(2048)		// サポートする１セクタ最大サイズ
#define	CLU1MAX		(SEC1MAX*8)	// サポートする１クラスタ最大サイズ
	// 本当は可変にしたいのだが、ワークの確保・解放が非常に面倒なので固定にした

#define	FLONGCHECK	(BIT7)	// FILES32(,,fstart)に指定して、ロングファイル名での比較を指示する

#define	SYM_UNGETC	(0xffff)	// ungetc32で戻されたデータがない印

/* パス名要素長(EOS付き) */
#define MAXDRIVE32		(1+1+1+1)		// LUN+ID+':'+00
#define	MAXLONGFILE		(255+1)			// ロングファイル名の最大長+EOS（バイト数）
#define	MAXLONGFILE32		MAXLONGFILE
#define MAXFILE32		MAXLONGFILE		// 念のためロングファイル名にしておく
#define	MAXFNAME32		MAXLONGFILE		// 念のためロングファイル名にしておく
#define MAXSHORTFILE		(8+1)			// ショートファイル名
#define MAXSHORTFILE32		MAXSHORTFILE
#define MAXEXT32		(1+3+1)			/* '.'+拡張子+00 */
#define MAXPATH32		MAXLONGFILE		// ロングファイル名長は、実はドライブ＋ディレクトリ＋ファイル名（拡張子も含む）の長さ
#define MAXDIR32		MAXLONGFILE		// 同上
#define	MAXDRVDIR32		(MAXDRIVE32-1+MAXDIR32)	/* ドライブ名＋ディレクトリ */
#define MAXFILEEXT32		MAXLONGFILE		// ロングファイル名
#define MAXSHORTFILEEXT		(MAXSHORTFILE-1+MAXEXT32)	// ショートファイル名+'.'+拡張子+00
#define MAXLONGFILEEXT		MAXLONGFILE		// ロングファイル名
#define MAXSHORTFILEEXT32	MAXSHORTFILEEXT
#define MAXLONGFILEEXT32	MAXLONGFILEEXT

// FILE32構造体
// メンバー名はdosclass.hのそれに出来るだけ合わせる（プログラムの修正が少なくなるように）
typedef struct {
	// ユーザー公開部分
	// ファイル属性（Windowsが作成）
	unshort	mtime;		// 作成時刻
	unshort	mdate;		// 作成日付
	unshort	adate;		// 最終アクセス日付
	unshort	time;		// 更新時刻(FAT16=X68と同じ)
	unshort	date;		// 更新日付(FAT16=X68と同じ)
	unlong	filelen;	// ファイルサイズ(FAT32でも最大2Gまで)
	unchar	atr;		// ファイル属性
	unchar	m10ms;		// 作成時刻10ms
	// ドライブ情報（SCSIハード依存）
	unlong	scsiid;		// 上位１６ビット＝LUN/下位１６ビット＝ID(←ユーザー指定)
	//
	// 以下の項目はユーザー非公開
	unshort	sec1;		// １セクターサイズ(←READCAP)
	unshort	blksz;		// S_READEXT()のブロック長引数(←sec1)
	unlong	allsec;		// 有効全セクター数
	// FAT情報（フォーマットから）
	unshort	clu1sec;	// １クラスタのセクター数
	unshort	clu1byte;	// １クラスタのバイト数
	unlong	secfat1;	// FAT1先頭セクター=FAT1[0〜]テーブルのあるセクター
	short	fats;		// FAT数
	unlong	fatsecs;	// 1FATセクター数
	unlong	secdata;	// データ領域先頭セクター
	unlong	fatroot;	// ルートディレクトリのFAT番号
	unlong	fbufffat;	// fbuff[]に読み込まれているFATの先頭番号（高速処理用）
	// VFAT用
	// VFATは後ろから前に辿ればよいはずだが、
	// ＦＡＴは後ろから前には辿れないので、先頭を別途記録しておく。
	// この情報が有効なのは、そのファイルのVFATが有効な時のみ。
	unlong	VFATTop;	// 今参照しているファイルのVFAT先頭FAT
	unshort	OfstVFATTop;	// そのクラスタ内でのオフセット;buff[..]がそのデータ
	// ファイル名
	unchar	name0[8+3+1];	    // ファイル名 拡張子+EOS（ディレクトリエントリそのもの+EOS）
	unchar	name[MAXFILEEXT];   // ファイル名.拡張子+EOS（name0[]を普通のファイル名形式に変換した物）
	unchar	lname[MAXLONGFILE]; // ロングファイルファイル名+EOS
	// １ファイル配置情報	// FAT番号＝クラスタ番号である
	unlong	topfat;		// このファイルの先頭FAT番号
	unlong	filefat;	// 読み込み中FAT番号（ファイル）
	unlong	fat;		// 読み込み中FAT番号（ディレクトリ）
	unlong	oldfat;		// １回前に読み込んだFAT番号
	unshort	ofst;		// このクラスタ内での読み込み位置(buff[ofst])
	unlong	seek;		// 読み込み位置（ファイル先頭からの相対位置）
	int	error;		// 直前に発生したエラーの番号
	unchar	*next;		// 検索時の継続用 : buffの中のアドレス＝&buff[..]
	unchar	nextfname[MAXLONGFILE];	// 検索時の継続用 : 検索対象ファイル名
	unchar	nextatr;	// 検索時の継続用 : ファイル属性
	// ワーク
	unshort	ungetc;		// ungetc32()で戻す１バイトを記録する
				// 0x00〜0xff=戻されているデータ
				// SYM_UNGETC=戻されているデータなし
	unchar	buff[CLU1MAX];	// ファイル読み込みバッファーアドレス:クラスタサイズ
	unlong	fbuff[SEC1MAX/FAT1BYTE];
				// FAT読み込みバッファーアドレス:セクター単位
				// fbuff[sec1/FAT1BYTE]
				// unlongだけど80形式なのでそのまま使ってはいけない
} FILE32;

#ifdef	__cplusplus
extern	"C" {
#endif
// 危険な関数でもあるのでプロトタイプ宣言のみ
// 全ての関数が実装済みではない
	// 外部関数
	// 標準関数に似てるけどfopenが―寸違う。
	// その理由は、ファイル構造体の実体がＯＳ内部に有るのではなくユーザーが与えるから。
	int	fopen32(const unchar *,const char *,FILE32 *);
	int	vfopen32(const unchar *,const char *,FILE32 *);
	int	fseek32(FILE32 *,long ,int );
	int	fclose32(FILE32 *);
	size_t	fread32(void *,size_t ,size_t ,FILE32 *);
	int	fgetc32(FILE32 *);
	char	*fgets32(char *, int , FILE32 *);
	long	ftell32(FILE32 *);
	void	rewind32(FILE32 *);
	int	feof32(FILE32 *);
	int	ferror32(FILE32 *);
	void	clearerr32(FILE32 *);
	long	filelength32(FILE32 *);
	int	ungetc32(int ,FILE32 *);
	int	fnsplit32(const unchar *,unchar *,unchar *,unchar *,unchar *
									,int ,FILE32 *,int );
	int	vfnsplit32(const unchar *,unchar *,unchar *,unchar *,unchar *
									,int ,FILE32 *,int );
	unchar	*Path2ScsiID(unchar *,unlong *);
	int	strsfn32(unchar *,unchar *,unchar *,unchar *,unchar *);
	int	file_copy32(unchar *,unchar *,unchar *,int,int,int,int,int,int*);
	int	vfile_copy32(unchar *,unchar *,unchar *,int,int,int,int,int,int*);
	int	file_copy_sub32(FILE32 *,FILE *,int,unchar *,int,int,int,int*);
	int	vunlink32(unchar *);
	int	vrmdir32(unchar *);
	int	CHMOD32(unchar *,int);
	int	VCHMOD32(unchar *,int);
	// 内部関数
	unlong	NextFat(FILE32 *,unlong );
	int	CluRead(FILE32 *);
	int	CluWrite(FILE32 *,unlong);
	int	GetDriveInf32(FILE32 *);
	int	_FILES32(FILE32 *,unchar *,int ,int );
	int	_VFILES32(FILE32 *,unchar *,int ,int );
	int	FILES32(FILE32 *,unchar *,int );
	int	NFILES32(FILE32 *);
	int	VFILES32(FILE32 *,unchar *,int );
	int	NVFILES32(FILE32 *);
	unchar	VCalcFnameSum(unchar *);
	void	VGetLongname(unchar *,UniCode *,int);
	int	_DelDirEntry32(FILE32 *);
	int	_DelFatLink32(FILE32 *);
	int	_Delete32(FILE32 *);
	int	_CheckDirEmpty32(unchar *);
	int	_Attrib32(FILE32 *,int);
#ifdef	__cplusplus
}
#endif

// マクロ定義関数
#define	rewind32(fp)		(fseek32(fp,0L,SEEK_SET),clearerr32(fp))
#define	FILES32(fp,path,atr)	_FILES32(fp,path,atr,1)
#define	NFILES32(fp)		_FILES32(fp,"",0,0)
#define	VFILES32(fp,path,atr)	_VFILES32(fp,path,atr,1)
#define	NVFILES32(fp)		_VFILES32(fp,"",0,0)

// ＦＡＴ→セクター変換（内部関数）
#define	Fat2Sec(fp)	(fp->secdata+((fp->fat-fp->fatroot)*fp->clu1sec))

#endif
