開発環境 Microsoft Visual C++ 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 Win32 コンソール アプリケーション
プロジェクト名 dumpgif
アプリケーションの種類 コンソール アプリケーション
追加のオプション 空のプロジェクト

参考
GIFフォーマットの詳細 http://www.tohoho-web.com/wwwgif.htm
時雨エノキオプト-アセンブリホール2nd-自作ソフト-GIFデコーダ http://www.geocities.jp/warotarock/asen2ndgif001.html
GIF89a Specification http://www.w3.org/Graphics/GIF/spec-gif89a.txt
LZW and GIF explained http://www.martinreddy.net/gfx/2d/GIF-comp.txt

dumpgif.c
#include <fcntl.h>	// _O_WTEXT
#include <io.h>		// _setmode
#include <stdio.h>	// _fileno
#include <tchar.h>	// TCHAR
#include <Windows.h>
 
#define dprintf(fmt, var) _tprintf(_T(#var)_T("=[")fmt##_T("]\n"), var)
 
#pragma pack(push, 1)
typedef struct {
	BYTE	rgbtRed;
	BYTE	rgbtGreen;
	BYTE	rgbtBlue;
} SRGBTriple;
 
typedef struct {
	char	acSignature[3];
	char	acVersion[3];
	USHORT	usLogicalScreenWidth;
	USHORT	usLogicalScreenHeight;
	struct {
		UCHAR	SizeofGlobalColorTable:	3;	// 00000???
		UCHAR	SortFlag:		1;	// 0000?000
		UCHAR	ColorResolution:	3;	// 0???0000
		UCHAR	GlobalColorTableFlag:	1;	// ?0000000
	} ucbf;	// BitField
	UCHAR	ucBackgroundColorIndex;
	UCHAR	ucPixelAspectRatio;
} SGIFHeader;
 
typedef struct {
	USHORT	usImageLeftPosition;
	USHORT	usImageTopPosition;
	USHORT	usImageWidth;
	USHORT	usImageHeight;
	struct {
		UCHAR	SizeofLocalColorTable:	3;
		UCHAR	Reserved:		2;
		UCHAR	SortFlag:		1;
		UCHAR	InterlaceFlag:		1;
		UCHAR	LocalColorTableFlag:	1;
	} ucbf;
} SImageBlock;
 
typedef struct {
	UCHAR	ucBlockSize;
	struct {
		UCHAR	TransparentColorFlag:	1;
		UCHAR	UserInputFlag:		1;
		UCHAR	DisposalMethod:		3;
		UCHAR	Reserved:		3;
	} ucbf;
	USHORT	usDelayTime;
	UCHAR	ucTransparentColorIndex;
	UCHAR	ucBlockTerminator;
} SGraphicControlExtension;
 
typedef struct {
	UCHAR	ucBlockSize;
	char	acApplicationIdentifier[8];
	char	acApplicationAuthenticationCode[3];
} SApplicationExtension;
#pragma pack(pop)
 
// グローバル変数
static FILE*	g_pFile;		// ファイルポインタ
static UCHAR*	g_pucImageData;		// 画像データ
static int	g_iImageData;		// 画像データのサイズ
static int	g_iImageIndex;		// 画像データの指標
static int	g_aiDicTable[0x1000];	// 辞書テーブル
static int	g_iDicIndex;		// 辞書テーブルの指標
static UCHAR*	g_pucCodeData;		// コード化データ
static int	g_iCodeData;		// コード化データのサイズ
static int	g_iCodeIndex;		// コード化データの指標
static UCHAR	g_ucLZWMinimumCodeSize;	// 最小コードビット数
static int	g_iClearCode;		// クリアコード
static int	g_iEoICode;		// 終了コード
static int	g_iCodeSize;		// コードのビット数
 
// 関数プロトタイプ宣言
void FileRead(void* pvBuffer, size_t sizeCount);
int HexDump(UCHAR* pucBuf, int iBuf);
int ParseBlockData(void);
int ParseColorTable(int iNum);
int ParseGIFHeader(void);
int ParseGraphicControlExtension(void);
int ParseCommentExtension(void);
int ParseApplicationExtension(void);
int ParseImageBlock(void);
int ParseImageData(void);
int LZWDecode(void);
int FetchCodeData(int iCodeSize);
int AddImageData(int iCode);
int AddDicTable(void);
 
