Google-Syntax

#include <iostream>;

using namespace std;

int main() {
  cout << "Hello World!";
  return 0;
}

Google-Syntaxというコードをハイライトさせるプラグインを入れました。どうやら中国の方が開発されているソフトで、Googleの情報を使用しているらしいのです。Wordpressのプラグインです。

同様のソフトには、有名な SyntaxHighlighterなどがありますが、少し気に入らないのは、Donateして下さい、というボタンが現れることです。たとえば、

といった具合ですどうですか? コードの右側に何やら小さな緑色のボタンが出ています

これに対して Google-Syntaxでは

  1. #include <iostream>
  2. using namespace std;
  3. int main() {
  4.   cout << “Hello World!”;
  5.   return 0;
  6. }

 

のように、出ていないでしょう?

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

さて、ワード単位(16 bits単位)でのサーチはどうなるでしょうか?

これが結構ややこしい、何故ならば今度はワード単位なのでポインターもワードを指すのです。それに考慮すれば

typdef unsigned short u_short;     
  // これでu_shortというワード型を宣言した
std::vector <u_short> address;
  // u_charへのポインタをいれるvectorを宣言した
u_short *buffer = new u_short[bufSize/2]; 
  // ワードずつ確保なので半分
u_short *bufTop = buffer;
u_short *bufEnd = bufTop + bufSize/2;
u_short *bufPntr = bufTop;
 // 動き回るポインターを先頭にセット
fp.read(reinterpret_cast<char *> (buffer), bufSize);
 // ここではバイト単位でしか指定できないのでキャストした
while (bufPntr < bufEnd) {
  if (*bufPntr == 0xC4FF) {
    // DHT tagにヒットした
    address.push_back(bufPntr);
  }
  bufPntr++;
}
fp.close();
delete[] bufTop;

ちなみに u_shortとは unsigned shortであり、C/C++の規約上 16 bits整数を表すものです

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

まずはファイルを読み込み、DHT tagの検出を行う部分を造りました。先日も書いたように、ここでは バイト単位でサーチするか ワード単位でサーチするかで少し変化します。ただ、どう考えてもワード単位サーチの方が速そうですが、理解が簡単なのでまずはバイト単位です。あくまでも標準C++を用いています

#include "stdafx.h"
#include <iostream>
#include <fstream>;
#include <vector>;
typedef unsigned char u_char;

int _tmain(int argc, _TCHAR* 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;
	std::vector<u_char *> address; // DHT tag位置記録用
	fp.seekg(0, std::ios_base::end);  // ファイルの最後に移動
	end = fp.tellg();  // endpにはファイルの最後の位置がセット
	fp.seekg(0, std::ios_base::beg);  // ファイルの最初に移動
	begp = fp.tellg();  // begpにはファイルの先頭位置がセットされた
	fsize = endp - begp;  // fsizeにはファイルサイズがセットされた
	long const bufSize = static_cast<long>(fsize);  // bufSizeはバッファの大きさ
	u_char * buffer = new u_char[bufSize];
	u_char * const bufTop1 = buffer1;
	u_char * bufPntr = bufTop;
	fp.read(reinterpret_cast<char *>(buffer), bufSize);	
	u_char * const bufEnd1 = bufTop + bufSize;
	while (bufPntr < bufEnd) {
		if (*bufPnt == 0xFF) {
			if (*(bufPntr+1) == 0xC4) {
				address.push_back(bufPntr);
			}
		}
		bufPntr1++;
	}

	fp.close();
	delete[] buffer;

	std::cout << "\nDHT tagバイト検索\n";
	std::vector<u_char *>::iterator it;
	for (it = address.begin(); it != address1.end(); ++it) {
		std::cout << std::showbase << std::hex << (*it - bufTop) << std::endl;
	}

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

リトルエンディアン

ついにリトルエンディアンについて勉強しました。バイト列をメモリーに置くとき、小さいのを上位アドレスに置くか、下位アドレスに置くか、この違いなのです。どうやら IBM360/370というかつての名コンピューターではビッグエンディアンらしいのですが、現在のマイクロプロセッサーでは Core 7などを含め、インテル系など全てリトルエンディアンなのです。この問題は非常に深い問題であり、その点についての簡単な議論をここで見ることができます。
それはさておき、随分自分の知識というかスキルが進歩アップしたのですが、DHT tagの発見プログラムとして unsigned char * bufferにバイト列が蓄えられ、その中で 0xFFC4というDHT tagを発見するプログラム部分として まず、バイト検索では

unsigned char * bufTop = buffer;
unsigned char * temp;
for (long i = 0; i < bufSize; i++) {
  if (*buffer == 0xFF) {
    // tagマーカーに入った
    temp = buffer;
    buffer++;
    if (*buffer == 0xC4) {
      // DHTタグに入った
      std::cout << "DHT tag founded! ad address: ";
      std::cout << std::hex << temp << std::endl;
      buffer++;
    }
  }
}

となるのですが、これをワード(2 bytes)検索だと

unsigned short * bufTop = buffer;
for (long i = 0; i < bufSize/2; i++) {
  if (*buffer == 0xC4FF) { // DHT tagにヒットした
    std::cout << "DHT tag founded! at address: "; 
    std::cout << std::hex << buffer << std::end;
    buffer++;
  }
}

となるのです。ポインターの ++ 演算子による増加が 1 byteか 2 bytesかに気を付け、そしてリトルエンディアンであることに気をつけねばなりません。

相当悩んだぞ

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;
}

結果出力は以下の通り

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

物事には順序が必要です。気が付けば、デバグをするためねにはプログラムを書かねばならない、そのように思いました。
どういう仕様が必要か? ハフマン符号と、その長さを入力すれば、左詰めで1と0のハフマン符号が出力される、それが必要です。
艱難辛苦の末、以下のプログラムを書きました 如何にも単純、しかし作動します。ビット演算の魔術師にかかれば、もっと高速で効率の良いプログラムを書けるでしょう。そんなことわかっています。でも、まずは確実に動くものを造り、それから改良するのです。何しろ僕は、改良が得意な日本人の一人なのですから・・・

void outbit(const int& hc, const int& hb) {
	// 16 bitsの長さ hbのハフマン符号 hcを左詰めで出力する
	
	int mask = 0x01;
	for (int i=hb; i>0; i--) {
		mask <<= (i - 1);
		if ((mask & hc) != 0) {
			std::cout << 1;
		} else {
			std::cout << 0;
		}
		mask = 0x01;
	}
	std::cout << std::endl;
};

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

何か C++の言語仕様に対して根本的に間違っていたような気がします。Webにアクセスしてもう一度考え直しました。前回のプログラム・パーツを以下のように書き換えました

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

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]; 
// これでハフマン表の領域が確保された

これで良いのですよ 今度は間違いない、と確信しています