相当悩んだぞ

DHTの読み込みをC++で書いていて どうしても分からないことにぶち当たりました。それは、以下のような簡単なものなのです たと

えば、このようなbinary fileを作成します。

0x42 0x42 0x43 0x44 0xFF 0xC4 0x45 0x46

これはテキストとして表せばASCII Code表に則って ABCD トEF とあらわされると思います。
そこでプログラムを書いたのです。おのずと知れた JPEG DHTのタグ 0xFF 0xC4の連続する 2バイトを検出するのです。

char * buf;
fp.read(buf, 8);
for (int i=0; i<8; i++) {
  if (*buf == 0xFF) {
    std::cout << "DHTタグに入るよ\n";
  }
  std::cout << *buf << " ";
  buf++;
}

当然出力は、A B C D DHTタグに入るよ・・・
となる筈です。ところがならないのです!!!
どう考えても分からないのです。これはC++では何か変数の型チェックが厳しいのかも知れない? そのように思いました。そこで調べると charと宣言するとそれはdefaultでsigned charすなわち -127~+127を保持し、unsigned charが0~255を保持できる、と書いてあります。そんなこと分かっているのですが、ひょっとして、0xFFはsigned charではまずい値なのかも知れません。そこで

typedef unsigned char u_char;
u_char *buf;

としてみました。ところが、今度は fp.read(buf, 8); の部分で、bufをchar*に変換できません、と叱られました。そこで

typedef unsigned char u_char;
u_char *buf;
fp.read(reinterpret_cast<char *>(buf), 8);

このようにすると、無事0xFFを検出でき、

A B C D DHTタグに入るよ
ト E F

とこのように出力されるようになりました。フーッ C++は型のチェックが厳しいですね。

JPEGハフマン・テーブル – 解読実践(15)

さてさてファイルを読み込むことをせねばなりません。C++ではどのようにするか? これも少し調べました 標準C++を用いて書けば以下のようにするのが良いと思います

#include "stdafx.h"  // Windowsだから必要なのね
#include <iostream>
#include <fstream>

int main(const int argc, const char* argv[])
{
	if (argc !=2) {
		std::cout << "エラー::入力ファイル名を指定して下さい\n";
		char ch = 'x';
		while (ch != 'e') {
			std::cin >> ch;
		}
		return false;
	}
	std::ifstream fp(argv[1], std::ios::in|std::ios::binary);  // ファイル・オープン
	if (fp.fail()) {
		std::cout << "エラー::入力ファイルは存在しません\n";
		char ch = 'x';
		while (ch != 'e') {
			std::cin >> ch;
		}
		return false;
	}
	std::ifstream::pos_type begp, endp, fsize;
	fp.seekg(0, std::ios_base::end);  // ファイルの最後に移動
	endp = fp.tellg();  // endpにはファイルの最後の位置がセット
	fp.seekg(0, std::ios_base::beg);  // ファイルの最初に移動
	begp = fp.tellg();  // begpにはファイルの先頭位置がセットされた
	fsize = endp - begp;  // fsizeにはファイルサイズがセットされた
	char* buffer = new char[(int)fsize];  
	if (buffer == NULL) {
		std::cout << "エラー::バッファを確保できませんでした\n";
		char ch = 'x';
		while (ch != 'e') {
			std::cin >> ch;
		}
		return false;
	}
	fp.read(buffer, fsize);  // バッファにファイルから読み込み
        fp.close();
	char * const bp = buffer;
	std::ofstream fpout("Out.txt", std::ios::out|std::ios::binary);
	fpout.write(bp, fsize);  // Out.txtというファイルに書き出し
        fpout.close();
	delete[] buffer;  // バッファの解放
	return 0;
}

何ともはやめんどくさいですね。しかし、仕方無いのです。これだけのことを我々が普段ファイルを読み書きする時に行っているのです。もちろん最終的にはgraphic interfaceを実装するつもりですよ

JPEGハフマン・テーブル – 解読実践(14)

数日前にあげた 実際のDHTの例

FF C4
00 19
00
01 01 01 01 01 01 00 00 00 00 00 00 00 00 00 00
01 00 02 03 04 05
これではどうでしょうか?
データをこの通りにセットしました
その出力は以下の通り

どうやらきちんと動いているようです。
いちいちデータをマニュアルでセットしてコンパイルではやってられませんので、ファイルを読み込んでDHTを検出して、ハフマン符号を導く、それが次の課題ですね まあこれはそんなに難しいことではありません

JPEGハフマン・テーブル – 解読実践(13)

できた できた できたのだ
Windows7 VisutalStudio 2010でC++でテストしました

// JPEG_Analysis.cpp : programmed by S. SAITO, MD, FACC, FSCAI, FJCC
// created at 5:00AM on August 20th Monday 2012
//

#include "stdafx.h"
#include <iostream>

typedef unsigned char u_char;  // u_char型の宣言
typedef struct {
  int HuffBit;  // ハフマン符号のビット長
  int HuffCode; // ハフマン符号
  int HuffVal;  // ハフマン符号の意味する値
} HUFFTAB;   // これでHUFFTABという型を宣言した

void outbit(const int& hc, const int& hb) {
	// 16 bitsの長さ hbのハフマン符号 hcを左詰めで出力する

	int mask = 0x0001;
	for (int i=hb; i>0; i--) {
		mask <<= (i-1);
		if ((mask & hc) != 0) {
			std::cout << '1';
		} else {
			std::cout << '0';
		}
		mask = 0x0001;
	}
	std::cout << std::endl;
};

int _tmain(int argc, _TCHAR* argv[])
{
	u_char BITS[16];  // それぞれのビット長のハフマン符号がいくつあるか
	// 常に16バイトなので静的に配列確保した

	// データのセット 実際のプログラムではファイルから読み込む
	for (int i=0; i<16; i++) {  // データをセット
		BITS[i] = 0x00;
	}
	BITS[1] = 0x01; BITS[2] = 0x05; BITS[3] = 0x01;
	BITS[4] = 0x01; BITS[5] = 0x01; BITS[6] = 0x01; 
	BITS[7] = 0x01; BITS[8] = 0x01;

	int huffElementNo = 0;
	for (int i=0; i<16; i++) {
		huffElementNo += BITS[i]; // これでハフマン符号語の総数を求める
	}
	//
	// ハフマンテーブル領域の動的確保
	HUFFTAB *ht = new HUFFTAB[huffElementNo]; 
	// これでハフマン表の領域が確保された

	int code = 0;  // ハフマン符号初期値は0である
	int huffElement = 0;  // 配列のカウンター
	for (int i=0; i<16; i++) { // これでBitS[]配列全体を走査する
		for (int j=0; j<BITS[i]; j++) { 
			ht[huffElement].HuffBit = i+1;
			ht[huffElement].HuffCode = code;
			ht[huffElement].HuffVal = 0;  // とりあえずdummyで0を入れておく
			huffElement++;
			code+=1;  // 次のハフマン符号のために1 bit足す
		}
		code <<= 1;  // 次のビット数のハフマン符号のために、左に1 bitシフトする
	}

	for (int i=0; i<huffElementNo; i++) {
		std::cout << "Bit = " << ht[i].HuffBit << " ::: Code = " << " ";
		outbit(ht[i].HuffCode, ht[i].HuffBit);
	}

	char ch = NULL;
	while (ch != 'e') {
		std::cin >> ch;
	}
	return 0;
}

結果出力は以下の通り