int _tmain(int argc, TCHAR* argv[])
{
	TCHAR*		ptcFile;	// ファイル名
	UCHAR		ucLabel;	// ラベル
	int		iStatus;	// 状態
 
	_setmode(_fileno(stdout), _O_WTEXT);
	_setmode(_fileno(stderr), _O_WTEXT);
 
	if (argc != 2) {
		_ftprintf(stderr, _T("usage: dumpgif file\n"));
		return 1;
	}
	ptcFile = argv[1];
 
	// ファイルのオープン
	if (_tfopen_s(&g_pFile, ptcFile, _T("rb")) != 0) {
		_ftprintf(stderr, _T("error: _tfopen_s[%s]\n"), ptcFile);
		return 1;
	}
 
	// GIF Header
	iStatus = ParseGIFHeader();
 
	// Block
	while (iStatus == 0) {
		FileRead(&ucLabel, 1);
		_tprintf(_T("\n*** Block[%#x]\n"), ucLabel);
		switch (ucLabel) {
		case 0x2C:	// Image Block
			iStatus = ParseImageBlock();
			break;
		case 0x21:	// Extension Introducer
			FileRead(&ucLabel, 1);
			_tprintf(_T("Extension[%#x]\n"), ucLabel);
			switch (ucLabel) {
			case 0xF9:	// Graphic Control Extension
				iStatus = ParseGraphicControlExtension();
				break;
			case 0xFE:	// Comment Extension
				iStatus = ParseCommentExtension();
				break;
//			case 0x01:	// Plain Text Extension
//				;
			case 0xFF:	// Application Extension
				iStatus = ParseApplicationExtension();
				break;
			default:
				iStatus = -1;
			}
			break;
		case 0x3B:	// Trailer
			_tprintf(_T("Trailer\n"));
			iStatus = 1;
			break;
		default:
			iStatus = -1;
		}
	}
 
	fclose(g_pFile);
	return 0;
}
 
void FileRead(void* pvBuffer, size_t sizeCount)
{
	if (fread(pvBuffer, 1, sizeCount, g_pFile) != sizeCount) {
		_ftprintf(stderr, _T("error: fread\n"));
		exit(1);
	}
}
 
int HexDump(UCHAR* pucBuf, int iBuf)
{
	int	i;
 
	for (i = 0; i < iBuf; i++) {
		if (i % 16 == 0) {
			_tprintf(_T("%.8x:"), i);
		}
		_tprintf(_T("%.2x%c"), pucBuf[i], _T("   -   -   -   \n")[i % 16]);
	}
	if (i % 16) {
		_tprintf(_T("\n"));
	}
	return 0;
}
 
int ParseBlockData(void)
{
	UCHAR	ucBlockSize;
	UCHAR	aucDataValues[255];
 
	for (;;) {
		FileRead(&ucBlockSize, 1);
		_tprintf(_T("Block Data[%u]\n"), ucBlockSize);
		if (ucBlockSize == 0) {
			break;
		}
		FileRead(aucDataValues, ucBlockSize);
		HexDump(aucDataValues, ucBlockSize);
	}
	return 0;
}
 
int ParseColorTable(int iNum)
{
	SRGBTriple	sct;	// ColorTable
	int		i;
 
	for (i = 0; i < iNum; i++) {
		FileRead(&sct, 3);
		_tprintf(_T("%.2x%.2x%.2x%.2x%c"),
			i, sct.rgbtRed, sct.rgbtGreen, sct.rgbtBlue,
			"       \n"[i % 8]);
	}
	return 0;
}
 
int ParseGIFHeader(void)
{
	SGIFHeader	sgifh;
	int		iNumGCT;
 
	_tprintf(_T("*** GIF Header\n"));
 
	FileRead(&sgifh, 13);
	if (strncmp(sgifh.acSignature, "GIF", 3) != 0) {
		return -1;
	}
	dprintf(_T("%.3S"), sgifh.acSignature);
	dprintf(_T("%.3S"), sgifh.acVersion);
	dprintf(_T("%u"), sgifh.usLogicalScreenWidth);
	dprintf(_T("%u"), sgifh.usLogicalScreenHeight);
	dprintf(_T("%u"), sgifh.ucbf.GlobalColorTableFlag);
	dprintf(_T("%u"), sgifh.ucbf.ColorResolution);
	dprintf(_T("%u"), sgifh.ucbf.SortFlag);
	dprintf(_T("%u"), sgifh.ucbf.SizeofGlobalColorTable);
	dprintf(_T("%u"), sgifh.ucBackgroundColorIndex);
	dprintf(_T("%u"), sgifh.ucPixelAspectRatio);
 
	iNumGCT = 0;
	if (sgifh.ucbf.GlobalColorTableFlag) {
		iNumGCT = 2 << sgifh.ucbf.SizeofGlobalColorTable;
	}
	_tprintf(_T("Global Color Table[%d]\n"), iNumGCT);
	ParseColorTable(iNumGCT);
 
	return 0;
}
 
