#include <fcntl.h> // _O_WTEXT
#include <io.h> // _setmode
#include <stdio.h> // _fileno
#include <stdlib.h> // malloc
#include <tchar.h>
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
// 関数プロトタイプ宣言
USHORT betos(USHORT us);
void* FetchFile(size_t sizeCount);
int ParseFile(void);
int ParseUnknown(void);
int ParseAPPn(void);
int ParseDQT(void);
int ParseSOF0(void);
int ParseDHT(void);
int ParseSOS(void);
// グローバル変数
static UCHAR* g_pucFile; // ファイル内容
static size_t g_sizeFile; // ファイルサイズ
static size_t g_sizeFileIndex; // ファイルの指標
#define dprintf(fmt, var) _tprintf(_T(#var)_T("=[")fmt##_T("]\n"), var)
int _tmain(int argc, TCHAR* argv[])
{
struct _stat stat; // ファイル情報
FILE* pFile; // ファイルポインタ
TCHAR* ptcFile; // ファイル名
_setmode(_fileno(stdout), _O_WTEXT);
_setmode(_fileno(stderr), _O_WTEXT);
if (argc != 2) {
_ftprintf(stderr, _T("usage: dumpjpg file\n"));
return 1;
}
ptcFile = argv[1];
// ファイルサイズの取得
if (_tstat(ptcFile, &stat) != 0) {
_ftprintf(stderr, _T("error: _tstat[%s]\n"), ptcFile);
return 1;
}
g_sizeFile = stat.st_size;
// ファイルのオープン
if (_tfopen_s(&pFile, ptcFile, _T("rb")) != 0) {
_ftprintf(stderr, _T("error: _tfopen_s[%s]\n"), ptcFile);
return 1;
}
// メモリの確保
g_pucFile = (UCHAR*)malloc(g_sizeFile);
if (g_pucFile == NULL) {
_ftprintf(stderr, _T("error: malloc[%u]\n"), g_sizeFile);
return 1;
}
// ファイルの読み込み
if (fread(g_pucFile, 1, g_sizeFile, pFile) != g_sizeFile) {
_ftprintf(stderr, _T("error: fread[%s]\n"), ptcFile);
return 1;
}
fclose(pFile);
// ファイルの解析
g_sizeFileIndex = 0;
while (ParseFile() == 0) {
}
free(g_pucFile);
return 0;
}
// ビッグエンディアン短整数の変換
USHORT betos(USHORT us)
{
return us << 8 | us >> 8;
}
// ファイル内容の取得
void* FetchFile(size_t sizeCount)
{
void* pv;
if (g_sizeFile < g_sizeFileIndex + sizeCount) {
_ftprintf(stderr, _T("error: FetchFile\n"));
exit(1);
}
pv = g_pucFile + g_sizeFileIndex;
g_sizeFileIndex += sizeCount;
return pv;
}
// ファイルの解析
int ParseFile(void)
{
UCHAR* pucMarker;
size_t sizeFileIndex;
sizeFileIndex = g_sizeFileIndex;
pucMarker = (UCHAR*)FetchFile(2);
_tprintf(_T("\n*** [0x%02X%02X] [0x%08X]\n"),
pucMarker[0], pucMarker[1], sizeFileIndex);
if (pucMarker[0] != 0xFF) {
return -1;
}
switch (pucMarker[1]) {
case 0xC0:
ParseSOF0();
break;
case 0xC4:
ParseDHT();
break;
case 0xE0:
ParseAPPn();
break;
case 0xD8:
_tprintf(_T("SOI\n")); // 画像開始
break;
case 0xD9:
_tprintf(_T("EOI\n")); // 画像終了
return 1;
// break;
case 0xDA:
ParseSOS();
break;
case 0xDB:
ParseDQT();
break;
default:
ParseUnknown();
}
return 0;
}
// 不明
int ParseUnknown(void)
{
USHORT* pusLp;
USHORT usLp;
_tprintf(_T("Unknown\n"));
pusLp = (USHORT*)FetchFile(2);
usLp = betos(*pusLp);
FetchFile(usLp - 2);
return 0;
}
// アプリケーションデータ
int ParseAPPn(void)
{
USHORT usLa; // パラメータ長
struct SApp {
char aucID[5]; // JFIF識別子
UCHAR ucV1; // メジャーバージョン
UCHAR ucV2; // マイナーバージョン
UCHAR ucU; // 密度単位(1:dots/inch)
USHORT usXd; // 横密度
USHORT usYd; // 縦密度
UCHAR ucXt; // サムネイル横ドット数
UCHAR ucYt; // サムネイル縦ドット数
} *pApp;
USHORT* pus;
_tprintf(_T("APPn\n"));
pus = (USHORT*)FetchFile(2);
usLa = betos(*pus);
dprintf(_T("%u"), usLa);
pApp = (struct SApp*)FetchFile(usLa - 2);
dprintf(_T("%S"), pApp->aucID);
dprintf(_T("%u"), pApp->ucV1);
dprintf(_T("%u"), pApp->ucV2);
dprintf(_T("%u"), pApp->ucU);
dprintf(_T("%u"), betos(pApp->usXd));
dprintf(_T("%u"), betos(pApp->usYd));
dprintf(_T("%u"), pApp->ucXt);
dprintf(_T("%u"), pApp->ucYt);
return 0;
}
// 量子化テーブル定義
int ParseDQT(void)
{
USHORT usLq; // 量子化テーブル定義長(2+65*t)
struct SDQT {
UCHAR ucTq: 4; // 量子化テーブル識別子
UCHAR ucPq: 4; // エレメント精度
UCHAR aucQ[64]; // 量子化テーブルの要素
} *pDQT;
USHORT* pus;
int i;
_tprintf(_T("DQT\n"));
pus = (USHORT*)FetchFile(2);
usLq = betos(*pus);
dprintf(_T("%u"), usLq);
pDQT = (struct SDQT*)FetchFile(usLq - 2);
dprintf(_T("%u"), pDQT->ucPq);
dprintf(_T("%u"), pDQT->ucTq);
for (i = 0; i < 64; i++) {
_tprintf(_T("%02X%c"), pDQT->aucQ[i], _T(" - \n")[i % 8]);
}
return 0;
}
// フレーム開始:基本DCT方式
int ParseSOF0(void)
{
USHORT usLf; // フレームヘッダ長
#pragma pack(push, 1)
struct SOF {
UCHAR ucP; // サンプル精度
USHORT usX; // ライン数
USHORT usY; // ライン当たりのサンプル数
UCHAR ucNf; // フレーム内の画像成分数
} *pSOF;
#pragma pack(pop)
struct Pa { // 成分指定パラメータ
UCHAR ucC; // 成分識別子
UCHAR ucV: 4; // 垂直サンプリングファクタ
UCHAR ucH: 4; // 水平サンプリングファクタ
UCHAR ucTq; // 量子化テーブルセレクタ
} *pPa;
USHORT* pus;
int i;
_tprintf(_T("SOF0\n"));
pus = (USHORT*)FetchFile(2);
usLf = betos(*pus);
dprintf(_T("%u"), usLf);
pSOF = (struct SOF*)FetchFile(usLf - 2);
dprintf(_T("%u"), pSOF->ucP);
dprintf(_T("%u"), betos(pSOF->usX));
dprintf(_T("%u"), betos(pSOF->usY));
dprintf(_T("%u"), pSOF->ucNf);
for (i = 0; i < pSOF->ucNf; i++) {
pPa = (struct Pa*)(((UCHAR*)pSOF) + 6 + i * 3);
_tprintf(_T("%d:C=%u H=%u V=%u Tq=%u\n"),
i + 1, pPa->ucC, pPa->ucH, pPa->ucV, pPa->ucTq);
}
return 0;
}
// ハフマンテーブル定義
int ParseDHT(void)
{
USHORT usLh;
struct DHT {
UCHAR ucTh: 4; // ハフマンテーブル識別子
UCHAR ucTc: 4; // テーブルクラス(0:DC成分用、1:AC成分用)
UCHAR aucL[16]; // 長さiビットの符号語数
UCHAR aucV[]; // それぞれの符号語に関連する値
} *pDHT;
USHORT* pus;
int iLi;
int iLj;
int iV;
_tprintf(_T("DHT\n"));
pus = (USHORT*)FetchFile(2);
usLh = betos(*pus);
dprintf(_T("%u"), usLh);
pDHT = (struct DHT*)FetchFile(usLh - 2);
dprintf(_T("%u"), pDHT->ucTc);
dprintf(_T("%u"), pDHT->ucTh);
iV = 0;
for (iLi = 0; iLi < 16; iLi++) {
_tprintf(_T("L%d=[%u]\n"), iLi + 1, pDHT->aucL[iLi]);
for (iLj = 0; iLj < pDHT->aucL[iLi]; iLj++) {
_tprintf(_T("%02X%c"), pDHT->aucV[iV++],
_T(" - - - \n")[iLj % 16]);
}
if (iLj % 16) {
_tprintf(_T("\n"));
}
}
return 0;
}
// スキャン開始
int ParseSOS(void)
{
USHORT usLs; // スキャンヘッダ長
UCHAR* pucNs; // スキャン内の画像成分数
struct SPa { // 成分指定パラメータ
UCHAR ucCs; // スキャン成分セレクタ
UCHAR ucTa: 4; // AC成分用ハフマンテーブルセレクタ
UCHAR ucTd: 4; // DC成分用ハフマンテーブルセレクタ
} *pPa;
struct SSh {
UCHAR ucSs; // 基本DCT方式では未使用(値固定)
UCHAR ucSe; // 基本DCT方式では未使用(値固定)
UCHAR ucAl: 4; // 基本DCT方式では未使用(値固定)
UCHAR ucAh: 4; // 基本DCT方式では未使用(値固定)
} *pSh;
USHORT* pus;
UCHAR* puc;
UCHAR* pucNext;
int i;
_tprintf(_T("SOS\n"));
// スキャンヘッダ
pus = (USHORT*)FetchFile(2);
usLs = betos(*pus);
dprintf(_T("%u"), usLs);
pucNs = (UCHAR*)FetchFile(1);
dprintf(_T("%u"), *pucNs);
for (i = 0; i < *pucNs; i++) {
pPa = (struct SPa*)FetchFile(2);
_tprintf(_T("%d:Cs=[%u] Td=[%u] Ta=[%u]\n"),
i + 1, pPa->ucCs, pPa->ucTd, pPa->ucTa);
}
pSh = (struct SSh*)FetchFile(3);
dprintf(_T("%u"), pSh->ucSs);
dprintf(_T("%u"), pSh->ucSe);
dprintf(_T("%u"), pSh->ucAh);
dprintf(_T("%u"), pSh->ucAl);
// エントロピー符号化セグメント(インタバル)
for (i = 0; ; i++) {
puc = (UCHAR*)FetchFile(1);
if (*puc == 0xFF) {
pucNext = (UCHAR*)FetchFile(1);
if (*pucNext != 0x00) {
g_sizeFileIndex -= 2;
break;
}
}
_tprintf(_T("%02X%c"), *puc, _T(" - \n")[i % 8]);
}
_tprintf(_T("\n"));
return 0;
}