int ParseGraphicControlExtension(void)
{
	SGraphicControlExtension sgce;
 
	_tprintf(_T("Graphic Control Extension\n"));
 
	FileRead(&sgce, 6);
	dprintf(_T("%u"), sgce.ucBlockSize);
	dprintf(_T("%u"), sgce.ucbf.Reserved);
	dprintf(_T("%u"), sgce.ucbf.DisposalMethod);
	dprintf(_T("%u"), sgce.ucbf.UserInputFlag);
	dprintf(_T("%u"), sgce.ucbf.TransparentColorFlag);
	dprintf(_T("%u"), sgce.usDelayTime);
	dprintf(_T("%u"), sgce.ucTransparentColorIndex);
	dprintf(_T("%#x"), sgce.ucBlockTerminator);
	return 0;
}
 
int ParseCommentExtension(void)
{
	_tprintf(_T("Comment Extension\n"));
 
	return ParseBlockData();
}
 
int ParseApplicationExtension(void)
{
	SApplicationExtension sae;
 
	_tprintf(_T("Application Extension\n"));
 
	FileRead(&sae, 12);
	dprintf(_T("%u"), sae.ucBlockSize);
	dprintf(_T("%.8S"), sae.acApplicationIdentifier);
	dprintf(_T("%.3S"), sae.acApplicationAuthenticationCode);
 
	return ParseBlockData();
}
 
int ParseImageBlock(void)
{
	SImageBlock	sib;
	int		iNumLCT;
 
	_tprintf(_T("Image Block\n"));
 
	FileRead(&sib, 9);
	dprintf(_T("%u"), sib.usImageLeftPosition);
	dprintf(_T("%u"), sib.usImageTopPosition);
	dprintf(_T("%u"), sib.usImageWidth);
	dprintf(_T("%u"), sib.usImageHeight);
	dprintf(_T("%u"), sib.ucbf.LocalColorTableFlag);
	dprintf(_T("%u"), sib.ucbf.InterlaceFlag);
	dprintf(_T("%u"), sib.ucbf.SortFlag);
	dprintf(_T("%u"), sib.ucbf.Reserved);
	dprintf(_T("%u"), sib.ucbf.SizeofLocalColorTable);
	iNumLCT = 0;
	if (sib.ucbf.LocalColorTableFlag) {
		iNumLCT = 2 << sib.ucbf.SizeofLocalColorTable;
	}
	_tprintf(_T("Local Color Table[%d]\n"), iNumLCT);
	ParseColorTable(iNumLCT);
 
	FileRead(&g_ucLZWMinimumCodeSize, 1);
	dprintf(_T("%u"), g_ucLZWMinimumCodeSize);
	g_iClearCode	= 1 << g_ucLZWMinimumCodeSize;
	g_iEoICode	= g_iClearCode + 1;
	g_iCodeSize	= g_ucLZWMinimumCodeSize + 1;
 
	g_iImageData = sib.usImageWidth * sib.usImageHeight;
	g_pucImageData = (UCHAR*)malloc(g_iImageData);
	if (g_pucImageData == NULL) {
		_ftprintf(stderr, _T("error: malloc\n"));
		return -1;
	}
	g_iImageIndex = 0;
 
	FetchCodeData(0);
	ParseImageData();
	HexDump(g_pucImageData, g_iImageData);
	free(g_pucImageData);
	return 0;
}
 
int ParseImageData(void)
{
	UCHAR	ucBlockSize;
	UCHAR	aucDataValues[255];
 
	g_pucCodeData = aucDataValues;
	for (;;) {
		FileRead(&ucBlockSize, 1);
		_tprintf(_T("Block Data[%u]\n"), ucBlockSize);
		if (ucBlockSize == 0) {
			break;
		}
		FileRead(aucDataValues, ucBlockSize);
		HexDump(aucDataValues, ucBlockSize);
		g_iCodeData	= ucBlockSize;
		g_iCodeIndex	= 0;
		LZWDecode();
	}
	return 0;
}
 
int LZWDecode(void)
{
	int	iCode;
 
	while (1) {
		iCode = FetchCodeData(g_iCodeSize);
		if (iCode < 0) {
			return 1;
		}
		if (iCode == g_iClearCode) {
			// 辞書テーブルのクリア
			g_iDicIndex = g_iClearCode + 1;
			g_aiDicTable[g_iDicIndex] = g_iImageIndex;
			g_iCodeSize = g_ucLZWMinimumCodeSize + 1;
			continue;
		}
		if (iCode == g_iEoICode) {
			break;
		}
		if (g_iDicIndex < iCode) {
			fprintf(stderr, "error: StringTable %u %d\n",
				g_iDicIndex, iCode);
			return -1;
		}
		AddImageData(iCode);
		AddDicTable();
		if ((1 << g_iCodeSize) <= g_iDicIndex) {
			g_iCodeSize++;
		}
	}
	return 0;
}
 
// コードの取得
// 戻り値:-1=失敗 0以上=コード
int FetchCodeData(int iCodeSize)
{
	static UINT	uiBits;
	static int	iBits;
	int		iCode;
 
	if (iCodeSize <= 0) {
		uiBits	= 0;
		iBits	= 0;
		return -1;
	}
	while (iBits < iCodeSize) {
		if (g_iCodeData <= g_iCodeIndex) {
			return -1;
		}
		uiBits |= g_pucCodeData[g_iCodeIndex++] << iBits;
		iBits += 8;
	}
	iCode = uiBits & ((1 << iCodeSize) - 1);
	uiBits >>= iCodeSize;
	iBits -= iCodeSize;
	return iCode;
}
 
// 画像データの追加
int AddImageData(int iCode)
{
	int	iEnd;
	int	i;
 
	if (iCode < g_iClearCode) {
		if (g_iImageData <= g_iImageIndex) {
			return -1;
		}
		g_pucImageData[g_iImageIndex++] = iCode;
		return 0;
	}
	iEnd = g_aiDicTable[iCode];
	for (i = g_aiDicTable[iCode - 1]; i <= iEnd; i++) {
		if (g_iImageData <= g_iImageIndex) {
			return -1;
		}
		g_pucImageData[g_iImageIndex++] = g_pucImageData[i];
	}
	return 0;
}
 
// 辞書テーブルの追加
int AddDicTable(void)
{
	if (_countof(g_aiDicTable) <= ++g_iDicIndex) {
		return -1;
	}
	g_aiDicTable[g_iDicIndex] = g_iImageIndex;
	return 0;
}
 

出力
*** GIF Header
sgifh.acSignature=[GIF]
sgifh.acVersion=[89a]
sgifh.usLogicalScreenWidth=[16]
sgifh.usLogicalScreenHeight=[16]
sgifh.ucbf.GlobalColorTableFlag=[1]
sgifh.ucbf.ColorResolution=[7]
sgifh.ucbf.SortFlag=[0]
sgifh.ucbf.SizeofGlobalColorTable=[7]
sgifh.ucBackgroundColorIndex=[0]
sgifh.ucPixelAspectRatio=[0]
Global Color Table[256]
00000000 01800000 02008000 03808000 04000080 05800080 06008080 07808080
08c0c0c0 09ff0000 0a00ff00 0bffff00 0c0000ff 0dff00ff 0e00ffff 0fffffff
10000000 11000000 12000000 13000000 14000000 15000000 16000000 17000000
18000000 19000000 1a000000 1b000000 1c000000 1d000000 1e000000 1f000000
20000000 21000000 22000000 23000000 24000000 25000000 26000000 27000000
28000000 29000033 2a000066 2b000099 2c0000cc 2d0000ff 2e003300 2f003333
30003366 31003399 320033cc 330033ff 34006600 35006633 36006666 37006699
380066cc 390066ff 3a009900 3b009933 3c009966 3d009999 3e0099cc 3f0099ff
4000cc00 4100cc33 4200cc66 4300cc99 4400cccc 4500ccff 4600ff00 4700ff33
4800ff66 4900ff99 4a00ffcc 4b00ffff 4c330000 4d330033 4e330066 4f330099
503300cc 513300ff 52333300 53333333 54333366 55333399 563333cc 573333ff
58336600 59336633 5a336666 5b336699 5c3366cc 5d3366ff 5e339900 5f339933
60339966 61339999 623399cc 633399ff 6433cc00 6533cc33 6633cc66 6733cc99
6833cccc 6933ccff 6a33ff00 6b33ff33 6c33ff66 6d33ff99 6e33ffcc 6f33ffff
70660000 71660033 72660066 73660099 746600cc 756600ff 76663300 77663333
78663366 79663399 7a6633cc 7b6633ff 7c666600 7d666633 7e666666 7f666699
806666cc 816666ff 82669900 83669933 84669966 85669999 866699cc 876699ff
8866cc00 8966cc33 8a66cc66 8b66cc99 8c66cccc 8d66ccff 8e66ff00 8f66ff33
9066ff66 9166ff99 9266ffcc 9366ffff 94990000 95990033 96990066 97990099
989900cc 999900ff 9a993300 9b993333 9c993366 9d993399 9e9933cc 9f9933ff
a0996600 a1996633 a2996666 a3996699 a49966cc a59966ff a6999900 a7999933
a8999966 a9999999 aa9999cc ab9999ff ac99cc00 ad99cc33 ae99cc66 af99cc99
b099cccc b199ccff b299ff00 b399ff33 b499ff66 b599ff99 b699ffcc b799ffff
b8cc0000 b9cc0033 bacc0066 bbcc0099 bccc00cc bdcc00ff becc3300 bfcc3333
c0cc3366 c1cc3399 c2cc33cc c3cc33ff c4cc6600 c5cc6633 c6cc6666 c7cc6699
c8cc66cc c9cc66ff cacc9900 cbcc9933 cccc9966 cdcc9999 cecc99cc cfcc99ff
d0cccc00 d1cccc33 d2cccc66 d3cccc99 d4cccccc d5ccccff d6ccff00 d7ccff33
d8ccff66 d9ccff99 daccffcc dbccffff dcff0000 ddff0033 deff0066 dfff0099
e0ff00cc e1ff00ff e2ff3300 e3ff3333 e4ff3366 e5ff3399 e6ff33cc e7ff33ff
e8ff6600 e9ff6633 eaff6666 ebff6699 ecff66cc edff66ff eeff9900 efff9933
f0ff9966 f1ff9999 f2ff99cc f3ff99ff f4ffcc00 f5ffcc33 f6ffcc66 f7ffcc99
f8ffcccc f9ffccff faffff00 fbffff33 fcffff66 fdffff99 feffffcc ffffffff

*** Block[0x2c]
Image Block
sib.usImageLeftPosition=[0]
sib.usImageTopPosition=[0]
sib.usImageWidth=[16]
sib.usImageHeight=[16]
sib.ucbf.LocalColorTableFlag=[0]
sib.ucbf.InterlaceFlag=[0]
sib.ucbf.SortFlag=[0]
sib.ucbf.Reserved=[0]
sib.ucbf.SizeofLocalColorTable=[0]
Local Color Table[0]
g_ucLZWMinimumCodeSize=[8]
Block Data[71]
00000000:00 99 09 1c-c8 0c 11 c1-83 88 12 2a-5c a8 10 e1
00000010:40 83 02 21-22 64 d8 f0-60 c1 87 18-1f 52 dc 28
00000020:d1 a1 45 82-1d 33 46 a4-58 90 e4 45-83 12 51 5e
00000030:1c 59 b1 64-4b 95 29 4f-b2 5c e8 92-a6 48 90 1f
00000040:43 46 fc c8-f3 60 40 
Block Data[0]
00000000:cc cc cc cc-cc cc cc 88-cc cc cc cc-cc cc cc cc
00000010:cc 88 88 88-88 88 88 88-88 88 88 88-88 88 cc cc
00000020:cc cc cc 88-cc cc cc 88-cc cc cc 88-cc cc cc cc
00000030:cc cc cc 88-88 88 88 88-88 88 88 88-cc cc cc cc
00000040:cc cc cc 88-cc cc cc 88-cc cc cc 88-cc cc cc cc
00000050:88 88 88 88-88 88 88 88-88 88 88 88-88 88 88 cc
00000060:cc cc cc cc-cc cc cc 88-cc cc cc cc-cc cc cc cc
00000070:cc cc cc 88-cc cc cc cc-cc cc cc 88-cc cc cc cc
00000080:88 88 88 88-88 88 88 cc-88 88 88 88-88 88 88 cc
00000090:cc 88 cc 88-cc 88 cc cc-cc 88 cc 88-cc 88 cc cc
000000a0:cc 88 88 88-88 88 cc cc-cc 88 88 88-88 88 cc cc
000000b0:cc 88 cc 88-cc 88 cc cc-cc 88 cc 88-cc 88 cc cc
000000c0:88 88 88 88-88 88 88 cc-88 88 88 88-88 88 88 cc
000000d0:cc cc cc 88-cc cc cc cc-cc cc cc 88-cc cc cc cc
000000e0:cc cc cc 88-cc cc cc cc-cc cc cc 88-cc cc cc cc
000000f0:cc cc cc cc-cc cc cc cc-cc cc cc cc-cc cc cc cc

*** Block[0x3b]
Trailer
最終更新:2012年09月01日 16:48