ちょっと見たかぎりでは辞書ファイル構成がシステムソ
フト電子辞典シリーズと違っていて、藤井さんのdessed
では変換できないようです。誰かやってみませんか?
--
太田純(Junn Ohta) (株)リコー/新横浜事業所
oh...@sdg.mdd.ricoh.co.jp
- http://www.denshijiten.co.jp/
+ http://www.densijiten.co.jp/
ですね。
また新しい非公開フォーマットの登場ですね。
EPWING やロゴヴィスタ社のシステムソフト電子辞典シリーズと
競合していますが、今後どうなるんだろう。
ラインナップを見るとまだまだ数で追い付いていないし、
(株)電子辞典でしか手に入らない辞書もないようです。
アカデミックパックは豊富に揃ってるけど。
なにより、EPWINGやロ社のと違い仕様が解明されていないので、
GNU/Linux で使えないので買おうという気にはなれませんね。
とは言っても、わざわざ変換してまで使うユーザは少数派で、
ほとんどの人はフォーマットの仕様なんて気にしないから、
非公開が増えるのでしょうけど。
コラムとインタビューが面白かったです。
(社長の出世作は面白くなかったですが。)
検索ソフトの DDviewer への力の入れ具合がうかがえます。
開発者インタビューにある辞書作成用の DDregister と DDmaker が
広辞苑などと同じフォーマットの形式を吐くのか気になるところ。
辞書ファイルを hex してみましたが、
ロ社のとはヘッダ部の構成や
オフセット部がリトルエンディアンなど違いがありますね。
肝心のデータのところは手がかりが少ない感じです、解読は難しそう。
太田さんには以前にこの質問をしたのですが、
ラクに解読する方法を知ってる人いますか?
やっぱり Jamming は対応するのかな?
辞書の自由
http://openlab.ring.gr.jp/edict/jus200007/
---
藤井宏憲
すみません。(_ _;
> EPWING やロゴヴィスタ社のシステムソフト電子辞典シリーズと
> 競合していますが、今後どうなるんだろう。
> ラインナップを見るとまだまだ数で追い付いていないし、
> (株)電子辞典でしか手に入らない辞書もないようです。
> アカデミックパックは豊富に揃ってるけど。
Windowsユーザーにとってはどれを買っても同じ、とい
うことになればそこそこ売れるのではないかと思います。
近所のビックカメラでも、パッケージの背表紙が赤のシ
ステムソフト電子辞典シリーズと並んで背表紙が青のHD
辞典シリーズがなかよく並んで陳列されてます。
コンテンツについては、システムソフト電子辞典シリー
ズだって独自に電子化を行っているわけではなくて、基
本的にはすでに電子化されたコンテンツを買ってきて独
自フォーマットにして売っているわけで、HD辞典シリー
ズも同じやりかたをきっと狙っているでしょう。だとす
ると「(株)電子辞典でしか手に入らない辞書」というの
もなかなか出てこないはずで。
# 以前DOS/Vマガジンに書いた記事にEPWINGコンソーシ
# アムの担当者が文句をつけてきて、そのときこぼれ話
# として聞いたことなのですが、せっかくEPWINGコンソ
# ーシアムで手間ひまかけていろんな辞書を電子化した
# のに、EPWINGの辞書は売れないで、後からのほほんと
# やってきて電子化済みのコンテンツを買っていき、独
# 自フォーマットにして売っているメーカーの製品が売
# れている、かといって電子化にかかった費用をすべて
# コンテンツの価格に載せたらとんでもないことになる
# のでそれはできない、やんぬるかな、とのこと。
EPWINGや電子ブックになくて電子化されている辞書コン
テンツとしては、新明解国語辞典が目立つところですか
ね。最初に三省堂が「ハードディスクで使う」シリーズ
(DTONIC付属)で出して、そのあとシステムソフト電子辞
典シリーズにも入ったようなので、三省堂が電子化して
ロゴヴィスタがそれを買ったのかな。
> なにより、EPWINGやロ社のと違い仕様が解明されていないので、
> GNU/Linux で使えないので買おうという気にはなれませんね。
> とは言っても、わざわざ変換してまで使うユーザは少数派で、
> ほとんどの人はフォーマットの仕様なんて気にしないから、
> 非公開が増えるのでしょうけど。
システムソフトのEDviewerはEPWING V1のコンテンツが
読めるのでパッケージにEPWINGという文字がありますね。
なのでコンテンツがEPWING形式だと勘違いして買ってい
く客があとを絶たなくて、そういう人たちを救済するた
めにもEPWINGに変換できるdessedが役に立っているわけ
です。HD辞典シリーズはそういう意味では間違って買う
人は少ないでしょうし、しかもコンテンツに新味もない
ときては解析のモチベーションが出ないですかね。
> 開発者インタビューにある辞書作成用の DDregister と DDmaker が
> 広辞苑などと同じフォーマットの形式を吐くのか気になるところ。
他社コンテンツをDDmakerで変換してDDviewerで見られ
るようになればおもしろいかな、と思ったのですが、最
大5000件しか登録できないのではあまり意味がない...。
> 辞書ファイルを hex してみましたが、
> ロ社のとはヘッダ部の構成や
> オフセット部がリトルエンディアンなど違いがありますね。
> 肝心のデータのところは手がかりが少ない感じです、解読は難しそう。
最近辞書の相互乗り入れというのを考えていて、UNIXな
人々にはあまり関係ないのですが、システムソフト電子
辞典とかDTONICとかHD辞典とか、はたまたロボワードと
かのフォーマットをEPWING経由で相互変換できるように
なったらユーザーには便利かな、と思うのです。dessed
とDTONIC ToolKitはソースがあるし、やろうと思えばあ
る程度のことはできそうですなんですけどね。
> 太田さんには以前にこの質問をしたのですが、
> ラクに解読する方法を知ってる人いますか?
そういう人がいたら私にも紹介してください。(_ _)
> やっぱり Jamming は対応するのかな?
:-)
そんな客のひとりが私です。
> > 開発者インタビューにある辞書作成用の DDregister と DDmaker が
> > 広辞苑などと同じフォーマットの形式を吐くのか気になるところ。
>
> 他社コンテンツをDDmakerで変換してDDviewerで見られ
> るようになればおもしろいかな、と思ったのですが、最
> 大5000件しか登録できないのではあまり意味がない...。
「ああ」と「あああ」で辞書を作成して、
バイナリにどんな違いがあるかで、
圧縮アルゴリズムの手がかりになるかなー、と思いました。
---
藤井宏憲
今のところ、わかったことを。
ユニコード、解析しにくい。
---
4096バイト毎に LZSS にて圧縮
まとめて圧縮するデータの塊をチャンクと呼ぶ
リトルエンディアン(LE)
本文は UTF-16 (LE)
ヘッダ、オフセット部、チャンク部で構成
■ヘッダ
0x50バイト
位置 (バイト数)
--------------
0x00 (4) 'BODY' など
0x16 (4)
0x1a (4) チャンク部開始位置(ファイルの先頭から)
0x1e (4) チャンク部のサイズ
0x40 (4) 圧縮前データサイズ
ファイルサイズ = チャンク部開始位置 + チャンク部のサイズ
チャンク数 = (チャンク部開始位置 - 0x50) / 4
■オフセット部
4バイト、LE
■チャンク部
まず、1ビットのフラグ。
フラグが `1'のときは続く1バイトが文字。
フラグが `0'のときは続く2バイトで一致を表現。表現法は不明
---
藤井宏憲
す、すごい...。(^^;
ことによると、もしかして、ひょっとすると、遠からず
解析できてしまうかもしれませんね。:-D
圧縮を伸長できるようになりました。
---
■株式会社電子辞典の HD 辞典シリーズのファイル形式
4096バイト毎に LZSS で圧縮
まとめて圧縮するデータの塊をチャンクと呼ぶ
リトルエンディアン(LE)
本文は UTF-16 (LE)
ヘッダ、オフセット部、チャンク部で構成
■ヘッダ
0x50バイト
位置 (バイト数)
-----------------
0x00 (4) 'BODY' など
0x16 (4)
0x1a (4) チャンク部開始位置(ファイルの先頭から)
0x1e (4) チャンク部のサイズ
0x40 (4) 圧縮前データサイズ
ファイルサイズ = チャンク部開始位置 + チャンク部のサイズ
チャンク数 = (チャンク部開始位置 - 0x50) / 4
■オフセット部
(4 * チャンク数) バイト
各チャンクの開始位置(チャンク部開始位置から)の列
4バイト、LE
■チャンク部
4096バイト毎に LZSS で圧縮
まず、1ビットのフラグ。
フラグが 1 のときは続く8ビットが文字。
フラグが 0 のときは、続く8ビットで位置を5ビットで一致長。
一致長には2を加える。
---
藤井宏憲
うーむ、すばらしいです。
> 4096バイト毎に LZSS で圧縮
LZSSだということをどうやって見当をつけたのか、その
あたりが知りたいです。できれば私もそのテのノウハウ
を身につけてみたいので...。
> まず、1ビットのフラグ。
> フラグが 1 のときは続く8ビットが文字。
> フラグが 0 のときは、続く8ビットで位置を5ビットで一致長。
> 一致長には2を加える。
まずフラグがあるというのはLZSSの常道なんですね? あ
とは地道にパラメーターを変更しながらちゃんと伸長で
きる組み合わせを探す、ということかな?
それにしても、すごいなあ...。
まずは各圧縮のブロックを1ブロック1ファイルに分割しました。
つぎに自作の2進ダンプで、各ファイルの先頭8バイトをダンプすると、
$ for i in kbody/*;do head -c 8 $i|bbd;echo;done | head
11110100 01000000 00000000 01000000 10010001 01111110 00100000 00100000
10100101 11001100 00110001 00110011 00001100 01011110 00100110 10111111
11001001 01001000 01100001 00111111 11111010 10010111 11100011 01111111
10000110 11001100 00100100 01111111 10001001 00010111 11100010 00000011
10010000 01000000 00111111 01010101 11101011 01001101 11001010 11011101
10011010 01111110 00111010 10110101 00101010 11110110 00101010 11010111
11111000 01001100 00100100 10110010 00001010 10001111 11100010 00100111
11010010 01001100 00110111 10110011 00001000 00010100 11000010 01000111
10101101 11001100 00101100 11010011 00001001 11111101 10001110 10110011
10001000 01001100 00110010 01111001 01011100 11110110 00101011 00010101
A A A A
このように、0, 9, 18, 27, ...ビット目に縦に1が並びます。
では逆に27ビット目が 1 ではなく 0 なブロックは、
$ for i in kbody/*;do head -c 8 $i|bbd;echo;done | egrep '^.{30}0'
11110100 01000000 00000000 01000000 10010001 01111110 00100000 00100000
11011100 01001100 00111001 00000000 00100000 11000011 01100110 00010010
11110010 01001100 00110101 11100000 00100000 11111011 11100110 00011111
10100010 01000000 00000000 01000000 10010001 01111110 00100000 00110000
A A A A
このように、なりました。
---
藤井宏憲
なるほど、ビット単位で眺めればそれなりに構造が見え
てくるわけですね。そのためのツールも作りようはある
と。ちょっと勉強してどれか製品を選んでトライしてみ
ようかなと思います。
EPWINGはハフマンでシステムソフトがLZ77、株式会社電
子辞典がLZSSということになるわけですが、選択肢とし
てはそれぐらいなのかな。
LZSS でも S-EBXA なんかは 8つのフラグをまとめて
1バイトにしているようです[1]。
ビット単位をバイト単位で扱う LZSS の常套手段ですね。
> ちょっと勉強してどれか製品を選んでトライしてみ
> ようかなと思います。
おおっ、となるとエンカルタか世界大百科事典あたりでしょうか?
期待しちゃいます。
ただ、どちらもコンテンツ完全収録な体験版をやっちゃってるなー。
> EPWINGはハフマンでシステムソフトがLZ77、株式会社電
> 子辞典がLZSSということになるわけですが、選択肢とし
> てはそれぐらいなのかな。
nomad さんが解析された DTONIC はハフマン法。
これまた nomadさんが取り組まれている LDOCE4 は gzip。
他に使われそうなアルゴリズムは動的ハフマンとか
LZ78 や LZW の動的辞書法でしょうか。
ただ、圧縮されたデータを XOR などで暗号化されると
もはや歯が立たないと思います。
[1] S-EBXA の圧縮形式について
http://www.sra.co.jp/people/m-kasahr/dict-compress/sebxa-compress.html
---
藤井宏憲
うむむ、圧縮に手を出すにはもう少し経験値上げておか
ないとだめかも。(^^;
> おおっ、となるとエンカルタか世界大百科事典あたりでしょうか?
やりたいのは世界大百科なんですよね。
> ただ、どちらもコンテンツ完全収録な体験版をやっちゃってるなー。
そうなんです。Jammingで世界大百科が読めるのですが、
それは第二版だけで、アスキーが体験版をつけた初版に
は対応してません。ファイル構成を眺めるたかぎりでは
どちらも同じように見えるんですけどね。そのあたりは
微妙かもしれない...。
> 他に使われそうなアルゴリズムは動的ハフマンとか
> LZ78 や LZW の動的辞書法でしょうか。
LZ78とLZWは特許がらみの問題があるので、賢いところ
は手を出さないのではないかと思っているのです。
> ただ、圧縮されたデータを XOR などで暗号化されると
> もはや歯が立たないと思います。
そうなんですよね。でも世界大百科はJammingでも何と
かなっているわけですから、暗号化まではされていない
のではないかと期待しているのでした。
すみません、間違えてました。CD-ROMを発掘して確認し
たところ、アスキー付録の体験版は第2版のほうでした。
インストールしたらJammingで検索できちゃいました...。
というわけで、すでに前例があるのだから、いまさら読
めるようになったところで問題はないかな、と。:-)
# 藤井さん、これを読んで何か思い当たるようなことは
# ありませんか?
●ファイル
sinidx.db: 検索インデックス
・かな/表記それぞれについての前方一致/後方一致イン
デックスを含む
・構造はEPWINGのhonmonと同じ(bookinfoで情報が見え
る!)で、インデックスだけが含まれている
・各エントリの候補リスト所在ブロック番号の位置には
title.dat中の項番(0~356047)がある
title.dat: 候補リストデータ
・35万件の候補リスト(検索結果として一覧表示される
もの)について、タイトルおよびtitlez.dat/itemloc.
dat中の項番(0~87825)が格納されている
titlez.dat: 項目タイトルデータ
・87826件の項目タイトルが格納されている
itemloc.dat: 項目参照データ
・87826件の項目それぞれについて、item.dat中のオフ
セットとサイズ、itemlink.dat中のオフセットとサイ
ズが格納されている
item.dat: 圧縮本文データ
・87826件の項目それぞれについて、本文データが圧縮
されて格納されている
itemlink.dat: 未調査
○世界大百科事典の検索が可能なJammingでは、データ
ファイルとしてsinidx.db、title.dat、titlez.dat、
itemloc.dat、item.datだけをみている。ただしその
ほかに世界大百科事典に含まれるダイナミックリンク
ライブラリcx.dllを呼び出しているらしい。圧縮デー
タの伸長も自分でやらずcx.dllにやらせているかも?
●本文データ
・item.datに87826件のデータが含まれ、itemloc.dat
のオフセットとサイズで項目が取り出せる
・1/1.7程度に圧縮されているようだ
・サイズが40~80バイト程度の項目と400バイト以上の
項目にわかれている(※1)
・各項目のデータを取り出してlhaで圧縮してみたが、
圧縮されなかった(※2)
・各項目の最初の2バイトは02 01で固定。次の4バイト
はlittle endianの数値で、おそらく伸長後のサイズ。
それ以降は不明...
・最初の1000件のデータを比較すると、不明部分の先頭
数十バイトが一致しているものがかなりある(※3)
・初版と第2版のデータを比較すると、本文がまったく
同じものについては圧縮データも同じ。「あい(藍)」
の項目では本文先頭32文字が同じなのに圧縮データは
先頭付近から異なる。「あい(愛)」の項目は空白文字
の個数が異なるだけだが、本文先頭付近から異なって
いるにもかかわらず圧縮データは255バイトめまで一
致している(※4)
○※1、※2、※3、※4から考えて、LZ系のアルゴリズム
ではなく、ハフマン圧縮されているのではないか? 伸
長に必要な頻度テーブルは不明部分の先頭にあると考
えてよさそうだが、項目ごとに頻度テーブルをもって
いるとしたらサイズはそれほど大きくないはず。それ
に40~80バイトの短い項目も先頭付近の見かけは同じ。
どうなっているのか?
●データ
○初版の先頭3項目の圧縮データのサイズ
00000 5,399
00001 1,107
00002 11,864
○第2版の先頭3項目の圧縮データのサイズ
00000 5,470
00001 1,107
00002 11,875
○初版の項目データ先頭付近の16進ダンプ
00000: 02 01 11 24 00 00 95 61 11 CB 3C 72 04 8D 2C 39 4A FD 06 F2 85 E5 8C
^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
00001: 02 01 4D 07 00 00 9B 7C 61 FC DC 4E 7E D0 59 82 65 F4 87 16 5E 97 4B
00002: 02 01 96 57 00 00 9B 61 1F D1 43 00 DF F0 72 C6 1A F9 11 69 8C 88 30
^^^^^
○第2版の項目データ先頭付近の16進ダンプ
00000: 02 01 10 25 00 00 91 61 1B 79 05 EC 1F CF C2 15 BF E4 BF F3 8D 12 62
^^^^^ ^^ ^^^^^^^^^^^^^^ → これ以降全体が初版と異なる
00001: 02 01 4D 07 00 00 9B 7C 61 FC DC 4E 7E D0 59 82 65 F4 87 16 5E 97 4B
→ 全体が初版と同じ
00002: 02 01 DC 57 00 00 9B 61 1F D1 43 00 DF F0 72 C6 1A F9 11 69 8C 88 30
^^^^^ → これ以降255バイトめまで初版と同じ
○項目番号00000「あい(藍)」の本文先頭付近
初版
| 濃青色,いわゆる藍色の染料を採るために栽培されるタデ科の一年草。インジゴ
| と呼ばれる藍色の染料を採る植物には,アイのほかにリュウキュウアイ Strobil
| anthes cusia O. Kuntze(キツネノマゴ科)やインドキアイ(コマツナギ属の数種
第2版
| 濃青色,いわゆる藍色の染料を採るために栽培されるタデ科の一年草(イラスト
| )。インジゴと呼ばれる藍色の染料を採る植物には,アイのほかにリュウキュウ
| アイ Strobilanthes cusia O. Kuntze(キツネノマゴ科)やインドキアイ(コマツ
・第2版には「(イラスト)」のリンクが追加されている。
そのほかにも第2版には初版にない参照リンクがある
○項目番号00001「あい(間)」の本文先頭付近
初版
| 能一番のなかで狂言方の担当する役とその演技。間狂言(あいきようげん)とも,
| 能間ともいう。もっとも一般的なかたちは,二場物の能で前ジテの退場後,後ジ
| テの登場までのあいだをつなぐ役で,これに4種ある。〈語リ間〉(〈居語リ〉と
第2版
| 能一番のなかで狂言方の担当する役とその演技。間狂言(あいきようげん)とも,
| 能間ともいう。もっとも一般的なかたちは,二場物の能で前ジテの退場後,後ジ
| テの登場までのあいだをつなぐ役で,これに4種ある。〈語リ間〉(〈居語リ〉と
・初版と第2版で本文全体が同じ
○項目番号00002「あい(愛)」の本文先頭付近
初版
| 【〈愛〉の意味・〈愛〉の言語】
| 愛の過不足なく普遍妥当な定義を求めることは,愛の様態の多岐性,愛の解釈の
| 恣意性,愛の用語の混交性のために,困難というより,不可能であり,無意義で
第2版
| 【〈愛〉の意味・〈愛〉の言語】
| 愛の過不足なく普遍妥当な定義を求めることは,愛の様態の多岐性,愛の解釈
| の恣意性,愛の用語の混交性のために,困難というより,不可能であり,無意義
・初版と第2版の違いは、第2版では各段落の頭に2バイ
ト空白があり、1人の著者名の前に改行と1バイト空白
が置かれていることだけ
以上
その方法ならどんな圧縮法でも暗号法でも大丈夫そうですね。
そんなスキルを身につけたいな。
> ・最初の1000件のデータを比較すると、不明部分の先頭
> 数十バイトが一致しているものがかなりある(※3)
これは頻度テーブルが似ているので
一致する部分があるということですか?
そうすると、先頭数十バイトのみが一致するのでなく、
先頭数バイトは一致しないが、その後数バイトは
一致するなんてのも同じようにありそうです。
もしそのような項目がないとすると、
先行のバイトを続くバイトの暗号化に
使っている可能性もあるのではないでしょうか?
もしも頻度データを暗号化していたら、
恐れていた、本文も暗号化してても不思議ではないですね。
そうなると...
cx.dll でテキストを吸い出すことになるのだろうか。
> それに40~80バイトの短い項目も先頭付近の見かけは同じ。
素直に考えると、40~80バイトの短い項目は
頻度テーブルを避けてハフマンで圧縮しないと
なりそうですが、
見かけが同じとはこれもハフマンっぽいということですか?
8ビットでなく4ビット単位にすることで、
頻度テーブルのサイズを256から16にでもしていると言うことですか?
そんなことするのかな~。
おっしゃるとおり頻度テーブルが似ているのではないか
と思ったのですが、「その後数バイトは一致する」よう
なものはあまりなさそうでした。
> もしそのような項目がないとすると、
> 先行のバイトを続くバイトの暗号化に
> 使っている可能性もあるのではないでしょうか?
暗号化されていたらそれこそ歯が立たないでしょうね。
ただ、ハフマン圧縮ではないかという推測はだいぶ早と
ちりだったようです。初版と第2版で伸長後の本文は先
頭付近から違っているのに、圧縮データは255バイトめ
まで同じであるような項目があるというのがいちばん大
きな根拠だったのですが、ひょっとしたら先頭付近にタ
イトルデータや参照リンクのSGMLタグがたくさんあるの
かもしれません。
圧縮された本文データのさまざまな位置で1バイトのデ
ータを変更してから世界大百科事典を実行し、ふるまい
を観察した(※)のですが、以下のような性質がみられる
ことからやはりLZ系の圧縮かなと思うようになりました。
・圧縮本文先頭付近の数バイトを変化させてみたところ、
変化量が少なくても位置によってふるまいに違いがあ
りすぎる(のでハフマン圧縮の頻度テーブルとは違う
のではないか?)
・データ変更により文字化けが発生したとき、本文の一
部がそれ以降でたびたび現れる(LZ圧縮の辞書からの
コピーが起きているのではないか?)
データ変更によるふるまいの違い、文字化けの例、正常
な本文を参考のためにつけておきます。
また、先頭付近を1バイト変更したときに本文途中のご
く一部だけ化ける例があることから、暗号化されている
にしてもせいぜい固定パターンくり返しのXOR程度であ
り、ある位置の暗号化がそれより後ろに波及してはいな
いだろうと思われます。
というわけで、LZ系の圧縮であると仮定してもう少しい
ろいろ調べてみることにします。
※付属の検索ソフトがCD-ROMにある辞書データしか読ん
でくれないので、データにパッチを当てるたびにCD仮
想化ソフトで仮想CDを作ってマウントしするという作
業のくり返しです。けっこうたいへん。(^^;
★1: 項目00000「アイ(藍)」にパッチを当てたときのふるまい
------------------------------------------------------------------------
項目00000「アイ(藍)」先頭付近のデータ:
02 01 10 25 00 00 91 61 1B 79 05 EC 1F CF C2 15 BF E4 BF F3 8D 12 62
[不明のヘッダー部分]
pos=0x0000, 02 → 01 大きく化ける
pos=0x0000, 02 → 00 “項目データの取得に失敗しました”
pos=0x0001, 01 → 00 タグや改行だけ化ける
pos=0x0001, 01 → 02 暴走する
[これ以降圧縮本文?]
pos=0x0006, 91 → 90 化ける(※1, ※2)
pos=0x0006, 91 → 8f 化ける(※1, ※3) ★2:出力結果
pos=0x0006, 91 → 92 暴走する
pos=0x0006, 91 → 00 大きく化ける
pos=0x0007, 61 → 60 途中少しだけ化ける(※4)
pos=0x0007, 61 → 5f 途中少しだけ化ける(※5)
pos=0x0007, 61 → 5e 途中少しだけ化ける(※6)
pos=0x0007, 61 → 3c 大きく化ける
pos=0x0008, 1b → 1a 変化なし?
pos=0x0008, 1b → 19 変化なし?
pos=0x0008, 1b → 00 大きく化ける
pos=0x0009, 79 → 78 大きく化ける
pos=0x000a, 05 → 04 大きく化ける
pos=0x000b, ec → eb 大きく化ける
pos=0x000c, 1f → 1e 大きく化ける
pos=0x0080, e3 → e2 大きく化ける
pos=0x00c0, c8 → c7 本文10バイトめあたりから大きく化ける
pos=0x0100, 51 → 50 本文70バイトめあたりから大きく化ける
pos=0x0200, 1b → 1a 本文330バイトめあたりから大きく化ける
pos=0x0300, 3c → 3b 本文650バイトめあたりから大きく化ける
※1 先頭付近の文字列が後半で出現する
※2 SGMLのタグらしきものが見える
<TOC>
</ITALIC>
</SPECIAL FNAME="HDHゴシック">
<RUBIITA
※3 SGMLのタグらしきものが見える
<TITLアイ(藍
<YOMIアイ
<EUTITLChineseindigo||Polygonum<ITALItinctorionum</ITALICLour.TLE>
<AREFJ33023Z19"001イラストA000
※4 (イラスト) → (:>・:0001:>イラスト)
(イラスト) → (:>2+:0001:>イラスト イラスト)
※5 (イラスト) → (Z1>+:0001:>イラスト)
(イラスト) → (Z12+:0001:>イラスト イラスト)
※5 (イラスト) → (001+:0001:>イラスト)
(イラスト) → (002+:0001:>イラスト イラスト)
------------------------------------------------------------------------
★2: pos=0x0006, 91 → 8fのパッチを当てたときの出力結果
------------------------------------------------------------------------
<TITLアイ(藍>()<YOMIアイY><EUTITLChineseindigo∥Polygonum<ITALItinctorio
num</ITALICLour.TLE><B濃青色,いわゆる藍色の:>染歴採るためにる栽されるタ
デ科の一年草(TOC><+Z2:00⇒<AREFJ33023Z19"001イラストA000】</)B01ンジゴ
と呼ばれる藍色の:>染歴採る植物本は,MIアのほかにリュウキュウキアStrobila
nthes</SPECIALIC>SPECIALFNAME="HDHゴシック">cusia</SPECIALICO.Kuntze(キ
ツネノマゴ科)や01ンドキキアャRマツナギ属の:・CR>種,M}メ科)(TO9><+Z2:00
⇒<A REFJ33023Z12"001イラストA000】<2,+19>3+Z2:00⇒<A REFJ33023Z13"001
イラストA000】<3)などいくつかあるところから,とくにMIアを区別としタデMI
アとも呼ぶ。東南MIジア原産で代,国では古くからる栽されるタデ科の一年草(
TOC><+Z2:00⇒<AREFJ33023Z19ウキュ・。中世・は飛鳥時代以前に:00J33渡来史
⊃東・ウる。葉は先ク"ニがった卵形<+Z2柄は短く,全体R>東頭赤みを帯び黒ず
んだ緑<+ZニデM驕B茎の高19ο50R>東~80cm">Sヌ"HDネり,先端部が細呼く枝分
イ・しキュζ,夏330gま⊃<ヘ白<+Z2小花を穂状330迪トせM驕B宴Xラハ実は長さ2
mm">Sヌ"HDネり,先端部が細呼く枝分イ・しキュζ,夏330gま⊃<ヘ白<フM驕B茎
黒褐閨Cノ熟す帯び果実のM驕竭随艪轤骰ヘ品種="H謔阨マ異が大きい。藍色。中
品種="Hヘ小上粉<RUBIネの宛H謔、こ</RUBIネ,上粉百貫茎4貫茎小。中千本茎
縮藍<RUBIネちぢSヌ" い</RUBIネらる根れる分・渡来史藍>(オキリe地で⊃世△
全測,明治がっ後半<ヘ白<黷驛^デZ2:00⇒<A 渡来捨緑<+ック">Strフ輸入や草・
らに>(オロ≒ャック">Strフ開念C>="H謔ナ⊃<ヘ激減,全。,束R>東瞳Z2洲合△
鯛木綿Iネらで001FもIネが比較的宛H「うび果邪呼ど渡来獅級品をigoSに需要は
根強19ο一を・東~地域地で⊃<ェ続/TI躋>世↓全。主産各掴徳島県び果芝根れ
る分・渡来史藍>(オキリe地で⊃世△全測,明治がっ後半<ヘ2~3月主種子オキワ
き(オフに苗を買mヨレ呼ど擢。測,に需要は前作lノフムギニく、間に植えハ実
のM開花直デMフ7月中ご世∨茎Dネを収械藍えハ資ゥR>東瞳Z2洲合△鯛木綿Iネら
で001FもIネが比較的宛H「うび果邪呼ど8渡来作lロト生,夏比較的宛H「うび地
l頭や草・らに>(オロ≒ャック">Strフ開念C>="H謔ナ⊃<ヘ激減,全。,束R>謦[
セ緑(オロ㎏ia</SPECハ実草・OC>兼ェm潤Cノナ乾燥・堆積藍>(<ヘ2~3語トど・
小ゥニくト[部リ世・藍>(sDネc阜至ヤ発酵随荵023Z12"001イラストA000】<2,+
19>3+Z2:00⇒<A REFJ33023Z13"0とォい「腐葉土か・="Hネど棟nす種="H燥・・轣
C国では古くからる栽されqス科の一年草ネらで00キく3Z13"琅較的・REFR>悼Pに
る紐>東ツき固cナト藍玉、びツく試・"H白<黷驛^デZ2:00⇒<A 渡来捨緑<+ック">
Strフ輸入や草・らに>(オゴtrフ与デ・"10%の不溶性,束あるが含ま13"0とォい
「腐葉土か・="Hネど棟nす種="H燥・・轣C国では古くからる古くる栽木灰浮ヲホ
灰浮ふ・籤を加ど・Z13"琅較的・REFR水"H燥・・轣C衡に彪ル藍玉、びツく試藍
焦⊃<ヘ果邪頚トどミれq空気「全001・と酸化△全測・明漆びキ<柄はノ植えハ
実のM開花直デMフ7月中ご世∨茎Dネを収械藍えハ資ゥR>東瞳Z2洲ク">St半ヌ"
い</OC>=023Z19ウキュ・。中世・は飛鳥時代以前に:00J33渡来史⊃東ハ、や鴛i
・東瞳Z2洲ク">St半ヌ" い</OC>=023Z19ウキュ・。中世・は飛鳥時1・とヘ解熱
・解毒="H燥フ薬用rフ癌笆リ綿レク+19>染料としての藍【】日昧世・は飛但。・
87">星川 清親ャ上粉ら・/YO,広De(キツネノマゴ科)C広Deネ)や0
藍ォ,l類、びナSヌ"収蒲・">S古くLZ2:00古⇒代エ較砺ト全00染時測残吹ウトナ
リr刀ヒ<Aローマ(sDネc阜至ヤ発酵随荵023Z12"001イラストA000】<2,+19>3+Z2
:00。<Ccum(顔料)子オ鼬ケは IB<Ca(・フM驕B茎黒褐閨Cノ熟す帯び果実のM驕竭
随艪轤骰ヘ品種="H謔阨マ異・に由ネらフ与<A REFJ「う頭やm(兜マ異・=0Tマ異X
ク小叡qオ・書笆リ></文の不離製法の記述び地l頭や代≒ャッ・A 渡来捨欄DEA
ロ^C>=吹ウと賜<+発柱至ヤで0思⊃<ノ:0J3302ナ開花直デMフ7月中ご世∨茎Dネ
を収械藍えハ資ゥR>東瞳Z2洲ク">St半ヌJ3302ナ開花フM鬚る倦吹ウb<SB技術C国
ュる宰大陸 REFJ33igoSに需要の開ネREAK L至ヤ・洲ク">St半ヌJ3302ナ開花フM
鬚る倦吹ウb<SB技術C国ュる宰大陸 REFオZ2洲ク">S/OC>=023Z19ウキュ・。中世
・は飛鳥時1・とヘ解熱・解毒="H燥フ薬用生えハ・月鎬・煙瞳てを収。・中か10
⌒ぜノ苗ワナは古くからる栽されqス科の一年草ネらで00キく3Z13"琅較的・R染
料としての藍【】日昧世・は飛但。注iI宛H「Z出縁Fヰ洲n来史灰汁Cラスト z</
す種="H燥・・轣C国では古くからる栽されqス科の一年草ネらで0練縁Fyか・="H
ネど棟nす種="H燥・・轣C国では古くからる古くる栽木灰浮>Stヲす種>Z2<A 《延
喜式℃〈貲布(麻)一端,乾</文の不離製法の記述び地l頭や代≒ャッ・A 渡来捨
欄DEAロ二斗sDネD一斗sD薪卅斤〉ナ00キ事轤ノ>(・ス乾狽ヲホ灰一・RU建・鐘行
A。注iI宛H「Z出縁Fヰ洲n来史灰汁Cラスト z</す種="H燥・・轣C繚成閨CAルカ
リ<ヘ果写・日デ・"任R>ツ・フ与<武ャと酸麻布">SD一斗sD星平安・"炎㎏i中期
宰CR>ツ・ナ称方デMフ=023ヘ古く鎌倉中期栽らる席らで栽品る栽ニくト[「n来≒
ャ閨CAやm+R>゜>3+ロの>ツ・フ与<武ャと酸麻布">SD一斗sD星平安・"炎e易柱守
・Sト[部リ世・藍>(sDネc阜至ヤ発酵随荵023Z12"001イラストA000】<2,+月轤<
テく・sを防ぐ・成靄成功>St半ヌ" い</OC>=023Z19ウキュ・。中世・は飛鳥時
代以前に:00栽らる析夏季D一・RU建・鐘行A。注iI宛H「Z出縁Fヰ洲n来史灰汁Cラ
スト z</作業粉ら・鳥靄成qびセ。痛土収蒲藍壺期在置3Z19ウ加熱<Z5:0ェ四季R
EAハ試Aツ・フ歴可能る随nb轤ノ>コ町功>St半ヌ" い</OC>=023Z19ウキュ・。
中世・は飛鳥時代以前に:0紺屋全測・明痔や瞳Z2洲Fヰ<2Å・迯LD近年ヘ果・ロ
の宮城県栗駒町R>・葉蛮推ノ(1889‐1980)が古Stヲャ上粉ウキュ伝承竭随莉の〈
正年草ヤAロ^Cオ明漆n束ぞめキ<柄S年ヘ果・ロの宮城県栗駒町R>・葉蛮推ノ(
1889‐1980)が古Stヲャ上粉ウ1955年文化庚="Hニ収肝与<月轤<テセ吻,l花フ⇒:
>日昧世・06粉ャg ⇒<A33igoo縁F琅較的・R<Z4:0002:>染料としての藍【】日昧
世・は飛26 $V井カH「o縁Fヰ洲n来史灰汁Cラ緑<+ッ</す種ク">Strフ輸入や草
・らに>(オロ≒ャεくか・igoク">Strフ開ト z</0C>="H謔ナ⊃<ヘ激ャεく・>
N">S/y収フ宮礁資ゥM・煙頚トどミれq空気「全001・と酸化△全測・明漆びキ
<柄はノ植えハ実のM吻←,+煌{<CR:0J330Xト・也,多でらフ与⇒騨<A 渡来捨緑<
+ック">Strフ輸入や草・らに>(オゴtrフ与デ・"10%の慕,か・曹フM開Μ上・:>
染N貢Aツ轣C3Z1瀲中阜至、や瞳ヒ騨<A 摘Aハ深くえハ獅ュえ浅くえ白>染カH「Z
所e鳥蒔q中瓢19ウ・Z12"001イラ収換端<逞多の・j灰汁Cラスト z</作業粉ら・
鳥靄成qびセ。痛土収蒲藍壺期在置3ZZ指穃(兜都蛮推ピ莅と随np沂求E2Åリ綿I
フ座セ吻客びオヒ騨<なは飛秩CかJgoカソ)子オ12"00著名ャ上粉ル椏頚ト九条・
trフ兜玉。,・5世紀87"ホ以降,九条寝藍Iフ座ャ上粉トュ・。中世・は飛鳥時
代以前に:00栽らる析夏季D一・RU建・鐘行葉・モトと占【】<ニXトノ成付泣京東
寺を乾場80)が古千,粉メC寺と相論フ薬ミ実お任ciリr刀ヒ<Aローマ(sDネc阜
至ヤ発酵随荵023Z12"001イラストA000】< z<以降,九条寝藍Iフ座ャ上粉トュ・
。中世・は飛鳥時代以前に:00栽ら史鰹骭ァ中瓢19モ>Stヲ騨<業者を血z負ョ・12
"0屋・青屋・ウらに>(オゴ25941+煌紺く供彊慕,・日rフ兜栽らゥ・収寄斗sDネD
一斗sD薪卅斤〉ナ00キ事轤ノ>986ス乾・・将生慕,か・染カH「7所eLュ・9ウキ
・ル・]戸柄は相論ベニバュからi・丈ケT香OCオ磨q三草る随一紘紺襖は飛ヤ藍>(
sDニ粉ら代表・St商品直デMニテZ収フ宮純テぺ></文の不離製法の記述び地l頭
や代≒ャッ・A 渡来捨欄DEA本格 《キ0練縁FN12"0う頭お任・jキ23Z2洲クバュ・
>星平ノ紺衛正年23Z山城らぽ津纒イc粉・Z,寺と鯛m(兜sDネい・A本格 《キ0練
縁FN12"0う頭お任・jキ23Z2洲クバュ・>曹`Cラ聯濃・SB技阿氾く06粉・・j梶B阿
氾く06粉・・j梶B阿氾く06粉・・j梶B阿氾く06粉・・j梶B阿氾く以降,ャ上普C
九作の存在粉・・j梶B阿氾く06粉・・j梶B阿氾く06粉・・j梶B阿氾く以降,ャ穣
縁Fn来C九作の存在粉・・j梶B阿氾く06粉・・j梶B阿氾く06粉・・j梶B阿犯ネい
ノ蜂須賀氏輅・・糟ト季藩・E要財孤棟nす種="H燥・・轣C国では古くからる古
くる栽木灰浮>Stヲす種>Z2゜浅く古くからる保護・奨励纒イコで発展花フM鬚る
倦吹ウb<SB技術C国ュる宰大陸 REFオZ2洲ク">S/OC>=023Z19ヮw穃(740年(元文5
ウ薗イ査S測♀D浮>ヘ〈北">S不Dネい・A本格 《キ0練縁FN12"0う頭お任・jキ23Z
2洲クバュ・>染翌竭地方は灌漑ニ収鰹°g制約>染カ{格 ∬稲 《ェ紺衛許容イャg
ク>・)R貲布ヨ係DネD一張肓随_民生褐zトほ^<佼6粉成閨吉野川流域)全葬・コ
コに鏡吻客びオヒ騨<なは飛秩CかJgoカソ)子オ1ノ依・‐19阜く倦S村・8い・i
《キ0勇楠と綿テZ惨葬・代表・St商品直デMニテZ収フ宮純テぺ></文の不離製
法の記述び地l淘ホ応(オロ㍽w穃ヘ急速に拡大5:ヘ・80シ東・寛政12)ム地l淘
吹tけ6タャ宿aテく・ハロ㍽高17.9万俵(約1.4sェ紺奥t蛮進goo縁F琅較的・R<Z4:
0002:>染料としての藍【】・)Fク随艨qイ・・C告d厂・ヲ2"0なは矧ヤ引d卅技出
縁閧瘰・謔闢y用・(オビ梶B、2"0世・"0吻客びオヒ騨<なは飛秩CかJgoカソ)子
オ1ノ依・‐19阜く倦S村・8い、かJ2:0ェフ播種閨y】<ニヘ葬n臠A000¢S・"矧
。安・ワ000恁ウ俵建・害虫駆除6粉{肥・「鞄V>染フ灌水。,柁重労働ヵ月間発
酵随荵023Z12"001イラストA000】< z<以降,九条寝藍Iフ座連熟c来史梶穃+R>
゜>3+9‐tオ1ノ依・‐19阜く倦S村・8い、かJ2:0ェフ播種閨y】<ニヘ葬n臠A000
細="円prフ易窒ウ6q>・ケ綿z全装イ成イュ珞木綿z「の曲し41+煌紺q吹ウb<SB
技術C国ュる宰大陸 REFオZ2洲ク">S/OC>=023Z19ヮw穃(740汎連枷コ・8い*k鰹骭
ィノ依・≠フM吻丹念igoナ R<ルt泣寝絡ナ庫及Cかニ茎ン粉成ヰュ12)、OC>・謔
ト骰ノ総・lz</克闌テStヲ驍オ41イ・・渣・∑ヰls莅と・:ツ埼宰綜t流域゜浅東
屡ネい集00303:ュ著緬綜t轣Cオ41イ〈北各潔ョ・オ4><薦楠SPECIALEFオZ2捷・)
澎C>=023Z1て骰玉41+・全ュノ土・0⊇造轤髟q北各郡汁CラΞ閨拠n・ニ頻C昨形ゥ
,+:>染翌竭地方は灌漑ニ収鰹°g・い°ハ><<SP論フ法N">S自宅びオヒ梶BQ床<SP
論謔ヤZ12"・シャヲすB技渉Dネ・3:ュ・円pイろ梶BQ床<SP論謔ヤZ12"・シャヲす
B技渉Dネ・3:ュ・円pイろ梶BQ床<SP論謔ヤZjバd込み ∬・ヵ基本<至ヤ梶BO後20
堰qイ・C国・j給鳥屡用・ュ以ラロ艶ァ約>染カ{格 ∬稲 《ェ紺衛許容イャg ク
>S自宅びオヒ梶BQ床<SP論謔ヤZ12"・シャヲす以y用ーALEFオZ2藍【_絡ナ工程け
6タャ国条寝欄x合にXトカナ⊃・チ減俵(約1.゛ず,しく,熟練A 摘Av矧ヤ引d・
ツ塞棟nヘ灌漑ニ収鰹°g・い°ハ><<SP論フ法N">S自宅びオヒ梶BQ床<SP論謔ヤZ1
2"
(c) 1998 Hitachi Digital Heibonsha, All rights reserved.
------------------------------------------------------------------------
★3: 正常な出力結果
------------------------------------------------------------------------
アイ(藍)
アイ Chinese indigo∥Polygonum tinctorium Lour.
濃青色,いわゆる藍色の染料を採るために栽培されるタデ科の一年草(イラスト
)。インジゴと呼ばれる藍色の染料を採る植物には,アイのほかにリュウキュウ
アイ Strobilanthes cusia O. Kuntze(キツネノマゴ科)やインドキアイ(コマツ
ナギ属の数種,マメ科)(イラスト,イラスト)などいくつかあるところから,
とくにアイを区別してタデアイとも呼ぶ。東南アジア原産で,中国では古くから
栽培された。日本へは飛鳥時代以前に中国から渡来したとされる。葉は先のとが
った卵形で,柄は短く,全体が赤みを帯び黒ずんだ緑色となる。茎の高さは50~
80cmほどになり,先端部が細かく枝分れをして,夏に紅または白色の小花を穂状
に咲かせる。果実は長さ2mmほどの卵形で,黒褐色に熟す。葉の形や草丈などは
品種により変異が大きい。栽培品種には小上粉(こじようこ),上粉百貫,百貫,
小千本,縮藍(ちぢみあい)などがある。古くから日本各地で栽培されていたが,
明治時代後半になるとインドキアイから採ったインジゴの輸入や,さらに合成イ
ンジゴの開発により栽培は激減した。しかし,色合いや木綿などでの色もちが比
較的よいことなどから高級品を中心に需要は根強く,一部の地域で栽培が続けら
れてきた。主産地は徳島県である。2~3月に種子をまき,春に苗を畑に移す。徳
島などでは前作物のムギの畝間に植える。開花直前の7月中ごろに茎葉を収穫す
る。さらに8月に再生した茎葉を収穫することもある。葉から染料を採る。収穫
した葉を刻んで乾燥・堆積し,これに水をかけては切り返し,2~3ヵ月間発酵さ
せると黒い腐葉土のようなものとなる。これを多(すくも)と呼び,臼に入れてつ
き固めて藍玉をつくる。この藍玉には2~10%の不溶性のインジゴが含まれ,こ
れに木灰,石灰,ふすまを加えて発酵させると水溶性のインドキシルとなる。こ
れが藍汁で,布を漬けて空気にさらすと酸化されてふたたびインジゴになり,染
色される。またアイの葉や果実,藍玉は解熱・解毒などの薬用にもされた。
星川 清親
【染料としての藍】
藍は人類が最も古く利用した青色染料である。古代エジプトの藍染布が残ってお
り,古代ローマのindicum(顔料)の語源は India(インド)に由来するという。古
代インドのサンスクリットで書かれた文献製法の記述がある。古代中国ではタデ
アイを栽培していたから独自に発達したと思われ,日本でもタデアイを用いるか
ら,染色技術とともに大陸から渡来したとみなされる。古代日本ではタデアイの
生葉をすりつぶして水を加え,かきまぜ,袋に入れて絞り,浸出液を染液として
灰汁(あく)練りをした絹を染めた。《延喜式》に〈貲布(麻)一端,乾藍二斗,灰
一斗,薪卅斤〉の記事があり,乾藍による藍建ても行われ,灰汁のアルカリによ
って日数をかけて発酵を助成し,麻布類を染めたことがわかる。平安の初期から
中期にかけてはこの方法を続けたが,鎌倉期には木灰とともに石灰を用いてアル
カリ性を強め藍菌の発酵を容易にするとともに,腐敗を防ぐことに成功した。藍
建ては夏季の作業であったが,しだいに土間に藍壺を設置し,加熱によって四季
を通じて藍建てを可能にし,室町期には紺屋(こうや)の発生をみた。近年では宮
城県栗駒町の千葉アヤノ(1889‐1980)が古来の藍建てを伝承し,その〈正藍染(
しようあいぞめ)〉は1955年文化財に指定された。なお,緑染は藍と黄色染料と
の交染によって得られる。⇒インジゴ
新井 清
【日本における栽培・流通の歴史】
[古代,中世] 藍汁をもってする藍染は,染色のなかでも基本的なものとして
,最も多く用いられたので,アイは百姓の屋敷地でよく栽培され,荘園によって
は藍を年貢とする地もみられた。藍色には深藍,中藍,浅藍,白藍などの各種が
みられ,《延喜式》にはすでに藍染のことがみえる。都市ではこの藍を供給する
ための座が結成され,なかでも藍生産地として著名であった京都の九条一帯には
,15世紀半ば以降,九条寝藍座があって藍の売買を独占し,ときには付近の東寺
を乾場としたため,寺と相論をひきおこした。なおこの藍汁をもって染色する業
者を,藍屋・藍染屋・青屋・紺屋(こうや)などといった。 川
嶋 将生
[近世] アイ(タデアイ)は江戸時代にはベニバナ・アサとともに〈三草〉の一
つに数えられ,日本を代表する商品作物とされた。その栽培が本格化するのは,
木綿生産が盛んとなる近世に入ってからである。江戸初期には山城,摂津,尾張
,美濃などでの栽培が知られるが,その主産地は阿波であった。阿波ではすでに
中世に藍作の存在が知られるが,とくに蜂須賀氏の入国後,藩の重要財源として
蜂須賀氏の保護・奨励の下で発展した。1740年(元文5)の調査では藍作は〈北方(
きたがた)〉(吉野川流域)全村に及び,吉野川中下流域の名東・名西・麻植・板
野・阿波各郡を中心に藍作地帯を形成した。この地方は灌漑技術上の制約により
稲作が半ば許容されず,かつ耕地の8割ちかくが藍作に好適な砂質土の畑地で占
められていた関係もあって,農民生活のほとんどは藍作に依存していた。とくに
18世紀以降,畿内の綿作の発展に対応して生産は急速に拡大し,1800年(寛政12)
には作付け6500ha,藍玉生産高17.9万俵(約1.4万t)に達した。〈阿波藍〉は〈藍
の種まき生えたら間引き,植えりゃ水取り土用刈り〉とうたわれたように,2月
の播種(はしゆ)から7月の収穫まで除草,害虫駆除,施肥,炎天下の灌水作業と
重労働の連続であった。収穫した〈葉藍〉は細刻して乾燥させ,〈藍粉成(あい
こなし)〉といって連枷(からさお)で丹念に打ちほぐし,最後に葉と茎にわける
。こうして〈藍作人〉の手になる葉藍は,次に仲買人により〈藍師〉のもとに買
い集められる。藍師は葉藍から染料の〈多(すくも)〉〈藍玉〉をつくる藍玉製造
業者で,〈玉師〉ともいう。自宅に〈藍寝床〉とよぶ作業場をもつ。葉藍は9月
ごろ藍寝床に仕込み,約3ヵ月間,前後20回にわたって給水とかくはん,保温を
繰り返し,漸次発酵させて多に仕上げる。この作業工程では葉藍の発酵度合に応
じた水加減がむずかしく,熟練技術を要した。そのため藍師はこの工程では〈水
師〉とよばれる専門の職人を雇う場合が多かった。葉藍100貫目(約375kg)から50
~60貫目(約188~225kg)の多が生成された。多はそのままでも売買されたが,た
いていはさらに〈藍臼〉でつき固めて藍玉に加工(藍つき)された。できあがった
藍玉は藍師・藍商により全国の売場先に積み出され,各地の〈紺屋〉に供給され
た。
こうして藍師は阿波藍の生産と流通を支配したが,1767年(明和4)には阿波の
総藍師は1289人を数えた。なお藍師は在方では,藍作に欠くことのできない肥料
(とくに干陛(ほしか))や経営資金の前貸支配によって藍作人への経済的支配関係
を強化し,質地地主として大土地を集積する藍師も出現した。他方,藍作人は藍
作の展開に伴って,逆に商品経済の好品となり経営が破綻し,貧窮化の様相を強
めた。ところで徳島藩では阿波藍の利潤に注目し,1733年(享保18)には〈藍方御
用場〉を新設し,葉藍取引税の徴収など葉藍専売制ともいうべき政策に着手した
。しかし56年(宝暦6)の〈藍玉一揆〉(五社宮騒動。葉藍取引税,藍師株の撤廃を
要求)により藩の支配は大きく後退し,藍方御用場も廃止された。その後66年藩
主蜂須賀重喜は藩政改革の一環として〈藍方役場〉(翌年〈藍方代官所〉と改称)
を再興,その監督下で城下市中に藍玉売場(のち〈藍大市〉として盛況)を開設し
た。また藍師層と提携して大坂市場の直接掌握を図るなど積極的な国益政策を展
開し,さらに享和~天保期(1801‐44)にかけて関東売場株,大坂ならびに畿内売
場株の設定を皮切りにして31にのぼる全国売場株の成立をみた。全国の藍玉市場
の独占支配をめざしたものであるが,他方この前後から関東の武州藍をはじめ尾
張・美濃・山城・安芸・備前・因幡・長州・久留米・醍摩など各地でも〈地藍〉
の生産が活発化した。広島・長州藩などでは〈藍座〉を設置し,他国藍の移入を
禁じて自国藍の奨励と自給体制の確立をめざしている。明治維新後も全国的な需
要増により藍生産は拡大し,阿波藍は1903年に作付け1万5000ha,葉藍生産約2.2
万tと史上最高を記録した。しかし,開国以来のインド藍の大量輸入や国内の染
織業界の機械による工場生産への切替えは,しだいに阿波藍をはじめ国内藍の基
盤をゆさぶった。これに対処して五代友厚の朝陽館による製藍法の改良事業など
が興り,徳島でも五代友厚が1874年名東郡下に工場を設置し,精藍事業に着手し
た。さらに99年には長井長義の指導のもとに精藍伝習所が設置され,いわゆる長
井製藍が始まった。しかし,この前後から人造藍(化学染料)がドイツから大量輸
入されるに及び,国内藍・インド藍を駆逐して日本の市場を制圧した。ために阿
波藍も明治30年代後半を境に以後急速に低落した。現在では郷土の伝統産業とし
て,わずかな藍作農家が江戸時代以来の伝統的な藍作を継承し(1981年の栽培農
家67戸,作付け14.1ha,葉藍生産42t),技術の保存発展と後継者の育成に努めて
いる状況である。
高橋 啓
(c) 1998 Hitachi Digital Heibonsha, All rights reserved.
------------------------------------------------------------------------
Jamming は Macintosh版もあるからやっぱり解読してそうですね。
体験版を引っぱり出して色々やってみました。
各圧縮ブロックの最後の1バイトを2進ダンプしてみると、
$ for i in *;do tail -c 1 $i|bbd;echo;done|sort|uniq -c|sort -nr|head
620 00000000
586 10000000
336 11000000
297 01000000
166 11100000
165 10100000
159 00100000
147 01100000
88 11010000
84 00010000
このことから、圧縮後のバイト単位の暗号化はされておらず、
最上位ビットからのビットストリームのような気がします。
次に先頭8バイトは項目のサイズによりおおまかに2種類ありそうです。
$ for i in $(ls -S |head);do bskip 6 < $i|bhead 8|bbd;echo;done
10011010 01100001 00000011 11110000 11000100 01000000 11100011 10011111
10010001 01100001 00011011 01111001 00000101 11101100 00111000 00010011
10010101 01100001 00010001 11001010 10100100 01101000 11010100 01110111
10011010 01100001 00000011 00001000 11100011 10101101 11100010 10011000
10011010 01100001 00000001 11111100 11111100 01001111 00100110 00000001
10011010 01100001 00000011 00100011 10100011 11100000 10100001 11001010
10011010 01100001 00000100 01000111 01100011 10100111 10000001 11001011
10011010 01100001 00000011 11110000 11000100 01000000 11110011 01101100
10010101 01100001 00010001 11001011 00111100 01100000 10011000 01111000
10010101 01100001 00010001 11001000 11100000 01111000 10100000 01101111
$ for i in $(ls -Sr |head);do bskip 6 < $i|bhead 8|bbd;echo;done
10011011 01111100 01100001 11111100 11011100 01001111 00010100 10010011
10011011 01111100 01100010 10001101 11100011 01000000 00010011 00001111
10011011 01111100 01100010 10001011 00100011 00001110 10110011 00001111
10011011 01111100 01100001 11111100 11011100 01001111 00010110 00001111
10011011 01111100 01100001 11111100 11011100 01001110 11000110 00001110
10011011 01111100 01100001 11111100 11011100 01001110 11000110 00001111
10011011 01111100 01100001 11111100 11011100 01001110 10110110 00001110
10011011 01111100 01100001 11111100 11111100 01001111 01010110 00000001
10011011 01111100 01100011 11011000 10000011 00011110 10101001 10000111
10011011 01111100 01100001 11111100 11111101 10100011 10001111 10110110
先頭付近SGMLタグの違いだろうか?
0, 9ビット目が 1 なので株式会社電子辞典の DDviewer形式と同じかと
期待しましたが、うまくいかない感じ。残念。
そうか、そうですね。
> 各圧縮ブロックの最後の1バイトを2進ダンプしてみると、
> ...
> このことから、圧縮後のバイト単位の暗号化はされておらず、
> 最上位ビットからのビットストリームのような気がします。
なるほど、これも気付きませんでした。
> 次に先頭8バイトは項目のサイズによりおおまかに2種類ありそうです。
> ...
> 先頭付近SGMLタグの違いだろうか?
そのようです。Jammingにパッチを当てて世界大百科事
典の本文のタグを解釈させないようにして('<'と比較し
ている部分をつぶした)いろいろ表示させてみたところ、
先頭が「<TOC></TOC><TITLE>」となっている項目は圧縮
データ先頭が0x9bになっているようでした。
> 0, 9ビット目が 1 なので株式会社電子辞典の DDviewer形式と同じかと
> 期待しましたが、うまくいかない感じ。残念。
おぼろげですが、LZSSのようです。cx.dllの中にSGMLタ
グが並んでいる部分があって、その部分を辞書の初期デ
ータとしているみたい。圧縮データにパッチを当ててみ
ると、その領域の別の位置から取ってきたものらしきデ
ータが表示されますから。たしかに、圧縮する側と伸長
する側とで辞書の初期データを共有してよいのなら、数
多く出てくるタグデータを効率的に圧縮できるはずです
よね。
短い項目(項目00004「IIR」)の圧縮データのさまざまな
ビット位置の値を変更して、Jammingで表示される伸長
データがどのように変化するかを示した結果をつけてお
きます。短い項目は参照項目なので付属の検索ソフトで
はすぐに参照先が表示されてしまうのですが、Jamming
では直前の項目(項目00003「アイ(愛)」)のあとに続け
て表示されますから。結果をみてうなっているだけで、
まだ解析できるところまでには至っていませんが...。
cx.dllの逆アセンブルもしてみたのですが、スキル不足
でどういう処理をしているのかよくわかりません。(^^;
ただ、広いスパンでばーっとxorを掛けているような箇
所はどうやらなさそうでした。
以下、解析データです。
●Windows版Jamming 3.3へのパッチ当て
0x000ae4e8: 3c → ff
●項目00000~00049の先頭付近のようす(圧縮データ先
頭とJamming改で表示された伸長データ先頭)
00000: 91 61 1B 79 05 EC 1F <TOC><Z1+:0001:>イラスト</Z1+><Z2 アイ(藍)
00001: 9B 7C 61 FC DC 4E 7E <TOC></TOC><TITLE>アイ(間)</TITLE アイ(間)
00002: 9B 61 1F D1 43 00 DF <TOC><Z1:0001:>【〈愛〉の意味\xa5 アイ(愛)
00003: 91 61 1B 79 05 EC 1F <TOC><Z1+:0001:>イラスト</TITLE>< アイアイ
00004: 9B 7C 7D 5C 4E F4 C3 <TOC></TOC><TITLE>IIR</TITLE><YOM IIR
00005: 91 61 1B 79 05 EC 1F <TOC><Z1+:0001:>イラスト</Z1+></T アイアシ
00006: 9B 7C 61 FC DC 4E 7C <TOC></TOC><TITLE>アイアス<TITLE> アイアス
00007: 9B 7C 61 FC DC 4E 7C <TOC></TOC><TITLE>アイアトン<TITL アイアトン
00008: 9B 7C 7D 5E F4 C3 E3 <TOC></TOC><TITLE>IR</TITLE><YOMI IR
00009: 9B 7C 7D 5E F7 36 61 <TOC></TOC><TITLE>IRA</TITLE><YOM IRA
00010: 9B 7C 7D 5E 8F 36 61 <TOC></TOC><TITLE>IEA</TITLE><YOM IEA
00011: 9B 7C 62 89 98 8B 83 <TOC></TOC><TITLE>安威氏</TITLE>< 安威氏
00012: 9B 7C 7D 5E 6F 47 0E <TOC></TOC><TITLE>IAEA</TITLE><YO IAEA
00013: 9B 7C 7D 5E F9 8F 63 <TOC></TOC><TITLE>IS\xa5LM分析></ IS・LM分析
00014: 9B 7C 7D 5E FF 6E 61 <TOC></TOC><TITLE>ISO</TITLE><YOM ISO
00015: 9B 7C 7D 5E FF 70 8B <TOC></TOC><TITLE>ISP法</TITLE><Y ISP法
00016: 9B 7C 7D 5E 97 7A 61 <TOC></TOC><TITLE>IFR</TITLE><YOM IFR
00017: 9B 7C 7D 5E 97 7B 9D <TOC></TOC><TITLE>IFRB</TITLE><YO IFRB
00018: 9B 7C 7D 5E 97 83 C3 <TOC></TOC><TITLE>IFTU</TITLE><YO IFTU
00019: 99 61 1F 92 26 61 FE <TOC></TOC><Z1:0001:>[目的と組織 IMF
00020: 9B 7C 7D 5E CF 48 37 <TOC></TOC><TITLE>IMF‐JC</TITLE> IMF‐JC
00021: 9B 7C 7D 5E CF 6E 61 <TOC></TOC><TITLE>IMO</TITLE><YOM IMO
00022: 9B 7C 7D 5E C7 7E 61 <TOC></TOC><TITLE>ILS</TITLE><YOM ILS
00023: 99 61 1F 91 51 41 60 <TOC><Z1:0001:>[沿革と目的]</Z1 ILO
00024: 9B 7C 63 7D 42 17 0F <TOC></TOC><TITLE>秋穂[町]</TITLE 秋穂[町]
00025: 9B 7C 63 A2 C3 88 5E <TOC></TOC><TITLE>相生[市]</TITLE 相生[市]
00026: 9B 7C 63 A2 C3 88 5E <TOC></TOC><TITLE>相生[町]</TITLE 相生[町]
00027: 9B 7C 63 A2 C3 88 43 <TOC></TOC><TITLE>相生獅子</TITLE 相生獅子
00028: 9B 7C 7D 5E DF 3E 61 <TOC></TOC><TITLE>IOC</TITLE><YOM IOC
00029: 9B 7C 61 FC DC 4E 7E <TOC></TOC><TITLE>アイオリス</TIT アイオリス
00030: 9B 7C 61 FC DC 4E 7E <TOC></TOC><TITLE>アイオワ[州]</T アイオワ[州]
00031: 9B 7C 61 FC DC 4E 7E <TOC></TOC><TITLE>アイオン台風</T アイオン台風
00032: 9B 7C 61 FC DC 4E 7E <TOC></TOC><TITLE>アイガー[山]</T アイガー[山]
00033: 9B 7C 63 22 64 30 F3 <TOC></TOC><TITLE>合方</TITLE><YO 合方
00034: 9B 7C 61 FC DC 4E 7E <TOC></TOC><TITLE>アイガモ</TITLE アイガモ
00035: 9B 7C 63 22 63 8F 1E <TOC></TOC><TITLE>合川[町]</TITLE 合川[町]
00036: 99 61 1F 92 37 C1 AF <TOC><Z1:0001:>[歴史]</Z1></TIT 相川[町]
00037: 9B 7C 62 86 03 8F 1E <TOC></TOC><TITLE>愛川[町]</TITLE 愛川[町]
00038: 9B 7C 62 89 03 8F 02 <TOC></TOC><TITLE>鮎川義介</TITLE 鮎川義介
00039: 9B 7C 62 86 02 CD 63 <TOC></TOC><TITLE>愛玩動物</TITLE 愛玩動物
00040: 9B 7C 61 FC DC 4E 7E <TOC></TOC><TITLE>アイギス</TITLE アイギス
00041: 99 61 1F 91 91 31 7E <TOC><Z1:0001:>[合気]</Z1><Z2:0 合気道
00042: 9B 7C 61 FC DC 4E 7E <TOC></TOC><TITLE>アイギナ[島]</T アイギナ[島]
00043: 9B 7C 7D 5E EC C3 E3 <TOC></TOC><TITLE>IQ</TITLE><YOMI IQ
00044: 9B 7C 63 A2 C2 F8 53 <TOC></TOC><TITLE>相給</TITLE><YO 相給
00045: 9B 7C 62 86 02 E9 23 <TOC></TOC><TITLE>愛郷塾</TITLE>< 愛郷塾
00046: 9B 7C 62 85 D8 8E 62 <TOC></TOC><TITLE>阿育王</TITLE>< 阿育王
00047: 9B 7C 61 FC DC 4E 7E <TOC></TOC><TITLE>アイクシュテッ アイクシュテッ
00048: 9B 7C 6F AB 8D 8E F3 <TOC></TOC><TITLE>\xf1\xd0琿</TI {王愛}琿
00049: 9B 7C 6F AB 8D 8E E3 <TOC></TOC><TITLE>\xf1\xd0琿条約 {王愛}琿条約
●短い項目の先頭付近のダンプと伸長データ全体
00004: 02 01 6D 00 00 00 9B 7C 7D 5C 4E F4 C3 E4 0F E6 E0 F3 E3 C0 61 BE 7B 82
00008: 02 01 6C 00 00 00 9B 7C 7D 5E F4 C3 E3 0F E6 E0 F3 EF E0 06 F9 EF 8B CB
00012: 02 01 74 00 00 00 9B 7C 7D 5E 6F 47 0E 61 F2 87 DF C0 E7 DE E9 86 F9 EF
00013: 02 01 7F 00 00 00 9B 7C 7D 5E F9 8F 63 B2 42 6C 38 B3 30 FA 83 F9 B7 5C
00014: 02 01 6F 00 00 00 9B 7C 7D 5E FF 6E 61 F2 07 F3 70 39 F7 BA 77 BC 96 E2
00015: 02 01 6B 00 00 00 9B 7C 7D 5E FF 70 8B 99 30 F9 83 F9 B7 DC FB BD 3B BE
00016: 02 01 6F 00 00 00 9B 7C 7D 5E 97 7A 61 F2 07 F3 70 39 F7 BA 77 80 2D BF
00017: 02 01 7C 00 00 00 9B 7C 7D 5E 97 7B 9D 30 F9 43 F9 B7 FC FB DD 3B C0 16
00018: 02 01 89 00 00 00 9B 7C 7D 5E 97 83 C3 30 F9 43 F9 B7 FC FB DD 3B C0 16
00004:
<TOC></TOC><TITLE>IIR</TITLE><YOMI1>アイアイアール</YOMI1>
<BODY>⇒<A REFID="65417000">ブチルゴム</A>【改行】</BODY>
00008:
<TOC></TOC><TITLE>IR</TITLE><YOMI1>アイアール</YOMI1>
<BODY>⇒<A REFID="04804000">イソプレンゴム</A>【改行】</BODY>
00012:
<TOC></TOC><TITLE>IAEA</TITLE><YOMI1>アイエーイーエー</YOMI1>
<BODY>⇒<A REFID="26374000">国際原子力機関</A>【改行】</BODY>
00013:
<TOC></TOC><TITLE>IS【0xa5】LM分析</TITLE>
<YOMI1>アイエスエルエムぶんせき</YOMI1>
<BODY>⇒<A REFID="71747000">マクロ経済学</A>【改行】</BODY>
00014:
<TOC></TOC><TITLE>ISO</TITLE><YOMI1>アイエスオー</YOMI1>
<BODY>⇒<A REFID="26434000">国際標準化機構</A>【改行】</BODY>
00015:
<TOC></TOC><TITLE>ISP法</TITLE><YOMI1>アイエスピーほう</YOMI1>
<BODY>⇒<A REFID="00293000">亜鉛</A>【改行】</BODY>
00016:
<TOC></TOC><TITLE>IFR</TITLE><YOMI1>アイエフアール</YOMI1>
<BODY>⇒<A REFID="22918000">計器飛行方式</A>【改行】</BODY>
00017:
<TOC></TOC><TITLE>IFRB</TITLE><YOMI1>アイエフアールビー</YOMI1>
<BODY>⇒<A REFID="26395000">国際周波数登録委員会</A>【改行】</BODY>
00018:
<TOC></TOC><TITLE>IFTU</TITLE><YOMI1>アイエフティーユー</YOMI1>
<BODY>⇒<A REFID="02474000">アムステルダム【0xa5】インターナショナル</A>
</BODY>
●項目00004のバイト0006~0009にパッチを当てて
Jamming改で表示したときのようす(※は推測)
・圧縮はLZSS???
・スライド辞書には最初からタグなどのデータが入っている
・フラグ + コピー文字数(7ビット) + コピー開始位置(11ビット)???
・フラグ + 文字(8ビット)???
・そのまま格納されてはいないようだ...
0006: 10011101 -> 00011011 (9b -> 1b)
^ ^
???...TLE></EUTITLE><BODY>??⇒<A REFID="00000000"></A>?????...
※不明
0006: 10011101 -> 11011011 (9b -> db)
^ ^
*e^8R></TOC><TITLE>(アRCアRCアーR?)</TITLE><YOMIEUTITLE><BOD65417?<A R[w???...
※不明
0006: 10011101 -> 10111011 (9b -> bb)
^ ^
<TOC></TOC><TITLE>()</TITLE><YOMI1></YOMI1><BODY><IIROMI1><EUTITLE><アイアイアール/EUTITLE><BODY(0x8140×6)6
<TOC></TOC><TITLE>
<TOC></TOC><TITLE>()</TITLE><YOMI1></YOMI1><BODY><
※コピー文字数が+0x20変化した
0006: 10011101 -> 10001011 (9b -> 8b)
^ ^
???...TLE></EUTITLE><BODY>??⇒<A REFID="00000000"></A>???...
※不明
0006: 10011101 -> 10010011 (9b -> 93)
^ ^
<TOC></TOCIIRTITLE>()</TITLEアイアイアール><YOMI1></YOMI<BODY>??⇒<A65417D="00ブチルゴム000000「』『?t
※コピー文字数が-0x08変化した
0006: 10011101 -> 10011001 (9b -> 99)
^ ^
<TOC></TOC><TITLIIR()</TITLE><YOMIアイアイアール1></YOMI1><BOD??⇒<A REFID6541700000ブチルゴム"></A>
</BODt
※コピー文字数が-0x02変化した???
0006: 10011101 -> 10011111 (9b -> 9f)
^ ^
<TOC></TOC><TITLE>()</IIRTLE><YOMI1></YOアイアイアールMI1><BODY></YO REFID="000065417></A>ブチルゴム??(0x8140×2)DY>
※コピー文字数が+0x04変化した???
0006: 10011101 -> 10011010 (9b -> 9a)
^ ^
<TOC></TOC><TITLEIIR)</TITLE><YOMI1アイアイアール></YOMI1><BODY?⇒<A REFID=654170000"ブチルゴム></A>\?</BODYt
※コピー文字数が-0x01変化した
0007: 01111100 -> 11111100 (7c -> fc)
^ ^
__________________???Z15:0008:>【】</Z15><Z16:0008:>【】</Z16><Z17:0009:<????蜘ー0010:>【】</Z18><Z19:0010:>?
※不明("Z15:0008:>"は+0x1f5ずれた位置にある)
0007: 01111100 -> 00111100 (7c -> 3c)
^ ^
11><Z12:0006:>【】^8R</TITLE><YOMI1>ア???...
※コピー開始位置が+0x1a2バイトずれた??
0007: 01111100 -> 01011100 (7c -> 5c)
^ ^
z</Z2><Z3:0002:>【IIR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※コピー開始位置が+0x100バイトずれた
0007: 01111100 -> 01101100 (7c -> 6c)
^ ^
(0x8140×9)IIR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※コピー開始位置が+0x70~+0x9aバイト(+0x80バイト?)ずれた
0007: 01111100 -> 01110100 (7c -> 74)
^ ^
E></EUTITLE><BODY>IIR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※コピー開始位置が+0x40バイトずれた
0007: 01111100 -> 01111000 (7c -> 78)
^ ^
I1></YOMI1><BODY><IIR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※コピー開始位置が+0x20バイトずれた
0007: 01111100 -> 01111110 (7c -> 7e)
^ ^
________________<TIIR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※コピー開始位置が-0x10バイトずれた?
0007: 01111100 -> 01111101 (7c -> 7d)
^ ^
________<TOC></TOCIIR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※コピー開始位置が-0x08バイトずれた?
0008: 01111101 -> 11111101 (7d -> fd)
^ ^
____<TOC></TOC><TIIIR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※コピー開始位置が-0x04バイトずれた?
0008: 01111101 -> 00111101 (7d -> 3d)
^ ^
OC><TITLE>()IIR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※コピー開始位置が+0x02バイトずれた?
0008: 01111101 -> 01011101 (7d -> 5d)
^ ^
TOC></TOC><TITLE>(IIR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※コピー開始位置が+0x01バイトずれた
0008: 01111101 -> 01101101 (7d -> 6d)
^ ^
<TOC></TOC><TITLE>?8R</TITLE><YOMI1>ア???...
※不明(Iのフラグ?)
0008: 01111101 -> 01110101 (7d -> 75)
^ ^
<TOC></TOC><TITLE>???...<TOC></TOC><TITLE>()</TITLE><YOMI1></YOMI1><BODY><
※不明(Iのビット位置?)
0008: 01111101 -> 01111001 (7d -> 79)
^ ^
<TOC></TOC><TITLE>??R</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※不明(Iのビット位置?)
0008: 01111101 -> 01111111 (7d -> 7f)
^ ^
<TOC></TOC><TITLE>iiR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※文字Iがiに(01001001 -> 01>1<01001)
0008: 01111101 -> 01111100 (7d -> 7c)
^ ^
<TOC></TOC><TITLE>99R</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※文字Iが9に(0>100<1001 -> 0>011<1001)
0009: 01011100 -> 11011100 (5c -> dc)
^ ^
<TOC></TOC><TITLE>QQR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※文字IがQに(01001001 -> 001>0<1001)
0009: 01011100 -> 00011100 (5c -> 1c)
^ ^
<TOC></TOC><TITLE>EER</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※文字IがEに(01001001 -> 0100>01<01)
0009: 01011100 -> 01111100 (5c -> 7c)
^ ^
<TOC></TOC><TITLE>KKR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※文字IがKに(01001001 -> 01001>01<1)
0009: 01011100 -> 01001100 (5c -> 4c)
^ ^
<TOC></TOC><TITLE>HHR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
※文字IがHに(01001001 -> 0100100>0<)
0009: 01011100 -> 01010100 (5c -> 54)
^ ^
<TOC></TOC><TITLE>I?R</TITLE><YOMI1>ア???...
※フラグが変わった?
0009: 01011100 -> 01011000 (5c -> 58)
^ ^
<TOC></TOC><TITLE>I??</TITLE><YOMI1>ア???...
※フラグが変わった?
0009: 01011100 -> 01011110 (5c -> 5e)
^ ^
<TOC></TOC><TITLE>I=1?f{Z5C{Z5C{ZーZ16:0008:>【】</Z16><Z17:0009:>【】</Z17><Z18:0???...
※フラグが変わった?
0009: 01011100 -> 01011101 (5c -> 5d)
^ ^
<TOC></TOC><TITLE>I???f{Z5C{Z5C{ZーZ16:0008:>【】</Z16><Z17:0009:>【】</Z17><Z18:0???...
※フラグが変わった?
■世界大百科事典第2版 解析データ
●sinidx.db
・総索引(356047件)
・EPWINGのhonmonと同じ構造でインデックスだけが含まれている。
(bookinfoで書籍管理情報が表示できる。参照先が存在しない点を
除いてsqueezeでもエラーが出ない。)
・再下位インデックスはEPWINGでは
BYTE 見出し語長さ(N)
CHAR*N 見出し語
DWORD 本文ブロック番号
WORD 本文オフセット
DWORD 見出し一覧ブロック番号
WORD 見出し一覧オフセット
という構造だが、sinidx.dbでは「見出し一覧ブロック番号」の
部分しか値が入っていない(他はゼロで埋められている)。
・見出し一覧ブロック番号の値は、title.dat中の(b)索引データ表への
インデックスとなっている(0x00000000 ~ 0x00056ecf)。
●title.dat
・索引タイトルおよびリンク
・数値はBE
0x00000000: (a)ヘッダ
4 0x00056ecf (b)索引データ数n (= 356047)
4 0x00073111 (d)参照先データ数m (= 471313)
4 0x00000020 (b)索引データ表開始アドレス
4 0x00365416 (b)索引データ表サイズ
4 0x00365436 (c)索引タイトルデータ開始アドレス
4 0x004ddda4 (c)索引タイトルデータサイズ
4 0x008431da (d)項目参照データ表開始アドレス
4 0x001cc444 (d)項目参照データ表サイズ
0x00000020: (b)索引データ表
n×10 (c)索引タイトルオフセット[4] +
(d)項目参照データ項目数[2] +
(d)項目参照データオフセット[4]
0x00365436: (c)索引タイトルデータ
n×可変長 索引タイトル (0x00で終わる)
・参照のみの場合は0x8140(2バイト空白)で始まる
・本文がある場合は0xf56f(○の中に△の記号)で始まる
0x008431da: (d)項目参照データ表
m×4 項目番号(0 ~ 87825)×1000+関連項目番号
0x00a0f61e: 末尾
●titlez.dat
・項目タイトルデータ
・数値はBE
0x00000000: (a)ヘッダ
4 0x000015712 項目数n (= 87826)
0x00000004: (b)項目タイトルオフセット表
n×4 項目タイトルオフセット ((c)からのオフセット)
0x00055c4c: (c)項目タイトルデータ
n×可変長 項目タイトル(00で終わっている)
0x002c6540: 末尾
●itemloc.dat
・項目参照表
・titlez.datの項目と1対1に対応している
0x00000000: (a)本文参照表
0x15712×16 (0x15712 = 87826)
4 (1)item.dat中のオフセット (0x00000000 ~ 0x0600a8e4)
4 (1)item.dat中のサイズ
4 (2)itemlink中のオフセット (0x00000000 ~ 0x0015b0bc)
4 (2)itemlink中のサイズ (5の倍数)
0x00157120: 末尾
●item.dat
・本文データ
・圧縮されている
・各項目はitemloc.datからポイントされている
0x00000000: (a)本文
0x0600a928: 末尾
●itemlink.dat
0x00000000:
0x4568c×5 (0x4568c = 284300)
5 ???
0x0015b0bc: 末尾
以上
fj.comp.applications.dictionaryの記事<bo5q7u$r7h$1...@ns.src.ricoh.co.jp>で
私は書きました。
> おぼろげですが、LZSSのようです。
ただし、LZSSでは辞書になかった文字はフラグつきでそ
のまま出力に出てくるはずですが、こちらはどうやらそ
うなっていないのです。どういう意図で加工しているの
かな。
何らかの暗号化が行われているとしても、cx.dllにある
LZSSの辞書初期データらしきものと伸長後の本文データ
↓を使い、
> 00004:
> <TOC></TOC><TITLE>IIR</TITLE><YOMI1>アイアイアール</YOMI1>
> <BODY>⇒<A REFID="65417000">ブチルゴム</A>【改行】</BODY>
これを実際にLZSSで圧縮したものとitem.datにある圧縮
データを比較してみれば何かわかるかなと思っていると
ころなのですが...。とはいうものの、それもまた
> ・圧縮はLZSS???
> ・スライド辞書には最初からタグなどのデータが入っている
> ・フラグ + コピー文字数(7ビット) + コピー開始位置(11ビット)???
> ・フラグ + 文字(8ビット)???
このあたりの観察が正しければの話ですけどね。
ただ、これからちょっと多忙なので、しばらくは進展し
ないかもしれません。
ちょっとミスがありました。訂正。
-------------------------------------------------------------------
0006: 10011011 -> 00011011 (9b -> 1b)
^ ^
???...TLE></EUTITLE><BODY>??⇒<A REFID="00000000"></A>?????...
※不明
0006: 10011011 -> 11011011 (9b -> db)
^ ^
*e^8R></TOC><TITLE>(アRCアRCアーR?)</TITLE><YOMIEUTITLE><BOD65417?<A R[w???...
※不明
0006: 10011011 -> 10111011 (9b -> bb)
^ ^
<TOC></TOC><TITLE>()</TITLE><YOMI1></YOMI1><BODY><IIROMI1><EUTITLE><アイアイアール/EUTITLE><BODY(0x8140×6)6
※コピー文字数が+0x20変化した
0006: 10011011 -> 10001011 (9b -> 8b)
^ ^
???...TLE></EUTITLE><BODY>??⇒<A REFID="00000000"></A>???...
※不明
0006: 10011011 -> 10010011 (9b -> 93)
^ ^
<TOC></TOCIIRTITLE>()</TITLEアイアイアール><YOMI1></YOMI<BODY>??⇒<A65417D="00ブチルゴム000000「』『?t
※コピー文字数が-0x08変化した
0006: 10011011 -> 10011111 (9b -> 9f)
^ ^
<TOC></TOC><TITLE>()</IIRTLE><YOMI1></YOアイアイアールMI1><BODY></YO REFID="000065417></A>ブチルゴム??(0x8140×2)DY>
※コピー文字数が+0x04変化した
0006: 10011011 -> 10011001 (9b -> 99)
^ ^
<TOC></TOC><TITLIIR()</TITLE><YOMIアイアイアール1></YOMI1><BOD??⇒<A REFID6541700000ブチルゴム"></A>
</BODt
※コピー文字数が-0x02変化した
0006: 10011011 -> 10011010 (9b -> 9a)
なるほど。どんどん解読作業が進んでますね。
でも、16進数を2進数に変換してみると、
ちょっとつじつまが合わないようです。
4文字の IAEA, IFRB, IFTU を並べると、(横に長くてすみません)
12:10011011 01111100 01111101 01011110 01101111 01000111 00001110 01100001 11110010 10000111 11011111 11000000 11100111 11011110 11101001 10000110 11111001 11101111
17:10011011 01111100 01111101 01011110 10010111 01111011 10011101 00110000 11111001 01000011 11111001 10110111 11111100 11111011 11011101 00111011 11000000 00010110
18:10011011 01111100 01111101 01011110 10010111 10000011 11000011 00110000 11111001 01000011 11111001 10110111 11111100 11111011 11011101 00111011 11000000 00010110
3文字の IIR, ISO, IFR を並べると、
04:10011011 01111100 01111101 01011100 01001110 11110100 11000011 11100100 00001111 11100110 11100000 11110011 11100011 11000000 01100001 10111110 01111011 10000010
14:10011011 01111100 01111101 01011110 11111111 01101110 01100001 11110010 00000111 11110011 01110000 00111001 11110111 10111010 01110111 10111100 10010110 11100010
16:10011011 01111100 01111101 01011110 10010111 01111010 01100001 11110010 00000111 11110011 01110000 00111001 11110111 10111010 01110111 10000000 00101101 10111111
どうも、IAEA と IIR が1ビット少ないようです。
A や I の重複による適応型ハフマンの影響でしょうか?
もしも LZSS+適応型ハフマン となると、まず私に必要なのは勉強だな。
おそるべし、世界大百科辞典と Jamming。
そうなんですよ。最初のタグが圧縮されている部分から
して、コピー文字数のビットをいじったときの影響はい
かにもそれらしい(1桁左をいじると影響を受ける文字数
が2倍になる)のに、0011011という数値は実際にコピー
されている16文字とは相容れない。ゲタをはかせてある
のかもしれませんが、そうするとコピーできる文字数の
上限が減ってしまうわけですし。不思議。
> 4文字の IAEA, IFRB, IFTU を並べると、(横に長くてすみません)
> ...
> 3文字の IIR, ISO, IFR を並べると、
> ...
> どうも、IAEA と IIR が1ビット少ないようです。
> A や I の重複による適応型ハフマンの影響でしょうか?
なるほど。しかしLZSSの後段に適応型ハフマンをかける
としたら、コピー文字数や開始位置の部分もそうなって
いるほうが自然だし、そうであれば特定の位置のビット
をいじったときの影響はもっと摩可不思議なものであっ
てもおかしくないような気がするんですよね。とはいえ
1ビット少なそうという観察もまたそれらしいし...。
短い項目どれかについてすべてのビットをいじって影響
をみたらもう少し何かわかるでしょうか? あるいは、こ
のあたりをこういじったらどうなるか影響をみるといい、
といったアドバイスはありますか?
# 私のもっている初版と第2版はいずれもハードディス
# クインストールのできないバージョンです。そのあと
# に出たモバイル対応版ならItem.datをハードディスク
# に置いておけるのでパッチ当ても楽なんですけどね。
# cx.dllにパッチを当ててハードディスク上に置いたデ
# ータを読んでくれるようにしようと試みたのですが、
# それも失敗...。
> もしも LZSS+適応型ハフマン となると、まず私に必要なのは勉強だな。
それは私も。
fj.comp.miscあたりに投げればもう少し詳しい人が食い
ついてきてくれるかもしれませんが、あまりロコツにや
るものでもないと思うし、ちょっと躊躇しますよね...。
まあここまで手をかけたんだし、速度はにぶるかもしれ
ませんが当分がんばるつもりです。
1ビット変えるだけで、IIRがiiRと2文字も変わるのは
adaptive huffman なら説明がつきますね。
他の不可解な点の説明は思いつかないなー、
何を調べればいいんだろう?
ふむ。直前の文字のコピーが起きているのかなとも思っ
たのですが、コピー文字数と開始位置を指定するほうが
コストがかかりますね。だとすると適応型ハフマンのほ
うがありそうな話なのか...。
Webで圧縮アルゴリズムの話を探してつらつら読んでい
ると、LHAのように前段をLZ圧縮、後段をハフマン圧縮
しているものではコピー文字数や開始位置などの情報も
圧縮するのがふつうのようです。しかし今回の解析では
文字数や開始位置の各ビットが無圧縮の場合と関連があ
りすぎて、そのあたりは圧縮されていないのではないか
と思うのですよね。
> 他の不可解な点の説明は思いつかないなー、
> 何を調べればいいんだろう?
短い項目の全ビットをいじってどの位置以降が変化する
かをみれば、少なくともどの文字がどれだけのビット数
で表現されているかはわかりそうです。時間ができたら
やってみようかなと。
文字 I が i に変わると、それ移行の I が全て i に変わるのみでなく、
I から i までの間の全ての文字に影響するはずですね。
R に影響がないということは、予想が外れなのかな?
短い項目ではなく長い項目で文字を変化させたときの
その後の文字の変化で何か分からないかな。
一致長や一致位置も適応型ハフマンなら同じことが起こるはずですが、
こちらはスライド窓への影響で変化が大きそう。
> 短い項目どれかについてすべてのビットをいじって影響
> をみたらもう少し何かわかるでしょうか?
苦労の割には、
以前の結果と大きく違う結果は得られないと思います。
> あるいは、このあたりをこういじったらどうなるか影響をみるといい、
> といったアドバイスはありますか?
んー、ここが問題です。
何をどう調べればいいのか思いつきません。手詰り。
その時点での同じ頻度をもつ文字への変換でなくては、
その後のビット数への影響がでますね。
となると、 初期スライド窓や"<TOC></TOC><TITLE>" は
頻度テーブルにカウントするのだろうか?
いや、それはなさそうかな。
藤井宏憲さんの<87znfdyipk.wl%fu...@chi.its.hiroshima-cu.ac.jp>から
>Jamming は Macintosh版もあるからやっぱり解読してそうですね。
いっそのことJamming作者の今井さんに聞いてみてはいかがでしょう。
#以前、Jammingでndtp対応して欲しいとお願いしたら、丁重に断られて
#しまったけど。
--
Tanaka-Qtaro-Yasuhiro mailto:ta...@ca2.so-net.ne.jp
それはこれまでも頭をチラホラかすめていた考えなので
すが、いちおう最後の手段ということで...。(^^;
Jammingの強さのひとつはこうした解析による独自フォ
ーマット辞書への対応なのですが、それはJammingの競
争力の一部であるわけで、それをタダで分けてくれとは
できればいいたくないのです。
Junn Ohtaさんの<bocjmo$241$1...@ns.src.ricoh.co.jp>から
>Jammingの強さのひとつはこうした解析による独自フォ
>ーマット辞書への対応なのですが、それはJammingの競
>争力の一部であるわけで、それをタダで分けてくれとは
>できればいいたくないのです。
そうですね。太田さんのおっしゃる通りだと思います。
最後の手段になる前に、解析できるといいですね。
--
Tanaka-Qtaro-Yasuhiro mailto:ta...@ca2.so-net.ne.jp
ここはよくわかりませんでした。頻度テーブルは文字コ
ードの並びと何か関連付けされるのでしょうか?
> > あるいは、このあたりをこういじったらどうなるか影響をみるといい、
> > といったアドバイスはありますか?
>
> んー、ここが問題です。
> 何をどう調べればいいのか思いつきません。手詰り。
多忙になるはずの時期がちょっと延びました。
# FreeBSD 5.2-BETAが出ないので...。(^^;
なので例の解析の続きを。
さまざまなビット位置のデータを変更してスライド窓か
らのコピー発生状況の変化を調べることによって、対応
するビットパターンを特定しました。で、そのパターン
を検討したところ、おおよそ以下のようでした。
・コピーの有無によらず1で始まるビット列があるよう
なので、フラグは2ビットかも? つまりコピーは次の
要領で行われている?
フラグ = 2ビット
コピー文字数 = 6ビット
参照位置までの距離 = 11ビット
・コピーを示すフラグは“10”らしい
・ということは“10”以外で始まるビット列がハフマン
符号化に使われている?
・コピー文字数には+001001のゲタが履かせてあると解
釈するとつじつまが合う(合わないデータもあるが)
・参照位置までの距離の相対的なつじつまは合っている
(ゲタが履かせてある可能性はあるが)
以下、解析データです。
●スライド窓の初期データ
100127d0 3c 54 4f 43 3e 3c 2f 54 4f 43 3e 3c 54 49 54 4c <TOC></TOC><TITL
100127e0 45 3e 28 29 3c 2f 54 49 54 4c 45 3e 3c 59 4f 4d E>()</TITLE><YOM
100127f0 49 31 3e 3c 2f 59 4f 4d 49 31 3e 3c 42 4f 44 59 I1></YOMI1><BODY
10012800 3e 3c 2f 59 4f 4d 49 31 3e 3c 45 55 54 49 54 4c ></YOMI1><EUTITL
10012810 45 3e 3c 2f 45 55 54 49 54 4c 45 3e 3c 42 4f 44 E></EUTITLE><BOD
10012820 59 3e 0d 0a 81 cb 3c 41 20 52 45 46 49 44 3d 22 Y>..⇒<A REFID="
10012830 30 30 30 30 30 30 30 30 22 3e 3c 2f 41 3e 5c 6e 00000000"></A>\n
10012840 81 40 81 40 81 40 81 40 81 40 81 40 81 40 81 40
10012850 81 40 81 40 81 40 81 40 81 40 81 40 81 40 81 40
10012860 81 40 81 40 81 40 81 40 81 40 81 40 81 40 81 40
10012870 81 40 81 40 81 40 81 40 81 40 81 40 0d 0a 29 28 ..)(
10012880 81 6a 81 69 81 6c 81 6b 81 6e 81 6d 81 70 81 6f )(〕〔][}{
10012890 81 72 81 71 81 74 81 73 81 76 81 75 81 78 81 77 〉〈》《」「』『
100128a0 0d 0a 3c 2f 42 4f 44 59 3e 0d 0a 3c 54 4f 43 3e ..</BODY>..<TOC>
...
●項目00004の伸張結果
<TOC></TOC><TITLE>IIR</TITLE><YOMI1>アイアイアール</YOMI1><BODY>⇒<A REFID="65417000">ブチルゴム</A>
</BODY>
●項目00004の圧縮データとスライド窓からコピーされるタグ
(f:フラグ, n:コピー文字数, d:参照位置までの距離)
0000: 00000010 00000001 01101101 00000000 00000000 00000000 10011011 01111100
ffnnnnnn dddddddd
<TOC></TOC><TITLE>
0008: 01111101 01011100 01001110 11110100 11000011 11100100 00001111 11100110
ddd ffn nnnnnddd dddddddd
</TITLE><YOMI1>
0010: 11100000 11110011 11100011 11000000 01100001 10111110 01111011 10000010
0018: 11110010 11101111 11001010 01010101 11100111 11110000 10111000 00111100
ffnnn nnnddddd ddddddff nnnnnndd dddddddd d
</YOMI1><BODY> ⇒<A REFID="
0020: 00001101 11101111 00001110 00111001 11100111 11011101 00000001 10101011
0028: 11011001 01011101 11001101 01111101 11111010 11000011 00101111 10011110
ffnnnn nndddddd
</A>\n ※
0030: 11001100 10000011 01110111
dddddffn nnnnnddd dddddddd
</BODY>
※このタグはパターン変化に対する挙動がちょっとおかしい???
●各タグに対応するパターンの解析
<TOC></TOC><TITLE> (コピーされるタグ)
1001101101111100011 (対応するビットパターン)
10 (フラグ?)
010010 = 18 (コピー文字数)
+001001 (ゲタ)
011011 (パターンと一致)
01111100011 = 995 (参照位置までの距離)
</TITLE><YOMI1>
1001100001111100100
10
001111 = 15
+001001
011000 (一致)
01111100100 = 996 (コピー位置+21, 参照位置+20 → 一致)
</YOMI1><BODY>
1001011101111110010
10
001110 = 14
+001001
010111 (一致)
01111110010 = 1010 (コピー位置+29, 参照位置+15 → 一致)
⇒<A REFID="
1001010101111001111
10
001100 = 12
+001001
010101 (一致)
01111001111 = 975 (コピー位置+14, 参照位置+49 → 一致)
</A>\n
1011111001111011001
10
000110 = 6
+001001
001111 (一致しない???)
01111011001 = 985 (コピー位置+32, 参照位置+22 → 一致)
</BODY>
1001000001101110111
10
000111 = 7
+001001
010000 (一致)
01101110111 = 887 (コピー位置+6, 参照位置+104 → 一致)
以上
まずはじめは全部の文字が同じ頻度1なので
A B C
1 1 1
ハフマン木を作成。ここで `B' が来ると、頻度は
A C B
1 1 2
のように `C' までズレるんじゃないかと考えたのですが、
適応型ハフマンをよく知らないので勉強してみます。
> フラグ = 2ビット
> コピー文字数 = 6ビット
> 参照位置までの距離 = 11ビット
現在の私の予想は、
o フラグなし LZSS + 適応型ハフマン
o 一致長と不一致文字をひとつのハフマン木にすることにより、フラグをなくす
これはハズレかも、です。もちろん外れたほうがうれし
いのですが...。
コピーなしのときのパターン変化を調べたところ、次の
ことがわかりました。
・フラグ2ビット + 文字の下位7ビット?
・フラグは“11”か“10”で始まっている(“00”で始
まるものもありそうだが、未調査)
・文字のMSBが“0”ならフラグは“11”、MSBが“1”な
らフラグは“10”になる?
・フラグが“10”で始まるものは後続のビットパターン
でスライド窓からのコピーと識別可能?
・フラグが“11”で始まるものは後続のビットパターン
で直前文字のコピーと識別可能?
・圧縮データの変化と伸張データの変化には対応関係が
あり、文字コードの範囲での変化なら後続に影響はな
い(“II”→“ii”などの直後のコピーは別)
・文字コードには+10001100だけゲタを履かせてある?
というわけで、コピーなしのときもハフマン圧縮されて
いるわけではなさそうです。ただ“II”→“ii”のよう
な場合は何か特別なことをしていそうです。
また、フラグに後続するビットパターンとゲタの関係と
でコピーなし、スライド窓からのコピー、直前文字のコ
ピーをうまく識別できそうな気がします。もう少し調べ
てみないとわかりませんが...。
以下、解析データです。
●項目00004の圧縮/伸張データの対応関係
0000: 00000010 00000001 01101101 00000000 00000000 00000000 10011011 01111100
ffnnnnnn dddddddd
<TOC></TOC><TITLE>
0008: 01111101 01011100 01001110 11110100 11000011 11100100 00001111 11100110
dddffccc cccc<--- --->ffcc cccccffn nnnnnddd dddddddd ^^00で始まってる?
'I' コピー? 'R' </TITLE><YOMI1>
0010: 11100000 11110011 11100011 11000000 01100001 10111110 01111011 10000010
ffcccc cccffccc cccc
'ー'+0 'ー'+1
0018: 11110010 11101111 11001010 01010101 11100111 11110000 10111000 00111100
ffnnn nnnddddd ddddddff nnnnnndd dddddddd d
</YOMI1><BODY> ⇒<A REFID="
0020: 00001101 11101111 00001110 00111001 11100111 11011101 00000001 10101011
0028: 11011001 01011101 11001101 01111101 11111010 11000011 00101111 10011110
ffnnnn nndddddd
</A>\n ※
0030: 11001100 10000011 01110111
dddddffn nnnnnddd dddddddd
</BODY>
●バイト位置0008~0009の変化 ([I]IR)
vフラグ開始位置
0111[1101 0101]1100 (元データ) → I(49) [01001001]
0111[1101 0100]1100 (-00000001) → H(48) [01001000] (-00000001)
0111[1101 0111]1100 (+00000010) → K(4b) [01001011] (+00000010)
0111[1101 0001]1100 (-00000100) → E(45) [01000101] (-00000100)
0111[1101 1101]1100 (+00001000) → Q(51) [01010001] (+00001000)
0111[1100 0101]1100 (-00010000) → 9(39) [00111001] (-00010000)
0111[1111 0101]1100 (+00100000) → i(69) [01101001] (+00100000)
0111[1001 0101]1100 (-01000000) → (09) [00001001] (-01000000)
0111[0101 0101]1100 (-10000000) → ??? 観測不能
※11010101 - 01001001 = 10001100(8c)だけゲタを履いている?
※フラグ“11”プラス文字7ビットか?
※このIを変化させると直後のIも同じように変化する
(1バイトの一致でもコピーを行っている?)
●バイト位置000a~000bの変化 (II[R])
vフラグ開始位置
01001[110 11110]100 (元データ) → R(52) [01010010]
01001[110 11111]100 (+00000001) → S(53) [01010011] (+00000001)
01001[110 11100]100 (-00000010) → P(50) [01010000] (-00000010)
01001[110 11010]100 (-00000100) → N(4e) [01001110] (-00000100)
01001[110 10110]100 (-00001000) → J(4a) [01001010] (-00001000)
01001[110 01110]100 (-00010000) → B(42) [01000010] (-00010000)
01001[111 11110]100 (+00100000) → r(72) [01110010] (+00100000)
01001[100 11110]100 (-01000000) → (12) [00010010] (-01000000)
01001[010 11110]100 (-10000000) → ??? 観測不能
※11011110 - 01010010 = 10001100(8c)だけゲタを履いている?
※フラグ“11”プラス文字7ビットか?
●バイト位置0014~0015の変化 (アイアイア[ー]ル)
vフラグ開始位置
011[00001 101]11110 (元データ) → ー(815b) [10000001]01011011
011[00001 100]11110 (-00000001) → (805b) [10000000]01011011 (-00000001)
011[00001 111]11110 (+00000010) → ??? 観測不能
011[00001 001]11110 (-00000100) → (7d5b) [01111101]01011011 (-00000100)
011[00000 101]11110 (-00001000) → (795b) [01111001]01011011 (-00001000)
011[00011 101]11110 (+00010000) → (915b) [10010001]01011011 (+00010000)
011[00101 101]11110 (+00100000) → (a15b) [10100001]01011011 (+00100000)
011[01001 101]11110 (+01000000) → (c15b) [11000001]01011011 (+01000000)
011[10001 101]11110 (+10000000) → ??? 観測不能
※(1)00001101 - 10000001 = 10001100(8c)だけゲタを履いている?
※フラグ“10”で始まっている???
●バイト位置0015~0016の変化 (アイアイア[ー]ル)
vフラグ開始位置
1011[1110 0111]1011 (元データ) → ー(815b) 10000001[01011011]
1011[1110 0110]1011 (-00000001) → 〇(815a) 10000001[01011010] (-00000001)
1011[1110 0101]1011 (-00000010) → 〆(8159) 10000001[01011001] (-00000010)
1011[1110 0011]1011 (-00000100) → 仝(8157) 10000001[01010111] (-00000100)
1011[1110 1111]1011 (+00001000) → …(8163) 10000001[01100011] (+00001000)
1011[1111 0111]1011 (+00010000) → 〔(816b) 10000001[01101011] (+00010000)
1011[1100 0111]1011 (-00100000) → (813b) 10000001[00111011] (-00100000)
1011[1010 0111]1011 (-01000000) → (811b) 10000001[00011011] (-01000000)
1011[0110 0111]1011 (-10000000) → (81??) 10000001[????????] 観測不能
※11100111 - 01011011 = 10001100(8c)だけゲタを履いている?
※フラグ“11”プラス文字7ビットか?
●バイト位置0018の変化 (アイアイアー[ル])
[111]10010 (元データ) → ル(838b) 10000011[10001011]
[110]10010 (-0x0001) → リ(838a) 10000011[10001010] (-0x00000001)
※ここを「リ」にすると後続の「ブチルゴム」も「ブチリゴム」になる
(2バイトの一致でもコピーを行っている?)
At 7 Nov 2003 17:44:08 GMT,
oh...@src.ricoh.co.jp (Junn Ohta) wrote:
>
> <TOC></TOC><TITLE> (コピーされるタグ)
> 1001101101111100011 (対応するビットパターン)
> 10 (フラグ?)
> 010010 = 18 (コピー文字数)
>
> </TITLE><YOMI1>
> 001111 = 15
ここで、18文字コピーと15文字コピーが起こっていますが、
18文字コピーの後に18文字コピーはできないことはないですか?
もしくは x 文字コピーの後に x 文字コピーでつじつまが合わない
ところはないですか?
■予想
(1) フラグなし LZSS + 適応型ハフマン
(2) 一致長と不一致文字をひとつのハフマン木にすることにより、フラグをなくす
(3) 規則正しい初期ハフマン木
(4) FGK法でハフマン木の更新
(5) 一致開始位置は11ビット固定
■根拠
●(5) 一致開始位置が同じときコードも同じだから。
00008:
<TOC></TOC><TITLE>IR</TITLE><YOMI1>アイアール</YOMI1>
<BODY>⇒<A REFID="04804000">イソプレンゴム</A>【改行】</BODY>
00008:
10011011 01111100011 111010101 111011110 10011000 01111100011
`I' `R'
ヒントだけでじゅうぶん助かってます。
> ここで、18文字コピーと15文字コピーが起こっていますが、
> 18文字コピーの後に18文字コピーはできないことはないですか?
> もしくは x 文字コピーの後に x 文字コピーでつじつまが合わない
> ところはないですか?
どうやら後者が当てはまるようです。先頭のタグを展開
しているビットパターンをその直後でくり返したところ、
18文字ではなく60文字のコピーになってしまいました。
> ■予想
> (1) フラグなし LZSS + 適応型ハフマン
> (2) 一致長と不一致文字をひとつのハフマン木にすることにより、フラグをなくす
> (3) 規則正しい初期ハフマン木
> (4) FGK法でハフマン木の更新
> (5) 一致開始位置は11ビット固定
> ■根拠
> ●(5) 一致開始位置が同じときコードも同じだから。
ううう...。勉強してきます。(^^;
藤井さんがこのように推定した根拠は自分でも理解でき
ました。
> (4) FGK法でハフマン木の更新
これは何かそう見える断片があるということですか?
ああそうか、18文字コピーのビットパターンのあとに同
じパターンを続けても結果が異なるわけですからね。間
抜けでした。(^^;
(1) フラグなし LZSS + 適応型ハフマン
(2) 一致長と不一致文字をひとつのハフマン木にすることにより、フラグをなくす
(4) FGK法でハフマン木の更新
(5) 一致開始位置は11ビット固定
(6) 文字の葉が 256枚、一致文字数の葉が 58枚
(7) 一致文字数は 3 から 60
■初期ハフマン木の作り方
1) 256枚の文字の葉の後ろに58枚の一致文字数の葉を繋げる
2) 先頭の2ノードを合体し、最後尾に繋げる
3) 2 へ
> > (4) FGK法でハフマン木の更新
>
> これは何かそう見える断片があるということですか?
それは、
> 18文字ではなく60文字のコピーになってしまいました。
これが決定的です。
まず``18文字コピー''が出現したのでこの頻度が 1 増えます。
FGK では 1 増やす前に、現在のその頻度と同じ頻度のうち、
最も後ろのものとスワップします。
■初期ハフマン木
00000000 char t
00000001 char u
00000010 char v
00000011 char w
00000100 char x
00000101 char y
00000110 char z
00000111 char {
00001000 char |
00001001 char }
00001010 char ~
00001011 char \127
00001100 char \128
00001101 char \129
00001110 char \130
00001111 char \131
00010000 char \132
00010001 char \133
00010010 char \134
00010011 char \135
00010100 char \136
00010101 char \137
00010110 char \138
00010111 char \139
00011000 char \140
00011001 char \141
00011010 char \142
00011011 char \143
00011100 char \144
00011101 char \145
00011110 char \146
00011111 char \147
00100000 char \148
00100001 char \149
00100010 char \150
00100011 char \151
00100100 char \152
00100101 char \153
00100110 char \154
00100111 char \155
00101000 char \156
00101001 char \157
00101010 char \158
00101011 char \159
00101100 char \160
00101101 char \161
00101110 char \162
00101111 char \163
00110000 char \164
00110001 char \165
00110010 char \166
00110011 char \167
00110100 char \168
00110101 char \169
00110110 char \170
00110111 char \171
00111000 char \172
00111001 char \173
00111010 char \174
00111011 char \175
00111100 char \176
00111101 char \177
00111110 char \178
00111111 char \179
01000000 char \180
01000001 char \181
01000010 char \182
01000011 char \183
01000100 char \184
01000101 char \185
01000110 char \186
01000111 char \187
01001000 char \188
01001001 char \189
01001010 char \190
01001011 char \191
01001100 char \192
01001101 char \193
01001110 char \194
01001111 char \195
01010000 char \196
01010001 char \197
01010010 char \198
01010011 char \199
01010100 char \200
01010101 char \201
01010110 char \202
01010111 char \203
01011000 char \204
01011001 char \205
01011010 char \206
01011011 char \207
01011100 char \208
01011101 char \209
01011110 char \210
01011111 char \211
01100000 char \212
01100001 char \213
01100010 char \214
01100011 char \215
01100100 char \216
01100101 char \217
01100110 char \218
01100111 char \219
01101000 char \220
01101001 char \221
01101010 char \222
01101011 char \223
01101100 char \224
01101101 char \225
01101110 char \226
01101111 char \227
01110000 char \228
01110001 char \229
01110010 char \230
01110011 char \231
01110100 char \232
01110101 char \233
01110110 char \234
01110111 char \235
01111000 char \236
01111001 char \237
01111010 char \238
01111011 char \239
01111100 char \240
01111101 char \241
01111110 char \242
01111111 char \243
10000000 char \244
10000001 char \245
10000010 char \246
10000011 char \247
10000100 char \248
10000101 char \249
10000110 char \250
10000111 char \251
10001000 char \252
10001001 char \253
10001010 char \254
10001011 char \255
10001100 copy 3
10001101 copy 4
10001110 copy 5
10001111 copy 6
10010000 copy 7
10010001 copy 8
10010010 copy 9
10010011 copy 10
10010100 copy 11
10010101 copy 12
10010110 copy 13
10010111 copy 14
10011000 copy 15
10011001 copy 16
10011010 copy 17
10011011 copy 18
10011100 copy 19
10011101 copy 20
10011110 copy 21
10011111 copy 22
10100000 copy 23
10100001 copy 24
10100010 copy 25
10100011 copy 26
10100100 copy 27
10100101 copy 28
10100110 copy 29
10100111 copy 30
10101000 copy 31
10101001 copy 32
10101010 copy 33
10101011 copy 34
10101100 copy 35
10101101 copy 36
10101110 copy 37
10101111 copy 38
10110000 copy 39
10110001 copy 40
10110010 copy 41
10110011 copy 42
10110100 copy 43
10110101 copy 44
10110110 copy 45
10110111 copy 46
10111000 copy 47
10111001 copy 48
10111010 copy 49
10111011 copy 50
10111100 copy 51
10111101 copy 52
10111110 copy 53
10111111 copy 54
11000000 copy 55
11000001 copy 56
11000010 copy 57
11000011 copy 58
11000100 copy 59
11000101 copy 60
110001100 char \000
110001101 char \001
110001110 char \002
110001111 char \003
110010000 char \004
110010001 char \005
110010010 char \006
110010011 char \007
110010100 char \008
110010101 char \t
110010110 char \n
110010111 char \011
110011000 char \012
110011001 char \013
110011010 char \014
110011011 char \015
110011100 char \016
110011101 char \017
110011110 char \018
110011111 char \019
110100000 char \020
110100001 char \021
110100010 char \022
110100011 char \023
110100100 char \024
110100101 char \025
110100110 char \026
110100111 char \027
110101000 char \028
110101001 char \029
110101010 char \030
110101011 char \031
110101100 char
110101101 char !
110101110 char "
110101111 char #
110110000 char $
110110001 char %
110110010 char &
110110011 char \'
110110100 char (
110110101 char )
110110110 char *
110110111 char +
110111000 char ,
110111001 char -
110111010 char .
110111011 char /
110111100 char 0
110111101 char 1
110111110 char 2
110111111 char 3
111000000 char 4
111000001 char 5
111000010 char 6
111000011 char 7
111000100 char 8
111000101 char 9
111000110 char :
111000111 char ;
111001000 char <
111001001 char =
111001010 char >
111001011 char ?
111001100 char @
111001101 char A
111001110 char B
111001111 char C
111010000 char D
111010001 char E
111010010 char F
111010011 char G
111010100 char H
111010101 char I
111010110 char J
111010111 char K
111011000 char L
111011001 char M
111011010 char N
111011011 char O
111011100 char P
111011101 char Q
111011110 char R
111011111 char S
111100000 char T
111100001 char U
111100010 char V
111100011 char W
111100100 char X
111100101 char Y
111100110 char Z
111100111 char [
111101000 char \\
111101001 char ]
111101010 char ^
111101011 char _
111101100 char `
111101101 char a
111101110 char b
111101111 char c
111110000 char d
111110001 char e
111110010 char f
111110011 char g
111110100 char h
111110101 char i
111110110 char j
111110111 char k
111111000 char l
111111001 char m
111111010 char n
111111011 char o
111111100 char p
111111101 char q
111111110 char r
111111111 char s
===File ~/tmp/tree.ml=======================================
let rec make_list n =
let i = ref (n-1) in
let list = ref [] in
while !i >= 0 do
list := !i :: !list;
decr i
done;
!list
type node =
CopyLeaf of int
| CharLeaf of char
| Node of node * node
let chars = List.map (fun x -> CharLeaf (Char.chr x)) (make_list 256)
let copys = List.map (fun x -> CopyLeaf (x + 3)) (make_list 58)
let init = chars @ copys
let rec make_tree = function
[] -> failwith ""
| hd::[] -> hd
| h1::h2::rest -> make_tree (rest@[Node (h1,h2)])
let tree = make_tree init
let rec print_tree tree str =
match tree with
Node (left, right) ->
print_tree left (str ^ "0");
print_tree right (str ^ "1")
| CopyLeaf l ->
Printf.printf "%s copy %d\n" str l
| CharLeaf c ->
Printf.printf "%s char %s\n" str (Char.escaped c)
let test c =
let copys = List.map (fun x -> CopyLeaf x) (make_list c) in
let init = chars @ copys in
print_tree (make_tree init) ""
let test2 () = print_tree tree ""
let _ = test2 ()
============================================================
今はFGK法を実装している時間がないので、これでお終い。
こちらでも同じ結論に達して検証していたところです。
> > 18文字ではなく60文字のコピーになってしまいました。
> これが決定的です。
私もそう考えました。で、ほかの部分でも同じふるまい
が見られるかどうか確かめていたのですが、
> まず``18文字コピー''が出現したのでこの頻度が 1 増えます。
> FGK では 1 増やす前に、現在のその頻度と同じ頻度のうち、
> 最も後ろのものとスワップします。
長さ8の同じ文字(たとえばt)を続けると、後ろの文字が
60文字のコピーになることは確認しました。これは予想
と一致します。しかし、長さ9の同じ文字(たとえばr)を
続けると、後ろの文字が長さ9の最後の要素(文字s)には
なってくれず、予想と異なります。(Jammingでは数十文
字のスペースに展開される。)
なので、ひょっとすると文字や一致長のほかにもハフマ
ン木にぶら下がっているものがあるのかもしれません。
ここまできたらFGK法によるハフマン木の更新コードを
書いてみて、世界大百科事典の項目データを入力したと
きに予想されるLZSS圧縮データが得られるかどうか確認
するしかないですね。書いてみます。
どうやら正しそうです。まだ自分のプログラムにバグが
いるようで途中で壊れてしまうのですが...。
C:\dic\sedai2> decode 8
itemno=8
10011011: len=18, disp=995
111010101: char=0x49 'I'
111011110: char=0x52 'R'
10011000: len=15, disp=995
00001111: char=0x83
111001101: char=0x41 'ア'
11000001: char=0x83
111001111: char=0x43 'イ'
1011111: char=0x83
11000000: char=0x41 'ア'
00001101: char=0x81
111100111: char=0x5b 'ー'
1011111: char=0x83
00010111: char=0x8b 'ル'
10010111: len=14, disp=1005
10010110: len=13, disp=970
111000000: char=0x34 '4'
111000100: char=0x38 '8'
110111100: char=0x30 '0'
10110111: char=0x34 '4'
10001110: len=5, disp=970
10001100: len=3, disp=175
110100010: char=0x16
1011000: char=0x34 '4'
00010101: char=0x89
01100011: char=0xd7 '荷'
00010101: len=42, disp=1150
101111101: len=28, disp=1996
00110010: char=0xa6
00111101: char=0xb1
111011000: char=0x4c 'L'
10010000: len=7, disp=886
00000
ダウト。
現在のその頻度と *同じ頻度* のうち、
最も後ろのものとスワップします。
ですよ。
At 9 Nov 2003 18:24:21 GMT,
oh...@src.ricoh.co.jp (Junn Ohta) wrote:
>
> どうやら正しそうです。まだ自分のプログラムにバグが
> いるようで途中で壊れてしまうのですが...。
おお、素早いですね。もう FGK を実装されたのですか。
やっぱり、微調整が必要なのでしょう。
ところで、disp って何の略ですか?
そうでした。(^^;;;
> おお、素早いですね。もう FGK を実装されたのですか。
> やっぱり、微調整が必要なのでしょう。
微調整が必要なのか、それとも自分のプログラムが悪い
のか、にわかに判別できないところがつらいです。(^^;
> ところで、disp って何の略ですか?
displacementのつもり。
もしやと思い、調べてみると
他にも vitter なんて方法のもあるみたいですね。
もしかすると、FGK ではないのかもしれませんね。
> displacementのつもり。
なるのど。
一致までの距離で dist かなと思ったのですが。
FGKを調べるのにここを読んでいて、Vitterアルゴリズ
ムについても検討はしていました。
http://www.ics.uci.edu/~dan/pubs/DC-Sec4.html
VitterアルゴリズムのFGKとの違いは、
・暗黙の順序付け(implicit numbering)によって葉か
らルート、左から右につねに順序付けされているも
のと仮定する(FGKでは交換によってルートから遠い
ノードにより大きい順序が与えられることがあるが、
Vitterアルゴリズムではそうはならない)
・同じ重みのノードでは、どの葉ノードもどの中間ノ
ードより若く順序付けされる
・ノードの交換においては、葉ノードは同じ重みの葉
ノードの中で最大の順序番号をもつものとのみ交換
が行われる。中間ノードについても同様
ということのようです。(異種のノードの間で交換が
起こらないのなら葉ノードを中間ノードより若く順序
付けする理由がないと思うのだが、そこはよくわから
ない。)
私がハフマン木の初期状態に使ったデータでは、それ
ぞれの重みと順序付けは以下のようになっています。
これはFGKの仕様ですが、Vitterアルゴリズムの要求
も満たしていると思います。
ここから実際にデータを読んでハフマン木の更新にか
かるとFGKとVitterアルゴリズムで違いが出てくるの
ですが、どちらで試してみても途中から結果がおかし
くなる点については同じでした。Vitterアルゴリズム
で交換の相手を探すときは、ノードデータに保存され
ている順序番号ではなく、毎回ルートから葉へ、右か
ら左へ同じ種別(葉ノードか中間ノードか)で同じ重み
のノードを探すようにしています。
というわけで、うまくいかない理由はまだわかってい
ません。(あるいは私がFGKやVitterの仕様を勘違いし
て実装しているのかも。)
あとは何か考えられるでしょうか? 重みの初期値が異
なっているとか...。前に「何かほかにぶら下がって
いるものがあるのかも」と書きましたが、考えてみた
ら現在の初期状態ではすべての枝の終端に葉ノードが
あるので、ほかには何もぶら下がりようがなかったで
すね。だからそれはなし。
●ハフマン木の初期状態
110001100: weight=001, order=001, char=0x00
110001101: weight=001, order=002, char=0x01
110001110: weight=001, order=003, char=0x02
110001111: weight=001, order=004, char=0x03
110010000: weight=001, order=005, char=0x04
110010001: weight=001, order=006, char=0x05
110010010: weight=001, order=007, char=0x06
110010011: weight=001, order=008, char=0x07
110010100: weight=001, order=009, char=0x08
110010101: weight=001, order=010, char=0x09
110010110: weight=001, order=011, char=0x0a
110010111: weight=001, order=012, char=0x0b
110011000: weight=001, order=013, char=0x0c
110011001: weight=001, order=014, char=0x0d
110011010: weight=001, order=015, char=0x0e
110011011: weight=001, order=016, char=0x0f
110011100: weight=001, order=017, char=0x10
110011101: weight=001, order=018, char=0x11
110011110: weight=001, order=019, char=0x12
110011111: weight=001, order=020, char=0x13
110100000: weight=001, order=021, char=0x14
110100001: weight=001, order=022, char=0x15
110100010: weight=001, order=023, char=0x16
110100011: weight=001, order=024, char=0x17
110100100: weight=001, order=025, char=0x18
110100101: weight=001, order=026, char=0x19
110100110: weight=001, order=027, char=0x1a
110100111: weight=001, order=028, char=0x1b
110101000: weight=001, order=029, char=0x1c
110101001: weight=001, order=030, char=0x1d
110101010: weight=001, order=031, char=0x1e
110101011: weight=001, order=032, char=0x1f
110101100: weight=001, order=033, char=0x20
110101101: weight=001, order=034, char=0x21
110101110: weight=001, order=035, char=0x22
110101111: weight=001, order=036, char=0x23
110110000: weight=001, order=037, char=0x24
110110001: weight=001, order=038, char=0x25
110110010: weight=001, order=039, char=0x26
110110011: weight=001, order=040, char=0x27
110110100: weight=001, order=041, char=0x28
110110101: weight=001, order=042, char=0x29
110110110: weight=001, order=043, char=0x2a
110110111: weight=001, order=044, char=0x2b
110111000: weight=001, order=045, char=0x2c
110111001: weight=001, order=046, char=0x2d
110111010: weight=001, order=047, char=0x2e
110111011: weight=001, order=048, char=0x2f
110111100: weight=001, order=049, char=0x30
110111101: weight=001, order=050, char=0x31
110111110: weight=001, order=051, char=0x32
110111111: weight=001, order=052, char=0x33
111000000: weight=001, order=053, char=0x34
111000001: weight=001, order=054, char=0x35
111000010: weight=001, order=055, char=0x36
111000011: weight=001, order=056, char=0x37
111000100: weight=001, order=057, char=0x38
111000101: weight=001, order=058, char=0x39
111000110: weight=001, order=059, char=0x3a
111000111: weight=001, order=060, char=0x3b
111001000: weight=001, order=061, char=0x3c
111001001: weight=001, order=062, char=0x3d
111001010: weight=001, order=063, char=0x3e
111001011: weight=001, order=064, char=0x3f
111001100: weight=001, order=065, char=0x40
111001101: weight=001, order=066, char=0x41
111001110: weight=001, order=067, char=0x42
111001111: weight=001, order=068, char=0x43
111010000: weight=001, order=069, char=0x44
111010001: weight=001, order=070, char=0x45
111010010: weight=001, order=071, char=0x46
111010011: weight=001, order=072, char=0x47
111010100: weight=001, order=073, char=0x48
111010101: weight=001, order=074, char=0x49
111010110: weight=001, order=075, char=0x4a
111010111: weight=001, order=076, char=0x4b
111011000: weight=001, order=077, char=0x4c
111011001: weight=001, order=078, char=0x4d
111011010: weight=001, order=079, char=0x4e
111011011: weight=001, order=080, char=0x4f
111011100: weight=001, order=081, char=0x50
111011101: weight=001, order=082, char=0x51
111011110: weight=001, order=083, char=0x52
111011111: weight=001, order=084, char=0x53
111100000: weight=001, order=085, char=0x54
111100001: weight=001, order=086, char=0x55
111100010: weight=001, order=087, char=0x56
111100011: weight=001, order=088, char=0x57
111100100: weight=001, order=089, char=0x58
111100101: weight=001, order=090, char=0x59
111100110: weight=001, order=091, char=0x5a
111100111: weight=001, order=092, char=0x5b
111101000: weight=001, order=093, char=0x5c
111101001: weight=001, order=094, char=0x5d
111101010: weight=001, order=095, char=0x5e
111101011: weight=001, order=096, char=0x5f
111101100: weight=001, order=097, char=0x60
111101101: weight=001, order=098, char=0x61
111101110: weight=001, order=099, char=0x62
111101111: weight=001, order=100, char=0x63
111110000: weight=001, order=101, char=0x64
111110001: weight=001, order=102, char=0x65
111110010: weight=001, order=103, char=0x66
111110011: weight=001, order=104, char=0x67
111110100: weight=001, order=105, char=0x68
111110101: weight=001, order=106, char=0x69
111110110: weight=001, order=107, char=0x6a
111110111: weight=001, order=108, char=0x6b
111111000: weight=001, order=109, char=0x6c
111111001: weight=001, order=110, char=0x6d
111111010: weight=001, order=111, char=0x6e
111111011: weight=001, order=112, char=0x6f
111111100: weight=001, order=113, char=0x70
111111101: weight=001, order=114, char=0x71
111111110: weight=001, order=115, char=0x72
111111111: weight=001, order=116, char=0x73
00000000: weight=001, order=117, char=0x74
00000001: weight=001, order=118, char=0x75
00000010: weight=001, order=119, char=0x76
00000011: weight=001, order=120, char=0x77
00000100: weight=001, order=121, char=0x78
00000101: weight=001, order=122, char=0x79
00000110: weight=001, order=123, char=0x7a
00000111: weight=001, order=124, char=0x7b
00001000: weight=001, order=125, char=0x7c
00001001: weight=001, order=126, char=0x7d
00001010: weight=001, order=127, char=0x7e
00001011: weight=001, order=128, char=0x7f
00001100: weight=001, order=129, char=0x80
00001101: weight=001, order=130, char=0x81
00001110: weight=001, order=131, char=0x82
00001111: weight=001, order=132, char=0x83
00010000: weight=001, order=133, char=0x84
00010001: weight=001, order=134, char=0x85
00010010: weight=001, order=135, char=0x86
00010011: weight=001, order=136, char=0x87
00010100: weight=001, order=137, char=0x88
00010101: weight=001, order=138, char=0x89
00010110: weight=001, order=139, char=0x8a
00010111: weight=001, order=140, char=0x8b
00011000: weight=001, order=141, char=0x8c
00011001: weight=001, order=142, char=0x8d
00011010: weight=001, order=143, char=0x8e
00011011: weight=001, order=144, char=0x8f
00011100: weight=001, order=145, char=0x90
00011101: weight=001, order=146, char=0x91
00011110: weight=001, order=147, char=0x92
00011111: weight=001, order=148, char=0x93
00100000: weight=001, order=149, char=0x94
00100001: weight=001, order=150, char=0x95
00100010: weight=001, order=151, char=0x96
00100011: weight=001, order=152, char=0x97
00100100: weight=001, order=153, char=0x98
00100101: weight=001, order=154, char=0x99
00100110: weight=001, order=155, char=0x9a
00100111: weight=001, order=156, char=0x9b
00101000: weight=001, order=157, char=0x9c
00101001: weight=001, order=158, char=0x9d
00101010: weight=001, order=159, char=0x9e
00101011: weight=001, order=160, char=0x9f
00101100: weight=001, order=161, char=0xa0
00101101: weight=001, order=162, char=0xa1
00101110: weight=001, order=163, char=0xa2
00101111: weight=001, order=164, char=0xa3
00110000: weight=001, order=165, char=0xa4
00110001: weight=001, order=166, char=0xa5
00110010: weight=001, order=167, char=0xa6
00110011: weight=001, order=168, char=0xa7
00110100: weight=001, order=169, char=0xa8
00110101: weight=001, order=170, char=0xa9
00110110: weight=001, order=171, char=0xaa
00110111: weight=001, order=172, char=0xab
00111000: weight=001, order=173, char=0xac
00111001: weight=001, order=174, char=0xad
00111010: weight=001, order=175, char=0xae
00111011: weight=001, order=176, char=0xaf
00111100: weight=001, order=177, char=0xb0
00111101: weight=001, order=178, char=0xb1
00111110: weight=001, order=179, char=0xb2
00111111: weight=001, order=180, char=0xb3
01000000: weight=001, order=181, char=0xb4
01000001: weight=001, order=182, char=0xb5
01000010: weight=001, order=183, char=0xb6
01000011: weight=001, order=184, char=0xb7
01000100: weight=001, order=185, char=0xb8
01000101: weight=001, order=186, char=0xb9
01000110: weight=001, order=187, char=0xba
01000111: weight=001, order=188, char=0xbb
01001000: weight=001, order=189, char=0xbc
01001001: weight=001, order=190, char=0xbd
01001010: weight=001, order=191, char=0xbe
01001011: weight=001, order=192, char=0xbf
01001100: weight=001, order=193, char=0xc0
01001101: weight=001, order=194, char=0xc1
01001110: weight=001, order=195, char=0xc2
01001111: weight=001, order=196, char=0xc3
01010000: weight=001, order=197, char=0xc4
01010001: weight=001, order=198, char=0xc5
01010010: weight=001, order=199, char=0xc6
01010011: weight=001, order=200, char=0xc7
01010100: weight=001, order=201, char=0xc8
01010101: weight=001, order=202, char=0xc9
01010110: weight=001, order=203, char=0xca
01010111: weight=001, order=204, char=0xcb
01011000: weight=001, order=205, char=0xcc
01011001: weight=001, order=206, char=0xcd
01011010: weight=001, order=207, char=0xce
01011011: weight=001, order=208, char=0xcf
01011100: weight=001, order=209, char=0xd0
01011101: weight=001, order=210, char=0xd1
01011110: weight=001, order=211, char=0xd2
01011111: weight=001, order=212, char=0xd3
01100000: weight=001, order=213, char=0xd4
01100001: weight=001, order=214, char=0xd5
01100010: weight=001, order=215, char=0xd6
01100011: weight=001, order=216, char=0xd7
01100100: weight=001, order=217, char=0xd8
01100101: weight=001, order=218, char=0xd9
01100110: weight=001, order=219, char=0xda
01100111: weight=001, order=220, char=0xdb
01101000: weight=001, order=221, char=0xdc
01101001: weight=001, order=222, char=0xdd
01101010: weight=001, order=223, char=0xde
01101011: weight=001, order=224, char=0xdf
01101100: weight=001, order=225, char=0xe0
01101101: weight=001, order=226, char=0xe1
01101110: weight=001, order=227, char=0xe2
01101111: weight=001, order=228, char=0xe3
01110000: weight=001, order=229, char=0xe4
01110001: weight=001, order=230, char=0xe5
01110010: weight=001, order=231, char=0xe6
01110011: weight=001, order=232, char=0xe7
01110100: weight=001, order=233, char=0xe8
01110101: weight=001, order=234, char=0xe9
01110110: weight=001, order=235, char=0xea
01110111: weight=001, order=236, char=0xeb
01111000: weight=001, order=237, char=0xec
01111001: weight=001, order=238, char=0xed
01111010: weight=001, order=239, char=0xee
01111011: weight=001, order=240, char=0xef
01111100: weight=001, order=241, char=0xf0
01111101: weight=001, order=242, char=0xf1
01111110: weight=001, order=243, char=0xf2
01111111: weight=001, order=244, char=0xf3
10000000: weight=001, order=245, char=0xf4
10000001: weight=001, order=246, char=0xf5
10000010: weight=001, order=247, char=0xf6
10000011: weight=001, order=248, char=0xf7
10000100: weight=001, order=249, char=0xf8
10000101: weight=001, order=250, char=0xf9
10000110: weight=001, order=251, char=0xfa
10000111: weight=001, order=252, char=0xfb
10001000: weight=001, order=253, char=0xfc
10001001: weight=001, order=254, char=0xfd
10001010: weight=001, order=255, char=0xfe
10001011: weight=001, order=256, char=0xff
10001100: weight=001, order=257, len=3
10001101: weight=001, order=258, len=4
10001110: weight=001, order=259, len=5
10001111: weight=001, order=260, len=6
10010000: weight=001, order=261, len=7
10010001: weight=001, order=262, len=8
10010010: weight=001, order=263, len=9
10010011: weight=001, order=264, len=10
10010100: weight=001, order=265, len=11
10010101: weight=001, order=266, len=12
10010110: weight=001, order=267, len=13
10010111: weight=001, order=268, len=14
10011000: weight=001, order=269, len=15
10011001: weight=001, order=270, len=16
10011010: weight=001, order=271, len=17
10011011: weight=001, order=272, len=18
10011100: weight=001, order=273, len=19
10011101: weight=001, order=274, len=20
10011110: weight=001, order=275, len=21
10011111: weight=001, order=276, len=22
10100000: weight=001, order=277, len=23
10100001: weight=001, order=278, len=24
10100010: weight=001, order=279, len=25
10100011: weight=001, order=280, len=26
10100100: weight=001, order=281, len=27
10100101: weight=001, order=282, len=28
10100110: weight=001, order=283, len=29
10100111: weight=001, order=284, len=30
10101000: weight=001, order=285, len=31
10101001: weight=001, order=286, len=32
10101010: weight=001, order=287, len=33
10101011: weight=001, order=288, len=34
10101100: weight=001, order=289, len=35
10101101: weight=001, order=290, len=36
10101110: weight=001, order=291, len=37
10101111: weight=001, order=292, len=38
10110000: weight=001, order=293, len=39
10110001: weight=001, order=294, len=40
10110010: weight=001, order=295, len=41
10110011: weight=001, order=296, len=42
10110100: weight=001, order=297, len=43
10110101: weight=001, order=298, len=44
10110110: weight=001, order=299, len=45
10110111: weight=001, order=300, len=46
10111000: weight=001, order=301, len=47
10111001: weight=001, order=302, len=48
10111010: weight=001, order=303, len=49
10111011: weight=001, order=304, len=50
10111100: weight=001, order=305, len=51
10111101: weight=001, order=306, len=52
10111110: weight=001, order=307, len=53
10111111: weight=001, order=308, len=54
11000000: weight=001, order=309, len=55
11000001: weight=001, order=310, len=56
11000010: weight=001, order=311, len=57
11000011: weight=001, order=312, len=58
11000100: weight=001, order=313, len=59
11000101: weight=001, order=314, len=60
11000110: weight=002, order=315
11000111: weight=002, order=316
11001000: weight=002, order=317
11001001: weight=002, order=318
11001010: weight=002, order=319
11001011: weight=002, order=320
11001100: weight=002, order=321
11001101: weight=002, order=322
11001110: weight=002, order=323
11001111: weight=002, order=324
11010000: weight=002, order=325
11010001: weight=002, order=326
11010010: weight=002, order=327
11010011: weight=002, order=328
11010100: weight=002, order=329
11010101: weight=002, order=330
11010110: weight=002, order=331
11010111: weight=002, order=332
11011000: weight=002, order=333
11011001: weight=002, order=334
11011010: weight=002, order=335
11011011: weight=002, order=336
11011100: weight=002, order=337
11011101: weight=002, order=338
11011110: weight=002, order=339
11011111: weight=002, order=340
11100000: weight=002, order=341
11100001: weight=002, order=342
11100010: weight=002, order=343
11100011: weight=002, order=344
11100100: weight=002, order=345
11100101: weight=002, order=346
11100110: weight=002, order=347
11100111: weight=002, order=348
11101000: weight=002, order=349
11101001: weight=002, order=350
11101010: weight=002, order=351
11101011: weight=002, order=352
11101100: weight=002, order=353
11101101: weight=002, order=354
11101110: weight=002, order=355
11101111: weight=002, order=356
11110000: weight=002, order=357
11110001: weight=002, order=358
11110010: weight=002, order=359
11110011: weight=002, order=360
11110100: weight=002, order=361
11110101: weight=002, order=362
11110110: weight=002, order=363
11110111: weight=002, order=364
11111000: weight=002, order=365
11111001: weight=002, order=366
11111010: weight=002, order=367
11111011: weight=002, order=368
11111100: weight=002, order=369
11111101: weight=002, order=370
11111110: weight=002, order=371
11111111: weight=002, order=372
0000000: weight=002, order=373
0000001: weight=002, order=374
0000010: weight=002, order=375
0000011: weight=002, order=376
0000100: weight=002, order=377
0000101: weight=002, order=378
0000110: weight=002, order=379
0000111: weight=002, order=380
0001000: weight=002, order=381
0001001: weight=002, order=382
0001010: weight=002, order=383
0001011: weight=002, order=384
0001100: weight=002, order=385
0001101: weight=002, order=386
0001110: weight=002, order=387
0001111: weight=002, order=388
0010000: weight=002, order=389
0010001: weight=002, order=390
0010010: weight=002, order=391
0010011: weight=002, order=392
0010100: weight=002, order=393
0010101: weight=002, order=394
0010110: weight=002, order=395
0010111: weight=002, order=396
0011000: weight=002, order=397
0011001: weight=002, order=398
0011010: weight=002, order=399
0011011: weight=002, order=400
0011100: weight=002, order=401
0011101: weight=002, order=402
0011110: weight=002, order=403
0011111: weight=002, order=404
0100000: weight=002, order=405
0100001: weight=002, order=406
0100010: weight=002, order=407
0100011: weight=002, order=408
0100100: weight=002, order=409
0100101: weight=002, order=410
0100110: weight=002, order=411
0100111: weight=002, order=412
0101000: weight=002, order=413
0101001: weight=002, order=414
0101010: weight=002, order=415
0101011: weight=002, order=416
0101100: weight=002, order=417
0101101: weight=002, order=418
0101110: weight=002, order=419
0101111: weight=002, order=420
0110000: weight=002, order=421
0110001: weight=002, order=422
0110010: weight=002, order=423
0110011: weight=002, order=424
0110100: weight=002, order=425
0110101: weight=002, order=426
0110110: weight=002, order=427
0110111: weight=002, order=428
0111000: weight=002, order=429
0111001: weight=002, order=430
0111010: weight=002, order=431
0111011: weight=002, order=432
0111100: weight=002, order=433
0111101: weight=002, order=434
0111110: weight=002, order=435
0111111: weight=002, order=436
1000000: weight=002, order=437
1000001: weight=002, order=438
1000010: weight=002, order=439
1000011: weight=002, order=440
1000100: weight=002, order=441
1000101: weight=002, order=442
1000110: weight=002, order=443
1000111: weight=002, order=444
1001000: weight=002, order=445
1001001: weight=002, order=446
1001010: weight=002, order=447
1001011: weight=002, order=448
1001100: weight=002, order=449
1001101: weight=002, order=450
1001110: weight=002, order=451
1001111: weight=002, order=452
1010000: weight=002, order=453
1010001: weight=002, order=454
1010010: weight=002, order=455
1010011: weight=002, order=456
1010100: weight=002, order=457
1010101: weight=002, order=458
1010110: weight=002, order=459
1010111: weight=002, order=460
1011000: weight=002, order=461
1011001: weight=002, order=462
1011010: weight=002, order=463
1011011: weight=002, order=464
1011100: weight=002, order=465
1011101: weight=002, order=466
1011110: weight=002, order=467
1011111: weight=002, order=468
1100000: weight=002, order=469
1100001: weight=002, order=470
1100010: weight=002, order=471
1100011: weight=004, order=472
1100100: weight=004, order=473
1100101: weight=004, order=474
1100110: weight=004, order=475
1100111: weight=004, order=476
1101000: weight=004, order=477
1101001: weight=004, order=478
1101010: weight=004, order=479
1101011: weight=004, order=480
1101100: weight=004, order=481
1101101: weight=004, order=482
1101110: weight=004, order=483
1101111: weight=004, order=484
1110000: weight=004, order=485
1110001: weight=004, order=486
1110010: weight=004, order=487
1110011: weight=004, order=488
1110100: weight=004, order=489
1110101: weight=004, order=490
1110110: weight=004, order=491
1110111: weight=004, order=492
1111000: weight=004, order=493
1111001: weight=004, order=494
1111010: weight=004, order=495
1111011: weight=004, order=496
1111100: weight=004, order=497
1111101: weight=004, order=498
1111110: weight=004, order=499
1111111: weight=004, order=500
000000: weight=004, order=501
000001: weight=004, order=502
000010: weight=004, order=503
000011: weight=004, order=504
000100: weight=004, order=505
000101: weight=004, order=506
000110: weight=004, order=507
000111: weight=004, order=508
001000: weight=004, order=509
001001: weight=004, order=510
001010: weight=004, order=511
001011: weight=004, order=512
001100: weight=004, order=513
001101: weight=004, order=514
001110: weight=004, order=515
001111: weight=004, order=516
010000: weight=004, order=517
010001: weight=004, order=518
010010: weight=004, order=519
010011: weight=004, order=520
010100: weight=004, order=521
010101: weight=004, order=522
010110: weight=004, order=523
010111: weight=004, order=524
011000: weight=004, order=525
011001: weight=004, order=526
011010: weight=004, order=527
011011: weight=004, order=528
011100: weight=004, order=529
011101: weight=004, order=530
011110: weight=004, order=531
011111: weight=004, order=532
100000: weight=004, order=533
100001: weight=004, order=534
100010: weight=004, order=535
100011: weight=004, order=536
100100: weight=004, order=537
100101: weight=004, order=538
100110: weight=004, order=539
100111: weight=004, order=540
101000: weight=004, order=541
101001: weight=004, order=542
101010: weight=004, order=543
101011: weight=004, order=544
101100: weight=004, order=545
101101: weight=004, order=546
101110: weight=004, order=547
101111: weight=004, order=548
110000: weight=004, order=549
110001: weight=006, order=550
110010: weight=008, order=551
110011: weight=008, order=552
110100: weight=008, order=553
110101: weight=008, order=554
110110: weight=008, order=555
110111: weight=008, order=556
111000: weight=008, order=557
111001: weight=008, order=558
111010: weight=008, order=559
111011: weight=008, order=560
111100: weight=008, order=561
111101: weight=008, order=562
111110: weight=008, order=563
111111: weight=008, order=564
00000: weight=008, order=565
00001: weight=008, order=566
00010: weight=008, order=567
00011: weight=008, order=568
00100: weight=008, order=569
00101: weight=008, order=570
00110: weight=008, order=571
00111: weight=008, order=572
01000: weight=008, order=573
01001: weight=008, order=574
01010: weight=008, order=575
01011: weight=008, order=576
01100: weight=008, order=577
01101: weight=008, order=578
01110: weight=008, order=579
01111: weight=008, order=580
10000: weight=008, order=581
10001: weight=008, order=582
10010: weight=008, order=583
10011: weight=008, order=584
10100: weight=008, order=585
10101: weight=008, order=586
10110: weight=008, order=587
10111: weight=008, order=588
11000: weight=010, order=589
11001: weight=016, order=590
11010: weight=016, order=591
11011: weight=016, order=592
11100: weight=016, order=593
11101: weight=016, order=594
11110: weight=016, order=595
11111: weight=016, order=596
0000: weight=016, order=597
0001: weight=016, order=598
0010: weight=016, order=599
0011: weight=016, order=600
0100: weight=016, order=601
0101: weight=016, order=602
0110: weight=016, order=603
0111: weight=016, order=604
1000: weight=016, order=605
1001: weight=016, order=606
1010: weight=016, order=607
1011: weight=016, order=608
1100: weight=026, order=609
1101: weight=032, order=610
1110: weight=032, order=611
1111: weight=032, order=612
000: weight=032, order=613
001: weight=032, order=614
010: weight=032, order=615
011: weight=032, order=616
100: weight=032, order=617
101: weight=032, order=618
110: weight=058, order=619
111: weight=064, order=620
00: weight=064, order=621
01: weight=064, order=622
10: weight=064, order=623
11: weight=122, order=624
0: weight=128, order=625
1: weight=186, order=626
: weight=314, order=627
現状のテストプログラムはこんなところです。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#ifdef __TURBOC__
/* Turbo C++, Borland C++ */
#include <io.h>
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
typedef unsigned char uchar;
typedef unsigned long ulong;
#define TRUE 1
#define FALSE 0
int hufInitTree(void);
void hufPrintNode(int, int);
int hufSearchLevel(int, int, int);
int hufGetSwapTarget(int);
int hufDecode(int, int, int);
void hufDumpTree(int, int);
#if 0
void hufPrintTreeData(void);
#endif
long itemOpen(long);
long itemGetBit(int);
int itemClose(void);
int main(int, char **);
/*------------------- ハフマン符号の伸張処理 ----------------------*
/*
* ハフマン木のノード用構造体
*/
typedef struct {
int parent; /* 親ノードのインデックス */
int child[2]; /* 左右の子ノードへのインデックス */
long weight; /* 重み(初期値1) */
int order; /* ノード順序(下から上、左から右) */
uchar type; /* 葉ノードの値のタイプ */
uchar val; /* 葉ノードの値 */
} HUFNODE;
/*
* ハフマン木の初期データ記述用構造体
*/
typedef struct {
long startcode; /* ハフマン符号範囲の開始値 */
long endcode; /* ハフマン符号範囲の終了値 */
int codelen; /* ハフマン符号の長さ */
uchar type; /* ハフマン符号に対応する値のタイプ */
uchar startval; /* 開始ハフマン符号の値(以降1ずつ増加) */
} HUFINIT;
#define HUF_TYPE_NONE 0 /* ルートまたは中間ノード */
#define HUF_TYPE_CHAR 1 /* 葉ノード、値は不一致文字 */
#define HUF_TYPE_LEN 2 /* 葉ノード、値は一致長 */
#define HUF_NUM_ROOT 0 /* ルートノードのインデックス */
#define HUF_NUM_NODES 627 /* ハフマン木のノード数(1+2+4+…+256+116) */
/*
* ハフマン木の初期化データ
*/
HUFINIT huf_init[] = {
{ 0x00L, 0x8bL, 8, /* 不一致文字: */
HUF_TYPE_CHAR, 0x74 }, /* 00000000(0x74) ~ 10001011(0xff) */
{ 0x8cL, 0xc5L, 8, /* 一致長: */
HUF_TYPE_LEN, 3 }, /* 10001100(3) ~ 11000101(60) */
{ 0x18cL, 0x1ffL, 9, /* 不一致文字: */
HUF_TYPE_CHAR, 0x00 } /* 110001100(0x00) ~ 111111111(0x73) */
};
int huf_nodenum; /* 登録ノード数(HUF_NUM_NODESと同じはず) */
HUFNODE huf_node[HUF_NUM_NODES]; /* ハフマン木のノードデータ格納用 */
/*
* ハフマン木を初期化する
*/
int
hufInitTree(void)
{
int i, top, depth, order;
HUFINIT *ip;
/*
* ルートノードを作る
*/
top = HUF_NUM_ROOT;
huf_node[top].parent = -1;
huf_node[top].child[0] = -1;
huf_node[top].child[1] = -1;
huf_node[top].weight = 0L;
huf_node[top].order = 0;
huf_node[top].type = HUF_TYPE_NONE;
top++;
ip = huf_init;
for (i = 0; i < sizeof(huf_init) / sizeof(huf_init[0]); i++) {
uchar type, val;
long code;
type = ip->type;
val = ip->startval;
for (code = ip->startcode; code <= ip->endcode; code++) {
int n, dir;
long mask;
/*
* 個々の初期化データについて...
*/
depth = 0;
n = 0;
for (mask = 1 << (ip->codelen - 1); mask != 0; mask >>= 1) {
/*
* 上位ビットからノードをたどる
*/
depth++;
dir = (code & mask) != 0;
if (huf_node[n].child[dir] == -1) {
/*
* 新規ノードを追加
*/
huf_node[n].child[dir] = top;
huf_node[top].parent = n;
huf_node[top].child[0] = -1;
huf_node[top].child[1] = -1;
huf_node[top].weight = 0L;
huf_node[top].order = -depth; /* 順序判定用 */
huf_node[top].type = HUF_TYPE_NONE;
top++;
}
huf_node[n].weight++;
n = huf_node[n].child[dir];
}
/*
* 葉ノードにデータを設定
*/
huf_node[n].weight = 1L;
huf_node[n].type = type;
huf_node[n].val = val++;
}
ip++;
}
/*
* 深いノードから順に、左から右に順番をつける(FGK)
*/
order = 1;
while (depth >= 0) {
for (i = HUF_NUM_ROOT; i < top; i++) {
if (huf_node[i].order == -depth)
huf_node[i].order = order++;
}
depth--;
}
huf_nodenum = top;
return huf_nodenum;
}
/*
* ノードの情報を表示する
*/
void
hufPrintNode(int num, int printorder)
{
#define HUF_NUM_MAXLEVEL 32
int n;
uchar *p, buf[HUF_NUM_MAXLEVEL];
p = &buf[HUF_NUM_MAXLEVEL - 1];
*p = '\0';
for (n = num; n != HUF_NUM_ROOT; n = huf_node[n].parent)
*--p = (n == huf_node[huf_node[n].parent].child[0])? '0': '1';
printf("'%s', weight=%ld", p, huf_node[num].weight);
if (printorder)
printf(", order=%d", huf_node[num].order);
switch (huf_node[num].type) {
case HUF_TYPE_NONE:
printf(", (intermediate)");
break;
case HUF_TYPE_CHAR:
printf(", ch=0x%02x", (int)huf_node[num].val);
break;
case HUF_TYPE_LEN:
printf(", len=%d", (int)huf_node[num].val);
break;
}
printf("\n");
}
/*
* 指定された深さの交換先ノードを得る(Vitter)
*/
int
hufSearchLevel(int cur, int target, int level)
{
int ret;
if (target < 0 || level < 0)
return -1;
if (level == 0) {
if (huf_node[cur].weight == huf_node[target].weight &&
(huf_node[cur].type == HUF_TYPE_NONE &&
huf_node[target].type == HUF_TYPE_NONE ||
huf_node[cur].type != HUF_TYPE_NONE &&
huf_node[target].type != HUF_TYPE_NONE)) {
return target;
}
return -1;
}
if (huf_node[target].child[1] != -1) {
ret = hufSearchLevel(cur, huf_node[target].child[1], level-1);
if (ret >= 0)
return ret;
}
if (huf_node[target].child[0] != -1) {
ret = hufSearchLevel(cur, huf_node[target].child[0], level-1);
if (ret >= 0)
return ret;
}
return -1;
}
/*
* 交換先のノードを得る(Vitter)
*/
int
hufGetSwapTarget(int cur)
{
int n, ret;
n = 1;
for (;;) {
ret = hufSearchLevel(cur, HUF_NUM_ROOT, n++);
if (ret != -1)
return ret;
}
}
/*
* 作業中...
*/
int
hufDecode(int verbose, int dodump, int vitter)
{
int i, bit, cur, ch, lastch;
lastch = '\0';
for (;;) {
printf("output: ");
cur = HUF_NUM_ROOT;
while (huf_node[cur].type == HUF_TYPE_NONE) {
if ((bit = (int)itemGetBit(1)) < 0)
return -1;
printf("%c", bit + '0');
cur = huf_node[cur].child[bit];
}
printf(": ");
if (huf_node[cur].type == HUF_TYPE_CHAR) {
ch = (int)huf_node[cur].val;
printf("char=0x%02x", ch);
if (lastch != '\0') {
if (ch >= 0x40 && ch != 0x7f && ch <= 0xfc)
printf(" '%c%c'", lastch, ch);
lastch = '\0';
} else if (ch >= 0x20 && ch <= 0x7f) {
printf(" '%c'", ch);
lastch = '\0';
} else if (ch >= 0x81 && ch <= 0x9f || ch >= 0xe0 && ch <= 0xfc) {
lastch = ch;
}
} else {
printf("len=%d, disp=%d",
(int)huf_node[cur].val, (int)itemGetBit(11));
}
printf("\n");
/*
* FGK法によるハフマン木の組み替え
* 葉ノードからルートノードに向かって処理
*/
while (cur != HUF_NUM_ROOT) {
int target, maxorder, tmp;
long curweight;
/*
* 交換先として、同じ重みをもつノードのうち
* 順序番号が最大のものを得る
*/
if (vitter) {
target = hufGetSwapTarget(cur);
} else /* FGK */ {
target = cur;
curweight = huf_node[cur].weight;
maxorder = huf_node[cur].order;
for (i = 0; i < huf_nodenum; i++) {
if (huf_node[i].weight == curweight &&
huf_node[i].order > maxorder) {
target = i;
maxorder = huf_node[target].order;
}
}
}
if (target != cur) {
int curpar, targetpar;
/*
* 現在のノードと交換先のノードを交換する
* (親子リンクの貼り替えと順序番号の交換)
*/
if (verbose) {
printf("swap: current: ");
hufPrintNode(cur, !vitter);
printf(" target: ");
hufPrintNode(target, !vitter);
}
targetpar = huf_node[target].parent;
curpar = huf_node[cur].parent;
if (huf_node[targetpar].child[0] == target)
huf_node[targetpar].child[0] = cur;
else if (huf_node[targetpar].child[1] == target)
huf_node[targetpar].child[1] = cur;
else
fprintf(stderr, "Internal error in hufDecode()\n");
if (huf_node[curpar].child[0] == cur)
huf_node[curpar].child[0] = target;
else if (huf_node[curpar].child[1] == cur)
huf_node[curpar].child[1] = target;
else
fprintf(stderr, "Internal error in hufDecode()\n");
huf_node[target].parent = curpar;
huf_node[cur].parent = targetpar;
tmp = huf_node[target].order;
huf_node[target].order = huf_node[cur].order;
huf_node[cur].order = tmp;
}
huf_node[cur].weight++;
cur = huf_node[cur].parent;
}
huf_node[cur].weight++;
if (dodump)
hufDumpTree(HUF_NUM_ROOT, 0);
}
}
void
hufDumpTree(int n, int level)
{
HUFNODE *p = &huf_node[n];
static uchar huf_digits[10];
if (p->type == HUF_TYPE_NONE) {
huf_digits[level] = '\0';
printf("%s: weight=%03ld, order=%03d\n",
huf_digits, p->weight, p->order);
if (p->child[0] != -1) {
huf_digits[level] = '0';
hufDumpTree(p->child[0], level+1);
}
if (p->child[1] != -1) {
huf_digits[level] = '1';
hufDumpTree(p->child[1], level+1);
}
return;
}
huf_digits[level] = '\0';
printf("%s: weight=%03ld, order=%03d, ",
huf_digits, p->weight, p->order);
if (p->type == HUF_TYPE_CHAR)
printf("char=0x%02x\n", (int)p->val);
else
printf("len=%d\n", (int)p->val);
}
#if 0
/*
* ノードデータの内容を登録順に表示する
*/
void
hufPrintTreeData(void)
{
int i;
HUFNODE *p = huf_node;
for (i = 0; i < huf_nodenum; i++) {
printf("n=%3d, p=%3d, l=%3d, r=%3d, w=%3ld, o=%3d, t=%d, v=%d\n",
i, p->parent, p->child[0], p->child[1],
p->weight, p->order, p->type, p->val);
p++;
}
}
#endif
/*----------- 世界大百科事典の項目データファイルの処理 ------------*/
#define IT_FILE_LOC "itemloc.dat" /* 項目エントリファイル */
#define IT_FILE_ITEM "item.dat" /* 項目データファイル */
#define IT_NUM_LOCSIZ 16L /* 項目エントリのサイズ(itemloc.dat) */
#define IT_NUM_ITHDR 6L /* 項目ヘッダのサイズ(item.dat) */
static int it_locfd; /* itemloc.datのファイル記述子 */
static int it_itemfd = -1; /* item.datのファイル記述子 */
static long it_unread; /* 項目データの未読バイト数 */
static int it_bufend; /* it_bufの終端 */
static int it_curoff; /* it_buf中の現在のオフセット */
static int it_curbyte; /* 現在読んでいるバイトデータ */
static int it_curbit; /* 現在読んでいるビット位置 */
static uchar it_buf[BUFSIZ]; /* 項目読み込み用バッファ */
/*
* 項目データを読む準備をする
*/
long
itemOpen(long itemno)
{
int n, len;
ulong off, size, expand;
uchar loc[IT_NUM_LOCSIZ];
/*
* 項目エントリファイルを開き、指定された項目に対する
* 項目データファイル中のオフセットとサイズを得る
*/
if ((it_locfd = open(IT_FILE_LOC, O_RDONLY|O_BINARY)) < 0) {
return -1;
}
if (lseek(it_locfd, itemno * IT_NUM_LOCSIZ, SEEK_SET) < 0) {
close(it_locfd);
return -1;
}
if (read(it_locfd, loc, IT_NUM_LOCSIZ) != IT_NUM_LOCSIZ) {
close(it_locfd);
return -1;
}
close(it_locfd);
off = ((ulong)loc[0] << 24) + ((ulong)loc[1] << 16)
+ ((ulong)loc[2] << 8) + (ulong)loc[3];
size = ((ulong)loc[4] << 24) + ((ulong)loc[5] << 16)
+ ((ulong)loc[6] << 8) + (ulong)loc[7];
/*
* 項目データファイルを開き、バッファ1回分先読みする
*/
if ((it_itemfd = open(IT_FILE_ITEM, O_RDONLY|O_BINARY)) < 0) {
return -1;
}
if (lseek(it_itemfd, off, SEEK_SET) < 0) {
close(it_itemfd);
it_itemfd = -1;
return -1;
}
len = (size > (long)BUFSIZ)? BUFSIZ: (int)size;
if ((n = read(it_itemfd, it_buf, len)) < len) {
close(it_itemfd);
it_itemfd = -1;
return -1;
}
expand = ((ulong)it_buf[5] << 24) + ((ulong)it_buf[4] << 16)
+ ((ulong)it_buf[3] << 8) + (ulong)it_buf[2];
it_unread = size - (long)n;
it_bufend = n;
it_curoff = IT_NUM_ITHDR;
it_curbyte = it_buf[it_curoff];
it_curbit = 7;
/*
* 項目データ伸張後のサイズを返す
*/
return expand;
}
/*
* 項目データから指定ビット数のデータを読む
* ビットデータはMSBから先に読まれる
*/
long
itemGetBit(int nbits)
{
long val;
val = 0L;
while (nbits-- > 0) {
if (it_curbit < 0) {
if (it_curoff < it_bufend - 1) {
/*
* 先読みされたデータがまだある
*/
it_curbyte = it_buf[++it_curoff];
it_curbit = 7;
} else if (it_unread <= 0L) {
/*
* 未読のデータがない
*/
return -1;
} else {
int n, len;
/*
* バッファ1回分データを読む
*/
len = (it_unread > (long)BUFSIZ)? BUFSIZ: (int)it_unread;
if ((n = read(it_itemfd, it_buf, len)) < len) {
close(it_itemfd);
it_itemfd = -1;
return -1L;
}
it_unread -= (long)n;
it_bufend = n;
it_curoff = 0;
it_curbyte = it_buf[it_curoff];
it_curbit = 7;
}
}
val = (val << 1) | (it_curbyte >> it_curbit--) & 1;
}
return val;
}
/*
* 項目データの読み込みを終了する
*/
int
itemClose(void)
{
int ret;
if (it_itemfd < 0)
return 0;
ret = close(it_itemfd);
it_itemfd = -1;
return ret;
}
/*--------- メイン ---------*/
void
usage(void)
{
fprintf(stderr, "decode [-v] [-d] [-V] itemno\n");
fprintf(stderr, " -v: verbose\n");
fprintf(stderr, " -d: dump tree each time\n");
fprintf(stderr, " -V: use Vitter instead of FGK\n");
exit(1);
}
int
main(int ac, char **av)
{
int i, verbose, dodump, vitter;
uchar *s;
long itemno;
verbose = FALSE;
dodump = FALSE;
vitter = FALSE;
ac--, av++;
if (ac > 0 && **av == '-') {
for (s = *av + 1; *s; s++) {
switch (*s) {
case 'v':
verbose = TRUE;
break;
case 'd':
dodump = TRUE;
break;
case 'V':
vitter = TRUE;
break;
default:
usage();
}
}
ac--, av++;
}
if (ac <= 0)
usage();
itemno = strtol(*av, NULL, 10);
if (itemno < 0L) {
fprintf(stderr, "Invalid itemno: %ld\n", itemno);
exit(1);
}
printf("itemno=%ld\n", itemno);
if (hufInitTree() < 0) {
fprintf(stderr, "hufInitTree() failed\n");
exit(1);
}
if (dodump) {
hufDumpTree(HUF_NUM_ROOT, 0);
#if 0
hufPrintTreeData();
#endif
}
if (itemOpen(itemno) < 0) {
fprintf(stderr, "itemOpen() failed\n");
exit(1);
}
hufDecode(verbose, dodump, vitter);
itemClose();
exit(0);
どうも参照開始位置は11ビットと9ビットの2種類あるよ
うです。参照開始位置の先頭2ビットが00だったら9ビッ
ト、さもなければ11ビットと解釈するというルールで項
目「IIR」は復元できました。しかし長い項目を表示さ
せると、やはり途中から壊れてしまいます。何かまだ気
づいていないルールがあるのでしょうね。
ひょっとしたら参照開始位置も独立に適応型ハフマン圧
縮されているのかな???
ハフマン木の更新アルゴリズムは前回のままFGK法を使
っていますが、どうやらそのままでよさそうです。
# そろそろ別の締切が来るし、しばらく塩漬けかな? (^^;
●項目「IIR」の伸張結果
itemno=8
output: 10011011: len=18, disp=995 (01111100011)
output: 111010101: char=0x49 'I'
output: 111011110: char=0x52 'R'
output: 10011000: len=15, disp=995 (01111100011)
output: 00001111: char=0x83
output: 111001101: char=0x41 'ア'
output: 11000001: char=0x83
output: 111001111: char=0x43 'イ'
output: 1011111: char=0x83
output: 11000000: char=0x41 'ア'
output: 00001101: char=0x81
output: 111100111: char=0x5b 'ー'
output: 1011111: char=0x83
output: 00010111: char=0x8b 'ル'
output: 10010111: len=14, disp=1005 (01111101101)
output: 10010110: len=13, disp=970 (01111001010)
output: 111000000: char=0x34 '4'
output: 111000100: char=0x38 '8'
output: 110111100: char=0x30 '0'
output: 10110111: char=0x34 '4'
output: 10001110: len=5, disp=970 (01111001010)
output: 10001100: len=3, disp=43 (000101011) (←“イア”の先頭3バイト※)
output: 111101000: char=0x5c '\' (←“ソ”の2バイトめ)
output: 101011: char=0x83
output: 00000010: char=0x76 'プ'
output: 101011: char=0x83
output: 00011000: char=0x8c 'レ'
output: 101011: char=0x83
output: 00011111: char=0x93 'ン'
output: 101011: char=0x83
output: 111011111: char=0x53 'ゴ'
output: 10011: char=0x83
output: 00001100: char=0x80 'ム'
output: 10001111: len=6, disp=984 (01111011000)
output: 10010000: len=7, disp=886 (01101110110)
output: 00000
※disp=44でないとつじつまが合わない...。
●項目「アイ(藍)」の伸張結果(先頭付近)
itemno=0
output: 10010001: len=8, disp=776 (01100001000)
output: 110110111: char=0x2b '+'
output: 10010000: len=7, disp=758 (01011110110)
output: 00001111: char=0x83
output: 111001111: char=0x43 'イ'
output: 11000010: char=0x83
output: 00010101: char=0x89 'ラ'
output: 1011111: char=0x83
output: 111100100: char=0x58 'ス'
output: 1011111: char=0x83
output: 111110011: char=0x67 'ト'
output: 10001101: len=4, disp=36 (000100100)
output: 11000100: char=0x2b '+'
output: 10111011: len=4, disp=36 (000100100)
output: 10011100: len=19, disp=24 (000011000)
output: 110111110: char=0x32 '2'
output: 1011011: len=4, disp=24 (000011000)
output: 110111111: char=0x33 '3'
output: 10111010: len=19, disp=24 (000011000)
output: 10110110: char=0x33 '3'
output: 1011100: len=4, disp=24 (000011000)
output: 10010011: len=10, disp=794 (01100011010)
output: 00011100: char=0x90
output: 10000001: char=0xf5 '染'
output: 00100011: char=0x97
output: 01001011: char=0xbf '料'
output: 00001110: char=0x82
output: 01010010: char=0xc6 'と'
output: 10110000: char=0x82
output: 01000001: char=0xb5 'し'
output: 1001111: char=0x82
output: 01010000: char=0xc4 'て'
output: 1010110: char=0x82
output: 01011000: char=0xcc 'の'
output: 10110010: char=0x97
output: 00100001: char=0x95 '藍'
output: 1010011: len=19, disp=808 (01100101000)
output: 00011111: char=0x93
output: 10000110: char=0xfa '日'
output: 00100010: char=0x96
output: 00000111: char=0x7b '本'
output: 100110: char=0x82
output: 01010101: char=0xc9 'に'
output: 100110: char=0x82
output: 00110100: char=0xa8 'お'
output: 100111: char=0x82
output: 00111011: char=0xaf 'け'
output: 101000: char=0x82
output: 01110101: char=0xe9 'る'
output: 00011001: char=0x8d
output: 01011001: char=0xcd '栽'
output: 00100000: char=0x94
output: 00001000: char=0x7c '培'
output: 00110001: char=0xa5
output: 1001001: char=0x97
output: 00111000: char=0xac '流'
output: 00011110: char=0x92
output: 01010110: char=0xca '通'
output: 101011000: len=3, disp=43 (000101011)
output: 101000100: char=0xf0
output: 00011010: char=0x8e ' ���阨���臼臼碓臼虻�竏癇衆��ш�阨���臼臼碓臼虻�跂扈姥��粡齔集概�┛臼葦旭旭臼�
阨���臼臼臼旭浦�竏癇衆��ы�阨���旭葦碓旭�竏癇衆��阨���葦旭臼臼�竏癇衆���ぢ古'
output: 00011101: char=0x91
output: 01101111: char=0xe3 '代'
output: 00001101: char=0x81
output: 11000001: char=0x43 ','
output: 10010010: char=0x92
output: 00010010: char=0x86 '中'
output: 10110100: char=0x90
output: 00101110: char=0xa2 '世'
output: 10000110: char=0x81
output: 111111010: char=0x6e ']'
output: 101111111: len=12, disp=845 (01101001101)
output: 110000100: len=5, disp=28 (000011100)
output: 00010111: char=0x8b
output: 01100011: char=0xdf '近'
output: 11000011: len=7, disp=22 (000010110)
output: 10010000: len=3, disp=643 (01010000011)
output: 10000010: len=12, disp=1176 (10010011000)
output: 10110101: len=10, disp=1643 (11001101011)
output: 01001110: char=0xc2
output: 101101101: char=0xfd
output: 00100101: char=0x99
output: 01010011: char=0xc7 '夘'
output: 111111100: char=0x70 'p'
output: 110010011: char=0x07
output: 0111011: char=0x33 '3'
output: 00000001: char=0x75 'u'
●項目「アイ(藍)」の本文先頭付近
| <TOC><Z1+:0001:>イラスト</Z1+><Z2+:0001:>イラスト</Z2+><Z3+:0001:>
| イラスト</Z3+><Z4:0002:>【染料としての藍】</Z4><Z5:0003:>
| 【日本における栽培\xa5流通の歴史】</Z5><Z6:0003:>[古代,中世]
| </Z6><Z7:0003:>[近世]</Z7></TOC><TITLE>アイ(藍)</TITLE>
| <YOMI1>アイ</YOMI1><EUTITLE>Chinese indigo
参照開始位置は9~14ビットで可変のようです。先頭4ビ
ットで区別しているみたい??? とりあえず本文のハフマ
ン圧縮は伸長できるようになったようです。
> ひょっとしたら参照開始位置も独立に適応型ハフマン圧
> 縮されているのかな???
これについては
<87n0b7z1ge.wl%fu...@chi.its.hiroshima-cu.ac.jp>で
| ●(5) 一致開始位置が同じときコードも同じだから。
で否定されてましたね。
以下は項目00007「アイアトン」の伸長結果です。
itemno=7
10011011: len=18, disp=995 (01111100011)
00001111: char=0x83
111001101: char=0x41 'ア'
11000100: char=0x83
111001111: char=0x43 'イ'
10001100: len=3, disp=3 (000000011)
111110011: char=0x67 'g'
1011111: char=0x83
00011111: char=0x93 'ン'
10010010: len=9, disp=1003 (01111101011)
10010001: len=8, disp=964 (01111000100)
111010100: char=0x48 'H'
111110001: char=0x65 'e'
111111010: char=0x6e 'n'
111111110: char=0x72 'r'
00000101: char=0x79 'y'
110101100: char=0x20 ' '
111010101: char=0x49 'I'
10110111: char=0x72 'r'
10111001: char=0x65 'e'
00000000: char=0x74 't'
111111011: char=0x6f 'o'
10111000: char=0x6e 'n'
10010101: len=12, disp=986 (01111011010)
10110100: char=0x49 'I'
111011110: char=0x52 'R'
111100000: char=0x54 'T'
10111010: char=0x48 'H'
111001010: char=0x3e '>'
110111101: char=0x31 '1'
111000010: char=0x36 '6'
10101101: char=0x31 '1'
1010000: char=0x31 '1'
00001101: char=0x81
111101001: char=0x5d '‐'
111000001: char=0x35 '5'
1010101: char=0x31 '1'
11000001: len=3, disp=867 (01101100011)
10001110: len=5, disp=15 (000001111)
10001111: len=6, disp=1009 (01111110001)
1001101: len=3, disp=139 (0010001011)
111011001: char=0x4d 'M'
1011111: char=0x83
00010110: char=0x8a 'リ'
100100: char=0x83
111100100: char=0x58 'ス'
10101001: char=0x81
11000010: char=0x43 ','
100101: char=0x83
111111111: char=0x73 'ピ'
100111: char=0x83
00010001: char=0x85 'ュ'
1001000: char=0x81
111100111: char=0x5b 'ー'
1010010: len=3, disp=11 (000001011)
111101010: char=0x5e '^'
100111: char=0x83
10111101: char=0x93 'ン'
10100001: char=0x8a
00000010: char=0x76 '革'
00100010: char=0x96
01001001: char=0xbd '命'
1000011: char=0x8a
101110000: char=0xfa '期'
00001110: char=0x82
01011000: char=0xcc 'の'
00011000: char=0x8c
10110000: char=0x52 '軍'
00011100: char=0x90
111111000: char=0x6c '人'
1001100: char=0x81
1000000: char=0x43 ','
10001100: char=0x90
00111001: char=0xad '政'
00011010: char=0x8e
00101101: char=0xa1 '治'
00010101: char=0x89
01010010: char=0xc6 '家'
011011: char=0x81
111001110: char=0x42 '。'
01100: char=0x83
0111111: char=0x49 'オ'
111001000: char=0x3c '<'
1000101: char=0x43 'C'
0111110: char=0x52 'R'
10101110: char=0x3e '>'
01100: char=0x83
111101110: char=0x62 'ッ'
01100: char=0x83
111011010: char=0x4e 'ク'
01101: char=0x83
10100000: char=0x58 'ス'
01110: char=0x83
10110011: char=0x74 'フ'
01110: char=0x83
0110011: char=0x48 'ォ'
010111: len=3, disp=45 (000101101)
111110100: char=0x68 'h'
10001111: char=0x82
10000100: char=0xc6 'と'
10010100: char=0x96
111001100: char=0x40 '法'
1001001: char=0x8a
00000011: char=0x77 '学'
10000101: char=0x89
01111000: char=0x40 '院'
0101011: char=0x82
101010101: char=0xc9 'に'
010001: char=0x8a
01101101: char=0x77 '学'
0110111: char=0x82
00111101: char=0xd1 'び'
011010: char=0x81
001111: char=0x43 ','
001111: char=0x31 '1'
10101100: char=0x36 '6'
111000000: char=0x34 '4'
110111110: char=0x32 '2'
00100000: char=0x94
01111100: char=0x4e '年'
0100010: char=0x93
110001000: char=0xe0 '内'
00100011: char=0x97
0101100: char=0x90 '乱'
0101001: char=0x96
00000001: char=0x75 '勃'
01110000: char=0x94
10001000: char=0xad '発'
00000011: len=4, disp=47 (000101111)
001011: char=0x82
0101100: char=0xc6 'と'
010101: len=3, disp=1 (000000001)
01101101: char=0xe0
001011: char=0x82 '烽'
01110100: char=0xc9
00010111: char=0x8b
111101111: char=0x63 '議'
0010111: char=0x89
101110011: char=0xef '会'
10001101: char=0x8c
0111111: char=0x52 '軍'
010100: char=0x82
0010011: char=0xc9 'に'
10000111: char=0x8e
111011101: char=0x51 '参'
0110000: char=0x89
011011011: char=0xc1 '加'
010011: char=0x81
10000001: char=0x42 '。'
111011011: char=0x4f 'O'
110111010: char=0x2e '.'
10110101: char=0x20 ' '
010010: len=3, disp=134 (0010000110)
100110001: char=0x8d
01001: char=0x83 '鴻'
100111100: char=0x80
01001: char=0x83
111010001: char=0x45 'ウ'
11111: char=0x83
111010010: char=0x46 'ェ'
0000: char=0x83
01100011: char=0x8b 'ル'
010111: char=0x82
100110001: char=0xf0 'を'
0001111: char=0x8e
010111100: char=0x78 '支'
0011111: char=0x8e
101111101: char=0x9d '持'
111101: char=0x82
101101001: char=0xb5 'し'
10100110: len=5, disp=48 (000110000)
011100000: char=0xc4
111001110: len=10, disp=2306 (100100000010)
10100111: char=0x35 '5'
01110001: char=0x32 '2'
0000011: char=0x35 '5'
0001010: char=0x36 '6'
0000010: char=0x32 '2'
0000101: len=5, disp=2306 (100100000010)
0110111: char=0x93
0110010: char=0xc6 '独'
01101100: char=0x97
110000101: char=0xa7 '立'
0000011: char=0x94
01111001: char=0x68 '派'
01100110: len=4, disp=2312 (100100001000)
111111: char=0x82
10001110: char=0xcc 'の'
0000001: char=0x97
00111100: char=0x9d '理'
011110010: char=0x98
111001011: char=0x5f '論'
1111011: char=0x93
1000001: char=0x49 '的'
010100: len=3, disp=196 (0011000100)
001111100: char=0x7c '|'
111000: len=3, disp=194 (0011000010)
11111111: len=4, disp=204 (0011001100)
001111101: char=0x7d '}'
11100: char=0x83
1111011: char=0x93 'ン'
111010: len=3, disp=166 (0010100110)
00111011: char=0xb5
111101: char=0x82
00111010: char=0xc4 'て'
010101: char=0x81
000110: char=0x43 ','
101000001: char=0x91
101011000: char=0xce '対'
01000100: char=0x8d
00100101: char=0x91 '国'
1110101: char=0x89
101011100: char=0xa4 '王'
0010100: len=4, disp=232 (0011101000)
0000001: char=0x8c
01000000: char=0xf0 '交'
101100111: char=0x8f
100010000: char=0xc2 '渉'
110100: char=0x81
000111: char=0x43 ','
01110010: char=0x34 '4'
010101011: char=0x37 '7'
0010111: char=0x94
11111100: char=0x4e '年'
00100000: char=0x8f
0111101: char=0x48 '秋'
111101: char=0x82
11111110: char=0xcc 'の'
11011: char=0x83
0010001: char=0x8c 'レ'
11011: char=0x83
00111101: char=0x78 'ベ'
11100: char=0x83
1110111: char=0x89 'ラ'
110111: len=3, disp=47 (000101111)
100110001: char=0x59 'Y'
010100100: char=0x28 '('
100011101: char=0x95
10010001: char=0xbd '平'
000100: char=0x93
011110011: char=0x99 '等'
1100111: char=0x94
11110100: char=0x68 '派'
010100101: char=0x29 ')'
111001: len=3, disp=214 (0011010110)
0001011: char=0xcc
110100: char=0x81
100001011: char=0x71 '〈'
101101110: len=11, disp=171 (0010101011)
011110101: char=0x39 '9'
11101010: char=0x34 '4'
101111111: char=0x33 '3'
10100011: len=6, disp=171 (0010101011)
11011: char=0x83
100001010: char=0x70 'パ'
111111: len=3, disp=734 (01011011110)
101000110: char=0x6a 'j'
000100: char=0x93
101001100: char=0xa2 '討'
1100010: len=4, disp=133 (0010000101)
00101011: char=0x98
00101010: char=0x5f '論'
1101000: len=4, disp=179 (0010110011)
110011: char=0x81
11110010: char=0x72 '〉'
111101: char=0x82
011100001: char=0xc5 'で'
1110011: char=0x8a
010111000: char=0x88 '活'
0110100: char=0x96
101001001: char=0xf4 '躍'
111111: len=3, disp=163 (0010100011)
11010111: char=0xbd
110011: char=0x81
11010001: char=0x42 '。'
0000011: char=0x34 '4'
0011011: char=0x36 '6'
1110000: char=0x94
0001100: char=0x4e '年'
100111101: len=13, disp=253 (0011111101)
1100001: char=0xcc
1011100: char=0x96
101010000: char=0xba '娘'
11011: char=0x83
01100111: char=0x75 'ブ'
111110: len=3, disp=710 (01011000110)
010010111: char=0x57 'W'
111110: len=3, disp=668 (01010011100)
00010000: char=0x67 'g'
11010011: len=6, disp=308 (0100110100)
1011101: char=0x8c
11010111: char=0x8b '結'
11010111: char=0x8d
010011101: char=0xa5 '婚'
10100: len=3, disp=41 (000101001)
011110100: char=0x38 '8'
1110110: char=0x94
1011001: char=0x4e '年'
00001111: char=0x95
010100001: char=0xe9 '暮'
111011: char=0x82
011100011: char=0xea 'れ'
111011: char=0x82
011000111: char=0xa9 'か'
111011: char=0x82
001011110: char=0xe7 'ら'
10010: char=0x82
1100011: char=0xcc 'の'
1110011: len=4, disp=217 (0011011001)
11110100: char=0x8d
100011101: char=0xd9 '裁'
1111001: char=0x94
010111001: char=0xbb '判'
10011: char=0x82
0101101: char=0xc9 'に'
1110101: len=4, disp=5 (000000101)
1110011: char=0x8a
010100011: char=0xaf '官'
11110110: len=6, disp=243 (0011110011)
100010: len=4, disp=165 (0010100101)
11010101: char=0x8f
01011110: char=0x6f '出'
0110101: char=0x90
011110100: char=0xc8 '席'
10011: char=0x82
11001000: char=0xb5 'し'
110111: char=0x81
000111: char=0x43 ','
10011: char=0x82
111010000: char=0xbb 'そ'
10101: char=0x82
1110001: char=0xcc 'の'
1001101: char=0x8e
01000011: char=0x80 '死'
1100000: char=0x8c
00010101: char=0x59 '刑'
011111: char=0x94
10110011: char=0xbb '判'
1101100: char=0x8c
111111110: char=0x88 '決'
11100101: char=0x8f
11000111: char=0x91 '書'
10101: char=0x82
1010011: char=0xc9 'に'
0111101: char=0x8f
1001010: char=0x90 '署'
1100010: char=0x96
1111010010: char=0xbc '名'
1001011: len=6, disp=179 (0010110011)
0010110: char=0x97
10100: char=0x82 '翌'
111101101: len=8, disp=179 (0010110011)
0011001: len=5, disp=772 (01100000100)
011011010: len=7, disp=183 (0010110111)
1000010: len=5, disp=908 (01110001100)
11110101: char=0x8b
11001: char=0x83 '泣'
1101011: char=0x89
11001: char=0x83 '宴'
011101: char=0x93
11010: char=0x83 '塔'
0000110: char=0x68 'h'
1010101: char=0x90
000011010: char=0xaa '征'
10111011: char=0x95
1111001110: char=0x9e '服'
10100: char=0x82
1010111: char=0xc9 'に'
100000: char=0x93
111001001: char=0xaf '同'
100110: char=0x93
000100011: char=0xb9 '道'
100000: len=4, disp=137 (0010001001)
11011101: char=0x91
1111100100: char=0xe3 '代'
1000011: char=0x97
11000001: char=0x9d '理'
1010100: len=6, disp=659 (01010010011)
1101111: char=0x8c
11100000: char=0xbb '現'
100100: len=4, disp=161 (0010100001)
001111000: char=0x92
10110011: char=0x6e '地'
01101: len=3, disp=762 (01011111010)
111011010: char=0x63 'c'
10111: char=0x82
1111101000: char=0xe8 'り'
11011001: char=0x95
001100111: char=0x61 '病'
1100000: char=0x96
01010001: char=0x76 '没'
1100001: len=6, disp=145 (0010010001)
1111010001: len=26, disp=2604 (101000101100)
00110001: len=10, disp=659 (01010010011)
00011111: char=0x41 'A'
01101: len=3, disp=1046 (10000010110)
111100010: char=0x38 '8'
00001000: char=0x39 '9'
1000010: char=0x34 '4'
1101111110: char=0x22 '"'
10110001: char=0x3e '>'
0111101: char=0x8d
01010110: char=0xa1 '今'
10100000: char=0x88
1101111001: char=0xe4 '井'
10110000: char=0x20 ' '
1000001: char=0x8d
000101011: char=0x47 '宏'
100100: len=4, disp=2696 (101010001000)
101011: len=4, disp=803 (01100100011)
110111000: len=7, disp=2600 (101000101000)
現状のプログラムです。あとはハフマン圧縮の伸長結果
がLZSS圧縮を伸長するときの入力としてつじつまが合っ
ているかどうかかな。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#ifdef __TURBOC__
/* Turbo C++, Borland C++ */
#include <io.h>
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
typedef unsigned char uchar;
typedef unsigned long ulong;
#define TRUE 1
#define FALSE 0
int hufInitTree(void);
void hufPrintNode(int);
int hufDecode(int, int);
void hufDumpTree(void);
long itemOpen(long);
long itemGetBit(int);
int itemClose(void);
int main(int, char **);
uchar *
sj2euc(int c1, int c2)
{
static uchar buf[3];
if (c1 > 0x9f)
c1 -= 0x40;
c1 += c1;
if (c2 <= 0x9e) {
c1 -= 0xe1;
if (c2 >= 0x80)
c2 -= 1;
c2 -= 0x1f;
} else {
c1 -= 0xe0;
c2 -= 0x7e;
}
buf[0] = c1 | 0x80;
buf[1] = c2 | 0x80;
buf[2] = '\0';
return buf;
}
/*------------------- ハフマン符号の伸張処理 ----------------------*
/*
* ハフマン木のノード用構造体
*/
typedef struct {
int parent; /* 親ノードのインデックス */
int child[2]; /* 左右の子ノードへのインデックス */
long weight; /* 重み(初期値1) */
int order; /* ノード順序(下から上、左から右) */
uchar type; /* 葉ノードの値のタイプ */
uchar val; /* 葉ノードの値 */
uchar changed; /* 初期状態から変更された */
} HUFNODE;
int huf_onode[HUF_NUM_NODES+1]; /* 各順序位置のノードインデックス */
/*
* ハフマン木を初期化する
*/
int
hufInitTree(void)
{
int i, top, depth, order;
HUFINIT *ip;
/*
* ルートノードを作る
*/
top = HUF_NUM_ROOT;
huf_node[top].parent = -1;
huf_node[top].child[0] = -1;
huf_node[top].child[1] = -1;
huf_node[top].weight = 0L;
huf_node[top].order = 0;
huf_node[top].type = HUF_TYPE_NONE;
huf_node[top].changed = FALSE;
top++;
ip = huf_init;
for (i = 0; i < sizeof(huf_init) / sizeof(huf_init[0]); i++) {
uchar type, val;
long code;
type = ip->type;
val = ip->startval;
for (code = ip->startcode; code <= ip->endcode; code++) {
int n, dir;
long mask;
/*
* 個々の初期化データについて...
*/
depth = 0;
n = HUF_NUM_ROOT;
for (mask = 1 << (ip->codelen - 1); mask != 0; mask >>= 1) {
/*
* 上位ビットからノードをたどる
*/
depth++;
dir = (code & mask) != 0;
if (huf_node[n].child[dir] == -1) {
/*
* 新規ノードを追加
*/
huf_node[n].child[dir] = top;
huf_node[top].parent = n;
huf_node[top].child[0] = -1;
huf_node[top].child[1] = -1;
huf_node[top].weight = 0L;
huf_node[top].order = -depth; /* 順序判定用 */
huf_node[top].type = HUF_TYPE_NONE;
huf_node[top].changed = FALSE;
top++;
}
huf_node[n].weight++;
n = huf_node[n].child[dir];
}
/*
* 葉ノードにデータを設定
*/
huf_node[n].weight = 1L;
huf_node[n].type = type;
huf_node[n].val = val++;
}
ip++;
}
/*
* 深いノードから順に、左から右に順番をつける(FGK)
*/
order = 1;
while (depth >= 0) {
for (i = HUF_NUM_ROOT; i < top; i++) {
if (huf_node[i].order == -depth) {
huf_node[i].order = order;
huf_onode[order] = i;
order++;
}
}
depth--;
}
huf_nodenum = top;
return huf_nodenum;
}
/*
* ノードの情報を表示する
*/
void
hufPrintNode(int num)
{
#define HUF_NUM_MAXLEVEL 32
int n;
uchar *p, buf[HUF_NUM_MAXLEVEL];
p = &buf[HUF_NUM_MAXLEVEL - 1];
*p = '\0';
for (n = num; n != HUF_NUM_ROOT; n = huf_node[n].parent)
*--p = (n == huf_node[huf_node[n].parent].child[0])? '0': '1';
printf("%s: weight=%ld", p, huf_node[num].weight);
printf(", order=%d", huf_node[num].order);
switch (huf_node[num].type) {
case HUF_TYPE_NONE:
printf(", (intermediate)");
break;
case HUF_TYPE_CHAR:
printf(", ch=0x%02x", (int)huf_node[num].val);
break;
case HUF_TYPE_LEN:
printf(", len=%d", (int)huf_node[num].val);
break;
}
if (huf_node[num].changed)
printf(" *");
printf("\n");
}
void
hufChangeStatus(int num)
{
huf_node[num].changed = TRUE;
if (huf_node[num].child[0] != -1)
hufChangeStatus(huf_node[num].child[0]);
if (huf_node[num].child[1] != -1)
hufChangeStatus(huf_node[num].child[1]);
}
char *
bstr(ulong n, int len)
{
ulong i;
char *p;
static char buf[33];
p = buf;
for (i = 1L << (len - 1); i > 0L; i >>= 1)
*p++ = (n & i)? '1': '0';
*p = '\0';
return buf;
}
/*
* 作業中...
*/
int
hufDecode(int verbose, int dodump)
{
int i, bit, cur, ch, lastch;
lastch = '\0';
for (;;) {
printf("output: ");
cur = HUF_NUM_ROOT;
while (huf_node[cur].type == HUF_TYPE_NONE) {
if ((bit = (int)itemGetBit(1)) < 0) {
printf("\n");
return 0;
}
printf("%c", bit + '0');
cur = huf_node[cur].child[bit];
}
printf(": ");
if (huf_node[cur].type == HUF_TYPE_CHAR) {
ch = (int)huf_node[cur].val;
printf("char=0x%02x", ch);
if (lastch != '\0') {
if (ch >= 0x40 && ch != 0x7f && ch <= 0xfc) {
#ifdef UNIX
printf(" '%s'", sj2euc(lastch, ch));
#else
printf(" '%c%c'", lastch, ch);
#endif
}
lastch = '\0';
} else if (ch >= 0x20 && ch <= 0x7f) {
printf(" '%c'", ch);
lastch = '\0';
} else if (ch >= 0x81 && ch <= 0x9f || ch >= 0xe0 && ch <= 0xef) {
lastch = ch;
} else {
lastch = '\0';
}
} else {
int rest, len = (int)huf_node[cur].val;
ulong disp = itemGetBit(4);
if (disp <= 1) /* 000x */
rest = 5;
else if (disp <= 4) /* 001x, 0100 */
rest = 6;
else if (disp <= 8) /* 01xx, 1000 */
rest = 7;
else if (disp <= 11) /* 10xx */
rest = 8;
else if (disp <= 14) /* 110x */
rest = 9;
else /* 111x */
rest = 10;
disp = (disp << rest) + (int)itemGetBit(rest);
printf("len=%d, disp=%ld (%s)", len, disp, bstr(disp, 4+rest));
}
printf("\n");
/*
* FGK法によるハフマン木の組み替え
* 葉ノードからルートノードに向かって処理
*/
while (cur != HUF_NUM_ROOT) {
int target, maxorder, tmp;
long curweight;
/*
* 交換先として、同じ重みをもつノードのうち
* 順序番号が最大のものを得る
*/
target = cur;
curweight = huf_node[cur].weight;
maxorder = huf_node[cur].order;
for (i = 0; i < huf_nodenum; i++) {
if (huf_node[i].weight == curweight &&
huf_node[i].order > maxorder) {
target = i;
maxorder = huf_node[target].order;
}
}
if (target != cur) {
int curpar, targetpar;
/*
* 現在のノードと交換先のノードを交換する
* (親子リンクの貼り替えと順序番号の交換)
*/
if (verbose) {
printf("swap: current: ");
hufPrintNode(cur);
printf(" target: ");
hufPrintNode(target);
}
targetpar = huf_node[target].parent;
curpar = huf_node[cur].parent;
if (huf_node[targetpar].child[0] == target)
huf_node[targetpar].child[0] = cur;
else if (huf_node[targetpar].child[1] == target)
huf_node[targetpar].child[1] = cur;
else
fprintf(stderr, "Internal error in hufDecode()\n");
if (huf_node[curpar].child[0] == cur)
huf_node[curpar].child[0] = target;
else if (huf_node[curpar].child[1] == cur)
huf_node[curpar].child[1] = target;
else
fprintf(stderr, "Internal error in hufDecode()\n");
huf_node[target].parent = curpar;
huf_node[cur].parent = targetpar;
tmp = huf_node[target].order;
huf_node[target].order = huf_node[cur].order;
huf_node[cur].order = tmp;
tmp = huf_onode[huf_node[target].order];
huf_onode[huf_node[target].order] =
huf_onode[huf_node[cur].order];
huf_onode[huf_node[cur].order] = tmp;
hufChangeStatus(huf_onode[huf_node[target].order]);
hufChangeStatus(huf_onode[huf_node[cur].order]);
}
huf_node[cur].weight++;
cur = huf_node[cur].parent;
}
huf_node[cur].weight++;
if (dodump)
hufDumpTree();
}
}
void
hufDumpTree(void)
{
int i;
for (i = 1; i <= huf_nodenum; i++)
hufPrintNode(huf_onode[i]);
}
/*----------- 世界大百科事典の項目データファイルの処理 ------------*/
/*--------- メイン ---------*/
void
usage(void)
{
fprintf(stderr, "decode [-v] [-d] [-n] itemno\n");
fprintf(stderr, " -v: verbose\n");
fprintf(stderr, " -d: dump tree each time\n");
fprintf(stderr, " -n: dump init tree and exit\n");
exit(1);
}
int
main(int ac, char **av)
{
int i, verbose, dodump, dumponly;
char *s;
long itemno;
verbose = FALSE;
dodump = FALSE;
dumponly = FALSE;
ac--, av++;
while (ac > 0 && **av == '-') {
for (s = *av + 1; *s; s++) {
switch (*s) {
case 'v':
verbose = TRUE;
break;
case 'd':
dodump = TRUE;
break;
case 'n':
dumponly = TRUE;
break;
default:
usage();
}
}
ac--, av++;
}
if (dumponly) {
if (hufInitTree() < 0) {
fprintf(stderr, "hufInitTree() failed\n");
exit(1);
}
hufDumpTree();
exit(0);
}
if (ac <= 0)
usage();
itemno = strtol(*av, NULL, 10);
if (itemno < 0L) {
fprintf(stderr, "Invalid itemno: %ld\n", itemno);
exit(1);
}
printf("itemno=%ld\n", itemno);
if (hufInitTree() < 0) {
fprintf(stderr, "hufInitTree() failed\n");
exit(1);
}
if (dodump)
hufDumpTree();
if (itemOpen(itemno) < 0) {
fprintf(stderr, "itemOpen() failed\n");
exit(1);
}
hufDecode(verbose, dodump);
itemClose();
exit(0);
いちばん長い項目04103「イギリス」だとまだ途中から
化けちゃうし...。(>_<;
参照開始位置も一筋縄ではいかないみたいです。
参照開始位置は先頭6ビットのパターンによって9~15ビ
ットの可変長データで示されているようです。とはいえ、
これでもまだ洩れがあるかもしれません。
先頭6ビット 全体の長さ
000000~000111 9ビット
001000~010011 10ビット
010100~100011 11ビット
100100~101111 12ビット
110000~111011 13ビット
111100~111110 14ビット
111111 15ビット
参照開始位置が0なら1文字前からのコピー、nならn+1文
字前からのコピーになります。
また、参照開始位置は実際にコピーを始める位置と一定
のずれかたをしているようです。たとえば「0010001011」
が表す数値は139ですが、下に示す(f)のパターンになり、
実際のコピーは139-64+1=76文字前からになります。
しかし、ほとんど同じようなビットパターンでもずれが
-0の場合と-384の場合があったりして、うまく特定でき
ないことがあります。
参照開始位置のパターン 実際の参照開始位置とのずれ
[a] 00011xxx xxxxxxxx -4224
[b] 00010xxx xxxxxxxx -0
[c] 00001xxx xxxxxxxx -1152
[d] 000001xx xxxxxxxx -0(-384のこともある)
[e] 0000001x xxxxxxxx -0(-384のこともある)
[f] 00000001 xxxxxxxx -64
00000000 1xxxxxxx -64
[g] 00000000 01xxxxxx -0
[h] 00000000 001xxxxx -0
[i] 00000000 000xxxxx -0
可変長で表現されていることからハフマン木かなとも思
うのですが、同じ数値が出てくるときは毎回同じビット
パターンなので、少なくとも適応型ハフマン圧縮されて
いることはないはずです。どういうしくみになっている
のか、ちょっと行き詰まっています。
# えーん。(>_<;
●項目00007「アイアトン」の伸張結果
itemno=7
10011011: len=18, disp=995(01111100011[e])->995 '<TOC></TOC><TITLE>'
00001111: char=0x83
111001101: char=0x41 'ア'
11000100: char=0x83
111001111: char=0x43 'イ'
10001100: len=3, disp=3(000000011[i])->3 'ア'
111110011: char=0x67 'ト'
1011111: char=0x83
00011111: char=0x93 'ン'
10010010: len=9, disp=1003(01111101011[e])->1003 '</TITLE><'
10010001: len=8, disp=964(01111000100[e])->964 'EUTITLE>'
111010100: char=0x48 'H'
111110001: char=0x65 'e'
111111010: char=0x6e 'n'
111111110: char=0x72 'r'
00000101: char=0x79 'y'
110101100: char=0x20 ' '
111010101: char=0x49 'I'
10110111: char=0x72 'r'
10111001: char=0x65 'e'
00000000: char=0x74 't'
111111011: char=0x6f 'o'
10111000: char=0x6e 'n'
10010101: len=12, disp=986(01111011010[e])->986 '</EUTITLE><B'
10110100: char=0x49 'I'
111011110: char=0x52 'R'
111100000: char=0x54 'T'
10111010: char=0x48 'H'
111001010: char=0x3e '>'
110111101: char=0x31 '1'
111000010: char=0x36 '6'
10101101: char=0x31 '1'
1010000: char=0x31 '1'
00001101: char=0x81
111101001: char=0x5d '‐'
111000001: char=0x35 '5'
1010101: char=0x31 '1'
11000001: len=3, disp=867(01101100011[e])->867 '</B'
10001110: len=5, disp=15(000001111[i])->15 'IRTH>'
10001111: len=6, disp=1009(01111110001[e])->1009 '<BODY>'
1001101: len=3, disp=139(0010001011[f])->75 'イ'
111011001: char=0x4d 'ギ'
1011111: char=0x83
00010110: char=0x8a 'リ'
100100: char=0x83
111100100: char=0x58 'ス'
10101001: char=0x81
11000010: char=0x43 ','
100101: char=0x83
111111111: char=0x73 'ピ'
100111: char=0x83
00010001: char=0x85 'ュ'
1001000: char=0x81
111100111: char=0x5b 'ー'
1010010: len=3, disp=11(000001011[i])->11 'リ'
111101010: char=0x5e 'タ'
010111: len=3, disp=45(000101101[h])->45 'ー'
111110100: char=0x68 'ド'
00000011: len=4, disp=47(000101111[h])->47 '<CR>'
001011: char=0x82
0101100: char=0xc6 'と'
010101: len=3, disp=1(000000001[i])->1 'と'
01101101: char=0xe0 'も'
001011: char=0x82
01110100: char=0xc9 'に'
00010111: char=0x8b
111101111: char=0x63 '議'
0010111: char=0x89
101110011: char=0xef '会'
10001101: char=0x8c
0111111: char=0x52 '軍'
010100: char=0x82
0010011: char=0xc9 'に'
10000111: char=0x8e
111011101: char=0x51 '参'
0110000: char=0x89
011011011: char=0xc1 '加'
010011: char=0x81
10000001: char=0x42 '。'
111011011: char=0x4f 'O'
110111010: char=0x2e '.'
10110101: char=0x20 ' '
010010: len=3, disp=134(0010000110[f])->70 'ク'
100110001: char=0x8d 'ロ'
01001: char=0x83
100111100: char=0x80 'ム'
01001: char=0x83
111010001: char=0x45 'ウ'
11111: char=0x83
111010010: char=0x46 'ェ'
0000: char=0x83
01100011: char=0x8b 'ル'
010111: char=0x82
100110001: char=0xf0 'を'
0001111: char=0x8e
010111100: char=0x78 '支'
0011111: char=0x8e
101111101: char=0x9d '持'
111101: char=0x82
101101001: char=0xb5 'し'
10100110: len=5, disp=48(000110000[h])->48 '<CR>'
011100000: char=0xc4 'て'
111001110: len=10, disp=2306(100100000010[c])->1154 '<A REFID="'
10100111: char=0x35 '5'
01110001: char=0x32 '2'
0000011: char=0x35 '5'
0001010: char=0x36 '6'
0000010: char=0x32 '2'
0000101: len=5, disp=2306(100100000010[c])->1154 '000">'
0110111: char=0x93
0110010: char=0xc6 '独'
01101100: char=0x97
110000101: char=0xa7 '立'
0000011: char=0x94
01111001: char=0x68 '派'
01100110: len=4, disp=2312(100100001000[c])->1160 '</A>'
111111: char=0x82
10001110: char=0xcc 'の'
0000001: char=0x97
00111100: char=0x9d '理'
011110010: char=0x98
111001011: char=0x5f '論'
1111011: char=0x93
1000001: char=0x49 '的'
010100: len=3, disp=196(0011000100[f])->132 'ス'
001111100: char=0x7c 'ポ'
111000: len=3, disp=194(0011000010[f])->130 'ー'
11111111: len=4, disp=204(0011001100[f])->140 'クス'
001111101: char=0x7d 'マ'
11100: char=0x83
1111011: char=0x93 'ン'
111010: len=3, disp=166(0010100110[f])->102 'と'
00111011: char=0xb5 'し'
111101: char=0x82
00111010: char=0xc4 'て'
010101: char=0x81
000110: char=0x43 ','
101000001: char=0x91
101011000: char=0xce '対'
01000100: char=0x8d
00100101: char=0x91 '国'
1110101: char=0x89
101011100: char=0xa4 '王'
0010100: len=4, disp=232(0011101000[f])->168 '<CR>'
0000001: char=0x8c
01000000: char=0xf0 '交'
101100111: char=0x8f
100010000: char=0xc2 '渉'
110100: char=0x81
000111: char=0x43 ','
01110010: char=0x34 '4'
010101011: char=0x37 '7'
0010111: char=0x94
11111100: char=0x4e '年'
00100000: char=0x8f
0111101: char=0x48 '秋'
111101: char=0x82
11111110: char=0xcc 'の'
11011: char=0x83
0010001: char=0x8c 'レ'
11011: char=0x83
00111101: char=0x78 'ベ'
11100: char=0x83
1110111: char=0x89 'ラ'
110111: len=3, disp=47(000101111[h])->47 'ー'
100110001: char=0x59 'ズ'
010100100: char=0x28 '('
100011101: char=0x95
10010001: char=0xbd '平'
000100: char=0x93
011110011: char=0x99 '等'
1100111: char=0x94
11110100: char=0x68 '派'
010100101: char=0x29 ')'
111001: len=3, disp=214(0011010110[f])->150 'と'
0001011: char=0xcc 'の'
110100: char=0x81
100001011: char=0x71 '〈'
101101110: len=11, disp=171(0010101011[f])->107 '<A REFID="5'
011110101: char=0x39 '9'
11101010: char=0x34 '4'
101111111: char=0x33 '3'
10100011: len=6, disp=171(0010101011[f])->107 '2000">'
11011: char=0x83
100001010: char=0x70 'パ'
111111: len=3, disp=734(01011011110[e])->734 'NAM' ※-384が必要
101000110: char=0x6a 'j'
000100: char=0x93
101001100: char=0xa2 '討'
1100010: len=4, disp=133(0010000101[f])->69 '<CR>'
00101011: char=0x98
00101010: char=0x5f '論'
1101000: len=4, disp=179(0010110011[f])->115 '</A>'
110011: char=0x81
11110010: char=0x72 '〉'
111101: char=0x82
011100001: char=0xc5 'で'
1110011: char=0x8a
010111000: char=0x88 '活'
0110100: char=0x96
101001001: char=0xf4 '躍'
111111: len=3, disp=163(0010100011[f])->99 'し'
11010111: char=0xbd 'た'
110011: char=0x81
11010001: char=0x42 '。'
0000011: char=0x34 '4'
0011011: char=0x36 '6'
1110000: char=0x94
0001100: char=0x4e '年'
100111101: len=13, disp=253(0011111101[f])->189 'クロムウェル'
1100001: char=0xcc 'の'
1011100: char=0x96
101010000: char=0xba '娘'
11011: char=0x83
01100111: char=0x75 'ブ'
111110: len=3, disp=710(01011000110[e])->710 '<CR' ※-384が必要
010010111: char=0x57 'W'
111110: len=3, disp=668(01010011100[e])->668 'D><' ※-384が必要
00010000: char=0x67 'g'
11010011: len=6, disp=308(0100110100[f])->244 '<CR>と'
1011101: char=0x8c
11010111: char=0x8b '結'
11010111: char=0x8d
010011101: char=0xa5 '婚'
10100: len=3, disp=41(000101001[h])->41 '。4'
011110100: char=0x38 '8'
1110110: char=0x94
1011001: char=0x4e '年'
00001111: char=0x95
010100001: char=0xe9 '暮'
111011: char=0x82
011100011: char=0xea 'れ'
111011: char=0x82
011000111: char=0xa9 'か'
111011: char=0x82
001011110: char=0xe7 'ら'
10010: char=0x82
1100011: char=0xcc 'の'
1110011: len=4, disp=217(0011011001[f])->153 '国王'
11110100: char=0x8d
100011101: char=0xd9 '裁'
1111001: char=0x94
010111001: char=0xbb '判'
10011: char=0x82
0101101: char=0xc9 'に'
1110101: len=4, disp=5(000000101[i])->5 '裁判'
1110011: char=0x8a
010100011: char=0xaf '官'
11110110: len=6, disp=243(0011110011[f])->179 'として'
100010: len=4, disp=165(0010100101[f])->101 '<CR>'
1001011: len=6, disp=179(0010110011[f])->115 'した。'
0010110: char=0x97
10100: char=0x82 '翌'
111101101: len=8, disp=179(0010110011[f])->115 '年クロム'
0011001: len=5, disp=772(01100000100[e])->772 '/BOLD' ※-384が必要
011011010: len=7, disp=183(0010110111[f])->119 'Eェルの'
1000010: len=5, disp=908(01110001100[e])->908 'CIAL ' ※-384が必要
11110101: char=0x8b
11001: char=0x83 '泣'
1101011: char=0x89
11001: char=0x83 '宴'
011101: char=0x93
11010: char=0x83 '塔'
0000110: char=0x68 'h'
1010101: char=0x90
000011010: char=0xaa '征'
10111011: char=0x95
1111001110: char=0x9e '服'
10100: char=0x82
1010111: char=0xc9 'に'
100000: char=0x93
111001001: char=0xaf '同'
100110: char=0x93
000100011: char=0xb9 '道'
100000: len=4, disp=137(0010001001[f])->73 'し,'
11011101: char=0x91
1111100100: char=0xe3 '代'
1000011: char=0x97
11000001: char=0x9d '理'
1010100: len=6, disp=659(01010010011[e])->659 '.DTD">' ※-384が必要
1101111: char=0x8c
11100000: char=0xbb '現'
100100: len=4, disp=161(0010100001[f])->97 '<CR>'
001111000: char=0x92
10110011: char=0x6e '地'
01101: len=3, disp=762(01011111010[e])->762 'DY>' ※-384が必要
111011010: char=0x63 'c'
10111: char=0x82
1111101000: char=0xe8 'り'
11011001: char=0x95
001100111: char=0x61 '病'
1100000: char=0x96
01010001: char=0x76 '没'
1100001: len=6, disp=145(0010010001[f])->81 'した。'
1111010001: len=26, disp=2604(101000101100[c])->1452 ' '
00110001: len=10, disp=659(01010010011[e])->659 '<JPNTitle>' ※-384が必要
00011111: char=0x41 'A'
01101: len=3, disp=1046(10000010110[d])->1046 '001'
111100010: char=0x38 '8'
00001000: char=0x39 '9'
1000010: char=0x34 '4'
1101111110: char=0x22 '"'
10110001: char=0x3e '>'
0111101: char=0x8d
01010110: char=0xa1 '今'
10100000: char=0x88
1101111001: char=0xe4 '井'
10110000: char=0x20 ' '
1000001: char=0x8d
000101011: char=0x47 '宏'
100100: len=4, disp=2696(101010001000[c])->1544 '</A>'
101011: len=4, disp=803(01100100011[e])->803 '</BO' ※-384が必要
110111000: len=7, disp=2600(101000101000[c])->1448 '</BODY>'
一部の長い項目(45KB~)を除いて、ほぼ復元できるよう
になりました。LZSSの伸長はまじめにやっておらず、長
ーいウィンドウにどんどん書き足しているだけですが。
fj.comp.applications.dictionaryの記事<bp2qvk$575$1...@ns.src.ricoh.co.jp>で
私は書きました。
> 参照開始位置は先頭6ビットのパターンによって9~15ビ
> ットの可変長データで示されているようです。とはいえ、
先頭6ビットは間違いで、やはり5ビットでした。
> しかし、ほとんど同じようなビットパターンでもずれが
> -0の場合と-384の場合があったりして、うまく特定でき
> ないことがあります。
これはウィンドウの初期化データ開始位置をウィンドウ
の先頭ではなく384バイト後ろにずらしたらつじつまが
合うようになりました。
長い項目で化けるのは、ルートノードの重みが32768に
なったあたりでおかしくなるようです。藤井さん、何か
思い当たることはありませんか? そちらで追試してみて
いただけるとありがたいのですが...。化ける項目はお
そらく以下のものだけです。
02157: size=66927
02529: size=70657
04103: size=78587
19919: size=55074
34642: size=64675
43381: size=74978
47597: size=69058
48166: size=49761
52667: size=45771
61882: size=45750
65466: size=48972
66276: size=65511
79540: size=51117
83086: size=55933
以下、現状のプログラムです。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#ifdef __TURBOC__
/* Turbo C++, Borland C++ */
#include <io.h>
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
typedef unsigned char uchar;
typedef unsigned long ulong;
#define TRUE 1
#define FALSE 0
int hufInitTree(void);
void hufPrintNode(int);
int hufDecode(long, int, int);
void hufDumpTree(void);
int lzDecode(long, int, int);
long itemOpen(long);
long itemGetBit(int);
int itemClose(void);
int main(int, char **);
uchar *
sj2euc(int c1, int c2)
{
static uchar buf[3];
if (c1 > 0x9f)
c1 -= 0x40;
c1 += c1;
if (c2 <= 0x9e) {
c1 -= 0xe1;
if (c2 >= 0x80)
c2 -= 1;
c2 -= 0x1f;
} else {
c1 -= 0xe0;
c2 -= 0x7e;
}
buf[0] = c1 | 0x80;
buf[1] = c2 | 0x80;
buf[2] = '\0';
return buf;
}
char *
bstr(ulong n, int len)
{
ulong i;
char *p;
static char buf[33];
p = buf;
for (i = 1L << (len - 1); i > 0L; i >>= 1)
*p++ = (n & i)? '1': '0';
*p = '\0';
return buf;
}
/*------------------- ハフマン符号の伸張処理 ----------------------*/
#define LZ_NUM_COPYOFF 996
#define LZ_NUM_INITOFF 384
#define LZ_NUM_WINSIZE 240000L /* 最大の項目が入る大きさ */
static uchar lz_window[LZ_NUM_WINSIZE];
static uchar lz_initstr[] =
"<TOC></TOC><TITLE>()</TITLE><YOMI1></YOMI1><BODY></YOMI1>"
"<EUTITLE></EUTITLE><BODY>\r\n\x81\xcb<A REFID=\"00000000\"></A>\\n"
"\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40"
"\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40"
"\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40"
"\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40\x81\x40"
"\x81\x40\x81\x40\r\n)(\x81\x6a\x81\x69\x81\x6c\x81\x6b"
"\x81\x6e\x81\x6d\x81\x70\x81\x6f\x81\x72\x81\x71\x81\x74"
"\x81\x73\x81\x76\x81\x75\x81\x78\x81\x77\r\n</BODY>\r\n<TOC>"
"<Z1:0001:>\x81\x79\x81\x7a</Z1><Z2:0001:>\x81\x79\x81\x7a</Z2>"
"<Z3:0002:>\x81\x79\x81\x7a</Z3><Z4:0002:>\x81\x79\x81\x7a</Z4>"
"<Z5:0003:>\x81\x79\x81\x7a</Z5><Z6:0003:>\x81\x79\x81\x7a</Z6>"
"<Z7:0004:>\x81\x79\x81\x7a</Z7><Z8:0004:>\x81\x79\x81\x7a</Z8>"
"<Z9:0005:>\x81\x79\x81\x7a</Z9><Z10:0005:>\x81\x79\x81\x7a</Z10>"
"<Z11:0006:>\x81\x79\x81\x7a</Z11><Z12:0006:>\x81\x79\x81\x7a</Z12>"
"<Z13:0007:>\x81\x79\x81\x7a</Z13><Z14:0007:>\x81\x79\x81\x7a</Z14>"
"<Z15:0008:>\x81\x79\x81\x7a</Z15><Z16:0008:>\x81\x79\x81\x7a</Z16>"
"<Z17:0009:>\x81\x79\x81\x7a</Z17><Z18:0010:>\x81\x79\x81\x7a</Z18>"
"<Z19:0010:>\x81\x79\x81\x7a</Z19><Z20:0011:>\x81\x79\r\n<RUBI>"
"<SPECIAL FNAME=\"HDH\x83\x53\x83\x56\x83\x62\x83\x4e\"> </SPECIAL> "
"<SPECIAL FNAME=\"HDH\x83\x53\x83\x56\x83\x62\x83\x4e\"><RUBI>\r\n"
"\x81\x43<CR>\x81\x42<CR>\x81\x60<CR>"
"<SBREAK L=2><Z1:0001><BOLD>\x81\x79\x81\x7a</BOLD></Z1>\\n<CR>"
"<SBREAK L=2><Z1:0001:><BOLD>\x81\x6d\x81\x6e</BOLD></Z1>\r\n"
"<BODY>\x81\xcb<A REFID=\"65432100\"></A>\\n</BODY>"
"<TOC></TOC><TITLE>\r\n\x00\x00"
"<!DOCTYPE HDHCX SYSTEM \"HDHCX.DTD\">\r\n"
"<HDHCX>\r\n<HEAD>\r\n<TITLE ID=\"C0000000\"></TITLE>\r\n"
"<JPNTitle></JPNTitle>\r\n<EURTitle></EURTitle>\r\n</HEAD>\r\n"
"<PARA>\x81\x40\r\n<BODY>\r\n<CAP1>\r\n<CAP2>\r\n<CAP3>\r\n"
"<Words></Words>\r\n<Rub></Rub>\r\n\x81\x71<A></A>\x81\x72\r\n"
"<Words>\x81\x71<Index><A></A></Index>\x81\x72</Words>\r\n"
"<Gai CODE=\"\"><Work>\x81\x73\x81\x74</Work>\x82\xaa\r\n"
"<unit></unit>\r\n<SNotice><ENotice>\r\n<No>\x81\x69\x31\x81\x6a</No>\r\n"
"<No>\x81\x69\x32\x81\x6a</No>\r\n<No>\x81\x69\x33\x81\x6a</No>\r\n"
"<No>\x81\x69\x34\x81\x6a</No>\r\n<AUTHOR></AUTHOR>\r\n</BODY>\r\n"
"</HDHCX>\r\n\x00";
/*
* 作業中...
*/
int
hufDecode(long nchars, int verbose, int dodump)
{
int i, bit, cur, ch;
static int lastch = '\0';
int val, overrun;
long disp, rdisp, rdispmax;
uchar *pos, *winend, *copy, *p;
memset(lz_window, '@', sizeof(lz_window));
memcpy(lz_window + LZ_NUM_INITOFF, lz_initstr, sizeof(lz_initstr));
winend = &lz_window[LZ_NUM_WINSIZE];
pos = &lz_window[LZ_NUM_COPYOFF];
overrun = FALSE;
rdispmax = 0L;
while (nchars > 0) {
cur = HUF_NUM_ROOT;
while (huf_node[cur].type == HUF_TYPE_NONE) {
if ((bit = (int)itemGetBit(1)) < 0) {
printf("\n");
if (verbose)
printf("rdispmax = %ld\n", rdispmax);
return -1;
}
if (verbose)
printf("%c", bit + '0');
cur = huf_node[cur].child[bit];
}
if (verbose)
printf(": ");
if (huf_node[cur].type == HUF_TYPE_CHAR) {
ch = (int)huf_node[cur].val;
if (verbose)
printf("char=0x%02x '", ch);
if (lastch != '\0') {
if (ch >= 0x40 && ch != 0x7f && ch <= 0xfc) {
#ifdef UNIX
printf("%s", sj2euc(lastch, ch));
#else
printf("%c%c", lastch, ch);
#endif
} else {
printf("\\x%02x\\x%02x", lastch, ch);
}
lastch = '\0';
} else if (ch >= 0x20 && ch <= 0x7f) {
printf("%c", ch);
lastch = '\0';
} else if (ch >= 0x81 && ch <= 0x9f || ch >= 0xe0 && ch <= 0xef) {
lastch = ch;
} else {
printf("\\x%02x", ch);
lastch = '\0';
}
if (verbose)
printf("'\n");
if (pos >= winend - 2 && !overrun) {
fprintf(stderr, "window overrun\n");
overrun = TRUE;
}
nchars--;
if (!overrun)
*pos++ = (uchar)ch;
} else {
int rest, len = (int)huf_node[cur].val;
ulong disp = itemGetBit(5);
char *s;
if (verbose)
printf("len=%d, ", len);
if (disp < 4L) { /* 00000~00011 (4) */
rest = 4;
} else if (disp < 10L) { /* 00100~01001 (6) */
rest = 5;
} else if (disp < 18L) { /* 01010~10001 (8) */
rest = 6;
} else if (disp < 24L) { /* 10010~10111 (6) */
rest = 7;
} else if (disp < 30L) { /* 11000~11101 (6) */
rest = 8;
} else { /* 11110~11111 (2) */
rest = 9;
}
disp = (disp << rest) + (int)itemGetBit(rest);
/*
* (a) 001xxxxx xxxxxxxx -0x3000 (-12288)
* (b) 0001xxxx xxxxxxxx -0x1200 (-4608)
* (c) 00001xxx xxxxxxxx -0x0600 (-1536)
* (d) 000001xx xxxxxxxx -0x0180 (-384)
* 0000001x xxxxxxxx -0x0180 (-384)
* (e) 00000001 xxxxxxxx -0x0040 (-64)
* 00000000 1xxxxxxx -0x0040 (-64)
* (f) 00000000 0xxxxxxx -0x0000 (-0)
*/
if (disp & 0x2000L) {
rdisp = disp - 0x3000L;
s = "a";
} else if (disp & 0x1000L) {
rdisp = disp - 0x1200L;
s = "b";
} else if (disp & 0x0800L) {
rdisp = disp - 0x0600L;
s = "c";
} else if (disp & 0x0600L) {
rdisp = disp - 0x0180L;
s = "d";
} else if (disp & 0x0180L) {
rdisp = disp - 0x0040L;
s = "e";
} else {
rdisp = disp;
s = "f";
}
if (rdisp > rdispmax)
rdispmax = rdisp;
if (verbose)
printf("disp=%ld(%s[%s])->%ld '",
disp, bstr(disp, 6+rest), s, rdisp);
nchars -= (long)len;
if (!overrun) {
copy = pos - rdisp - 1;
while (len-- > 0) {
if (copy < lz_window) {
copy++;
*pos++ = '?';
printf("?");
} else {
if (lastch != '\0') {
if (*copy >= 0x40 && *copy != 0x7f &&
*copy <= 0xfc) {
#ifdef UNIX
printf("%s", sj2euc(lastch, *copy));
#else
printf("%c%c", lastch, *copy);
#endif
}
lastch = '\0';
} else if (*copy >= 0x20 && *copy <= 0x7f) {
printf("%c", *copy);
lastch = '\0';
} else if (*copy >= 0x81 && *copy <= 0x9f ||
*copy >= 0xe0 && *copy <= 0xef) {
lastch = *copy;
} else {
printf("\\x%02x", *copy);
lastch = '\0';
}
*pos++ = *copy++;
}
}
}
if (verbose)
printf("'\n");
}
if (verbose >= 2) {
#if 1
if (huf_node[HUF_NUM_ROOT].weight == 32768L)
printf("\nWEIGHT FULL\n");
#endif
if (dodump)
hufDumpTree();
}
if (verbose) {
if (pos > lz_window)
printf("nchars = %ld\n", pos - lz_window);
printf("rdispmax = %ld\n", rdispmax);
}
return 0;
}
void
hufDumpTree(void)
{
int i;
/*----------- 世界大百科事典の項目データファイルの処理 ------------*/
return (long)expand;
}
/*--------- メイン ---------*/
fprintf(stderr, " -v: verbose (-vv for double verbose)\n");
fprintf(stderr, " -d: dump tree each time\n");
fprintf(stderr, " -n: dump init tree and exit\n");
exit(1);
}
int
main(int ac, char **av)
{
int i, verbose, dodump, dumponly;
char *s;
long itemno;
ulong expand;
verbose = 0;
dodump = FALSE;
dumponly = FALSE;
ac--, av++;
while (ac > 0 && **av == '-') {
for (s = *av + 1; *s; s++) {
switch (*s) {
case 'v':
verbose++;
break;
case 'd':
dodump = TRUE;
break;
case 'n':
dumponly = TRUE;
break;
default:
usage();
}
}
ac--, av++;
}
if (dumponly) {
if (hufInitTree() < 0) {
fprintf(stderr, "hufInitTree() failed\n");
exit(1);
}
hufDumpTree();
exit(0);
}
if (ac <= 0)
usage();
itemno = strtol(*av, NULL, 10);
if (itemno < 0L) {
fprintf(stderr, "Invalid itemno: %ld\n", itemno);
exit(1);
}
if (verbose)
printf("itemno=%ld\n", itemno);
if (hufInitTree() < 0) {
fprintf(stderr, "hufInitTree() failed\n");
exit(1);
}
if (dodump)
hufDumpTree();
if ((expand = itemOpen(itemno)) < 0L) {
fprintf(stderr, "itemOpen() failed\n");
exit(1);
}
hufDecode(expand, verbose, dodump);
itemClose();
exit(0);
> 以下、現状のプログラムです。
すごいです。すごすぎる。
> # 藤井さん、ヘルプー。(^^;
すみません、私の力量ではお役には立てそうにありません。
> 長い項目で化けるのは、ルートノードの重みが32768に
> なったあたりでおかしくなるようです。藤井さん、何か
> 思い当たることはありませんか?
私が思いついたのは、
(1) 効率の悪い適応型ハフマンから静的ハフマンへの移行
(2) ハフマン木の初期化
(3) オーバフロー対策で重みの減衰
この化けっぷりからすると、(3) かなー、という気がしました。
各葉っぱの頻度を半分にして、ハフマン木の再構築。
太田さんはどのように推測されましたか?
8万項目のなかのたったの14項目、
この感激を前に、今はどうでもいいやって気もしているのですが。
WEIGHT FULL が出たら、リターンするとか。
あはは。圧縮方式については私の想像はほとんど外れて
ましたし、藤井さんの助けがなかったらここまで来てな
かったんですけどね。
> すみません、私の力量ではお役には立てそうにありません。
了解。もうしばらく考えてみます。
> 私が思いついたのは、
> (1) 効率の悪い適応型ハフマンから静的ハフマンへの移行
> (2) ハフマン木の初期化
> (3) オーバフロー対策で重みの減衰
ふむ。(3)は考えつきませんでした。
> 太田さんはどのように推測されましたか?
ルートノードの重みが32768(あるいは32767)に達したら
(1)以後ハフマン木を更新しない、(2)ハフマン木をいっ
たん初期状態に戻すというのはすでに試してみたのです
が、どちらもだめでした。
> この化けっぷりからすると、(3) かなー、という気がしました。
> 各葉っぱの頻度を半分にして、ハフマン木の再構築。
頻度を単純に半分にできるなら葉っぱも中間ノードも同
じ比率で半分になるわけですが、頻度が1のノードは0に
はできないし、順序がかわる余地はあるのですね。でも
ハフマン木の再構築はけっこうめんどうかも。どうやっ
て実現すればいいのかちょっと考えてみます。
そのほかにも、この周辺でまだ試してみることがいくつ
かありそうですね。
> 8万項目のなかのたったの14項目、
> この感激を前に、今はどうでもいいやって気もしているのですが。
> WEIGHT FULL が出たら、リターンするとか。
うーむ。(^^;
難あり、ジャンク扱いってことで、使いたい人は現状の
プログラムをそのまま持ってってください。完成したら
世界大百科事典のすべての項目データをテキスト化する
プログラムとしてcsrdと同じnearly public domainで公
開するつもりですが。FreePWING化はおそらくどなたか
にお願いすることになると思います。
ビンゴー!!
何といったらいいのか、藤井さんの予測がことごとく当
たりですね。鳥肌立ちました。
というわけで、おそらくすべての項目が伸長できるよう
になりました。まだバグがあるかもしれませんが、きれ
いに書き直したプログラムをつけておきます。LZSSのウ
ィンドウサイズは4096でした。そのうちドキュメントを
つけてどこかに置いてもらうつもりです。
カレントディレクトリにitemloc.datとitem.datを置い
た状態で実行すると、1項目1行で標準出力に伸長された
項目データを書き出します。項目番号を指定するとその
項目だけ、何も指定しないと全項目を出力します。
/*
* 平凡社世界大百科事典項目データテキスト化ユーティリティ - cx2text
* Written by Junn Ohta (oh...@sdg.mdd.ricoh.co.jp), Public Domain.
* Helped by Hironori Fujii (fu...@chi.its.hiroshima-cu.ac.jp)
*/
char *prog = "cx2text";
char *version = "0.1";
char *date = "2003/11/18";
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#ifdef __TURBOC__
/* Turbo C++, Borland C++ */
#include <io.h>
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
typedef unsigned char uchar;
typedef unsigned long ulong;
#define TRUE 1
#define FALSE 0
uchar *sj2euc(int, int);
char *bstr(ulong, int);
int hufInitTree(void);
long hufReduceWeight(int, int);
int hufSetDepth(int, int);
void hufReconstructTree(void);
#ifndef TEST
int hufDecode(long);
#endif
#ifdef TEST
int hufDecode(long, int, int);
void hufPrintNode(int);
void hufChangeStatus(int);
void hufDumpTree(void);
#endif
int itemOpen(void);
long itemSelect(long);
long itemGetBit(int);
int itemClose(void);
int main(int, char **);
/*------------------- ユーティリティ関数 ----------------------*/
/*
* シフトJISの第1、第2バイトから日本語EUC文字列を作って返す
*/
uchar *
sj2euc(int c1, int c2)
{
static uchar buf[3];
if (c1 > 0x9f)
c1 -= 0x40;
c1 += c1;
if (c2 <= 0x9e) {
c1 -= 0xe1;
if (c2 >= 0x80)
c2 -= 1;
c2 -= 0x1f;
} else {
c1 -= 0xe0;
c2 -= 0x7e;
}
buf[0] = c1 | 0x80;
buf[1] = c2 | 0x80;
buf[2] = '\0';
return buf;
}
/*
* lenビットの数値nから2進文字列を作って返す
*/
char *
bstr(ulong n, int len)
{
ulong i;
char *p;
static char buf[33];
p = buf;
for (i = 1L << (len - 1); i > 0L; i >>= 1)
*p++ = (n & i)? '1': '0';
*p = '\0';
return buf;
}
/*------------------- ハフマン符号の伸張処理 ----------------------*/
/*
* ハフマン木のノード用構造体
*/
typedef struct {
int parent; /* 親ノードのインデックス */
int child[2]; /* 左右の子ノードへのインデックス */
long weight; /* 重み(初期値1) */
int order; /* ノード順序(下から上、左から右) */
uchar type; /* 葉ノードの値のタイプ */
uchar val; /* 葉ノードの値 */
#ifdef TEST
uchar changed; /* 初期状態から変更された */
#endif
} HUFNODE;
/*
* ハフマン木の初期データ記述用構造体
*/
typedef struct {
long startcode; /* ハフマン符号範囲の開始値 */
long endcode; /* ハフマン符号範囲の終了値 */
int codelen; /* ハフマン符号の長さ */
uchar type; /* ハフマン符号に対応する値のタイプ */
uchar startval; /* 開始ハフマン符号の値(以降1ずつ増加) */
} HUFINIT;
#define HUF_TYPE_NONE 0 /* ルートまたは中間ノード */
#define HUF_TYPE_CHAR 1 /* 葉ノード、値は不一致文字 */
#define HUF_TYPE_LEN 2 /* 葉ノード、値は一致長 */
#define HUF_NUM_ROOT 0 /* ルートノードのインデックス */
#define HUF_NUM_NODES 627 /* ハフマン木のノード数(1+2+4+…+256+116) */
#define HUF_NUM_WMAX 32768L /* 重みの最大値 */
/*
* ハフマン木の初期化データ
*/
HUFINIT huf_init[] = {
{ 0x00L, 0x8bL, 8, /* 不一致文字: */
HUF_TYPE_CHAR, 0x74 }, /* 00000000(0x74) ~ 10001011(0xff) */
{ 0x8cL, 0xc5L, 8, /* 一致長: */
HUF_TYPE_LEN, 3 }, /* 10001100(3) ~ 11000101(60) */
{ 0x18cL, 0x1ffL, 9, /* 不一致文字: */
HUF_TYPE_CHAR, 0x00 } /* 110001100(0x00) ~ 111111111(0x73) */
};
int huf_nodenum; /* 登録ノード数(HUF_NUM_NODESと同じはず) */
HUFNODE huf_node[HUF_NUM_NODES]; /* ハフマン木のノードデータ格納用 */
HUFNODE huf_tmp[HUF_NUM_NODES+1]; /* ハフマン木再構築用の作業領域 */
int huf_onode[HUF_NUM_NODES+1]; /* 各順序位置のノードインデックス */
/*
* LZSS伸張用データ
*/
#define LZ_NUM_STARTOFF 612 /* 開始時のウィンドウオフセット */
#define LZ_NUM_WINSIZE 4096 /* ウィンドウサイズ */
static uchar lz_window[LZ_NUM_WINSIZE]; /* LZSS参照ウィンドウ */
static uchar lz_initstr[] = /* 参照ウィンドウの初期データ */
/*
* ハフマン木を初期化する
*/
int
hufInitTree(void)
{
int i, top, depth, order;
HUFINIT *ip;
/*
* ルートノードを作る
*/
top = HUF_NUM_ROOT;
huf_node[top].parent = -1;
huf_node[top].child[0] = -1;
huf_node[top].child[1] = -1;
huf_node[top].weight = 0L;
huf_node[top].order = 0;
huf_node[top].type = HUF_TYPE_NONE;
#ifdef TEST
huf_node[top].changed = FALSE;
#endif
#ifdef TEST
huf_node[top].changed = FALSE;
#endif
top++;
}
huf_node[n].weight++;
n = huf_node[n].child[dir];
}
/*
* 葉ノードにデータを設定
*/
huf_node[n].weight = 1L;
huf_node[n].type = type;
huf_node[n].val = val++;
}
ip++;
}
/*
* 深いノードから順に、左から右に順番をつける
*/
order = 1;
while (depth >= 0) {
for (i = HUF_NUM_ROOT; i < top; i++) {
if (huf_node[i].order == -depth) {
huf_node[i].order = order;
huf_onode[order] = i;
order++;
}
}
depth--;
}
huf_nodenum = top;
return huf_nodenum;
}
/*
* それぞれの葉の重みを半分にする(ハフマン木の再構築用)
*/
long
hufReduceWeight(int n, int depth)
{
if (huf_node[n].type == HUF_TYPE_NONE) {
/*
* 中間ノードの重みは左右の子ノードの重みの和
*/
huf_node[n].weight = 0L;
if (huf_node[n].child[0] != -1)
huf_node[n].weight += hufReduceWeight(huf_node[n].child[0], depth);
if (huf_node[n].child[1] != -1)
huf_node[n].weight += hufReduceWeight(huf_node[n].child[1], depth);
} else {
/*
* 葉ノードの重みを半分にする
*/
huf_node[n].weight++;
huf_node[n].weight >>= 1;
}
return huf_node[n].weight;
}
/*
* ノード順序判定のために深さを記録する(ハフマン木の再構築用)
*/
int
hufSetDepth(int n, int depth)
{
int d, newdepth;
depth++;
huf_node[n].order = -depth;
newdepth = depth;
if (huf_node[n].child[0] != -1) {
if ((d = hufSetDepth(huf_node[n].child[0], depth)) > newdepth)
newdepth = d;
}
if (huf_node[n].child[1] != -1) {
if ((d = hufSetDepth(huf_node[n].child[1], depth)) > newdepth)
newdepth = d;
}
return newdepth;
}
/*
* ハフマン木の葉の重みを半分にして再構築する
*/
void
hufReconstructTree(void)
{
int i, top, order, depth, maxdepth;
long wmin;
/*
* それぞれの葉の重みを半分にする
*/
hufReduceWeight(HUF_NUM_ROOT, 0);
/*
* 作業領域先頭に旧ハフマン木の葉のデータを取り出す
* (領域先頭要素はルートノードのために空けておく)
*/
top = 1;
for (i = 0; i < huf_nodenum; i++) {
int n = huf_onode[i];
if (huf_node[n].type != HUF_TYPE_NONE) {
huf_tmp[top].type = huf_node[n].type;
huf_tmp[top].val = huf_node[n].val;
huf_tmp[top].weight = huf_node[n].weight;
huf_tmp[top].parent = -1;
huf_tmp[top].child[0] = -1;
huf_tmp[top].child[1] = -1;
huf_tmp[top].order = -1;
#ifdef TEST
huf_tmp[top].changed = FALSE;
#endif
top++;
}
}
/*
* 親の決まっていない重みが最小の2つの
* ノードを子として持つ中間ノードを作る
* これをルートノードまでくり返す
*/
while (top <= huf_nodenum) {
int n1, n2;
wmin = HUF_NUM_WMAX;
for (i = 1; i < top; i++) {
if (huf_tmp[i].parent == -1 &&
huf_tmp[i].weight < wmin) {
wmin = huf_tmp[i].weight;
n1 = i;
}
}
wmin = HUF_NUM_WMAX;
for (i = 1; i < top; i++) {
if (huf_tmp[i].parent == -1 &&
huf_tmp[i].weight < wmin && i != n1) {
wmin = huf_tmp[i].weight;
n2 = i;
}
}
huf_tmp[top].type = HUF_TYPE_NONE;
huf_tmp[top].val = 0;
huf_tmp[top].weight = huf_tmp[n1].weight + huf_tmp[n2].weight;
huf_tmp[top].child[0] = n1;
huf_tmp[top].child[1] = n2;
huf_tmp[top].parent = -1;
huf_tmp[top].order = -1;
#ifdef TEST
huf_tmp[top].changed = FALSE;
#endif
huf_tmp[n1].parent = top;
huf_tmp[n2].parent = top;
top++;
}
/*
* 最終ノード(仮のルートノード)を先頭要素にコピーする
*/
huf_tmp[HUF_NUM_ROOT] = huf_tmp[huf_nodenum];
huf_tmp[huf_tmp[HUF_NUM_ROOT].child[0]].parent = HUF_NUM_ROOT;
huf_tmp[huf_tmp[HUF_NUM_ROOT].child[1]].parent = HUF_NUM_ROOT;
/*
* 作業領域からハフマン木格納用領域に書き戻す
*/
for (i = 0; i < huf_nodenum; i++)
huf_node[i] = huf_tmp[i];
/*
* 深いノードから順に、左から右に順番をつける
*/
maxdepth = hufSetDepth(HUF_NUM_ROOT, 0);
order = 1;
for (depth = maxdepth; depth >= 0; depth--) {
int i, n, count;
count = 0;
for (i = 0; i < huf_nodenum; i++) {
if (huf_node[i].order == -depth)
count++;
}
while (count--) {
wmin = HUF_NUM_WMAX;
for (i = 0; i < huf_nodenum; i++) {
if (huf_node[i].order == -depth &&
huf_node[i].weight < wmin) {
n = i;
wmin = huf_node[i].weight;
}
}
huf_node[n].order = order;
huf_onode[order] = n;
order++;
}
}
}
/*
* 項目データを伸張して標準出力に書き出す
*/
int
#ifdef TEST
hufDecode(long nchars, int verbose, int dodump)
#else
hufDecode(long nchars)
#endif
{
int i, cur, val, ch, lastch;
long disp, rdisp;
uchar *winpos, *winend, *copy, *p;
#ifdef TEST
long rdispmax;
#endif
/*
* LZSS参照ウィンドウを初期化する
*/
memset(lz_window, '@', sizeof(lz_window));
memcpy(lz_window, lz_initstr, sizeof(lz_initstr));
winend = &lz_window[LZ_NUM_WINSIZE];
winpos = &lz_window[LZ_NUM_STARTOFF];
#ifdef TEST
rdispmax = 0L;
#endif
/*
* 伸張すべきデータが残っている間...
*/
lastch = '\0';
while (nchars > 0) {
/*
* 葉ノードに到達するまでハフマン木をたどる
*/
cur = HUF_NUM_ROOT;
while (huf_node[cur].type == HUF_TYPE_NONE) {
int bit;
if ((bit = (int)itemGetBit(1)) < 0) {
printf("\n");
#ifdef TEST
if (verbose)
printf("rdispmax = %ld\n", rdispmax);
#endif
return -1;
}
#ifdef TEST
if (verbose)
printf("%c", bit + '0');
#endif
cur = huf_node[cur].child[bit];
}
#ifdef TEST
if (verbose)
printf(": ");
#endif
if (huf_node[cur].type == HUF_TYPE_CHAR) {
/*
* LZSS不一致文字
*/
ch = (int)huf_node[cur].val;
#ifdef TEST
if (verbose)
printf("char=0x%02x '", ch);
#endif
if (lastch != '\0') {
/*
* シフトJIS文字の2バイトめ
*/
if (ch >= 0x40 && ch != 0x7f && ch <= 0xfc) {
#ifdef UNIX
if (lastch >= 0xed && lastch <= 0xfc) {
/*
* EUCに変換できない文字
* ・0xed~0xee: NEC選定IBM拡張文字
* ・0xf0~0xf7: HDHリストゴシックにだけある文字
* ・0xfa~0xfc: IBM拡張文字
*/
printf("\\x%02x\\x%02x", lastch, ch);
} else {
printf("%s", sj2euc(lastch, ch));
}
#else
if (lastch >= 0xf0 && lastch <= 0xf7) {
/*
* HDHリストゴシックにだけある文字
*/
printf("\\x%02x\\x%02x", lastch, ch);
} else {
printf("%c%c", lastch, ch);
}
#endif
} else {
printf("\\x%02x\\x%02x", lastch, ch);
}
lastch = '\0';
} else if (ch >= 0x20 && ch <= 0x7f) {
/*
* ASCII文字
*/
printf("%c", ch);
lastch = '\0';
} else if (ch >= 0x81 && ch <= 0x9f || ch >= 0xe0 && ch <= 0xfc) {
/*
* シフトJIS文字の1バイトめ
*/
lastch = ch;
} else {
/*
* 1バイト片仮名、制御文字
*/
printf("\\x%02x", ch);
lastch = '\0';
}
#ifdef TEST
if (verbose)
printf("'\n");
#endif
nchars--;
if (winpos >= winend)
winpos = lz_window;
*winpos++ = (uchar)ch;
} else {
/*
* LZSS参照ウィンドウからのコピー
*/
int len, rest;
ulong disp;
#ifdef TEST
char *s;
#endif
/*
* コピーする長さと参照開始位置までの距離を得る
*/
len = (int)huf_node[cur].val;
disp = itemGetBit(5);
#ifdef TEST
if (verbose)
printf("len=%d, ", len);
#endif
#ifdef TEST
s = "a";
#endif
} else if (disp & 0x1000L) {
rdisp = disp - 0x1200L;
#ifdef TEST
s = "b";
#endif
} else if (disp & 0x0800L) {
rdisp = disp - 0x0600L;
#ifdef TEST
s = "c";
#endif
} else if (disp & 0x0600L) {
rdisp = disp - 0x0180L;
#ifdef TEST
s = "d";
#endif
} else if (disp & 0x0180L) {
rdisp = disp - 0x0040L;
#ifdef TEST
s = "e";
#endif
} else {
rdisp = disp;
#ifdef TEST
s = "f";
#endif
}
#ifdef TEST
if (rdisp > rdispmax)
rdispmax = rdisp;
if (verbose)
printf("disp=%ld(%s[%s])->%ld '",
disp, bstr(disp, 5+rest), s, rdisp);
#endif
nchars -= (long)len;
/*
* 参照ウィンドウからコピーする
*/
copy = winpos - rdisp - 1;
if (copy < lz_window)
copy += LZ_NUM_WINSIZE;
while (len-- > 0) {
if (copy >= winend)
copy = lz_window;
if (winpos >= winend)
winpos = lz_window;
if (lastch != '\0') {
/*
* シフトJIS文字の2バイトめ
*/
if (*copy >= 0x40 && *copy != 0x7f && *copy <= 0xfc) {
#ifdef UNIX
if (lastch >= 0xed && lastch <= 0xfc) {
/*
* EUCに変換できない文字
* ・0xed~0xee: NEC選定IBM拡張文字
* ・0xf0~0xf7: HDHリストゴシックにだけある文字
* ・0xfa~0xfc: IBM拡張文字
*/
printf("\\x%02x\\x%02x", lastch, *copy);
} else {
printf("%s", sj2euc(lastch, *copy));
}
#else
if (lastch >= 0xf0 && lastch <= 0xf7) {
/*
* HDHリストゴシックにだけある文字
*/
printf("\\x%02x\\x%02x", lastch, *copy);
} else {
printf("%c%c", lastch, *copy);
}
#endif
} else {
printf("\\x%02x\\x%02x", lastch, *copy);
}
lastch = '\0';
} else if (*copy >= 0x20 && *copy <= 0x7f) {
/*
* ASCII文字
*/
printf("%c", *copy);
lastch = '\0';
} else if (*copy >= 0x81 && *copy <= 0x9f ||
*copy >= 0xe0 && *copy <= 0xfc) {
/*
* シフトJIS文字の1バイトめ
*/
lastch = *copy;
} else {
/*
* 1バイト片仮名、制御文字
*/
printf("\\x%02x", *copy);
lastch = '\0';
}
*winpos++ = *copy++;
}
#ifdef TEST
if (verbose)
printf("'\n");
#endif
}
/*
* 重みが上限値に達したら葉の重みを半分にして
* ハフマン木を再構築し、その後処理を再開する
*/
if (huf_node[HUF_NUM_ROOT].weight == HUF_NUM_WMAX) {
int i, type, val;
#ifdef TEST
if (verbose)
printf("\nWEIGHT FULL\n");
#endif
type = huf_node[cur].type;
val = huf_node[cur].val;
hufReconstructTree();
for (i = 0; i < huf_nodenum; i++) {
if (huf_node[i].type == type &&
huf_node[i].val == val)
break;
}
cur = i;
}
#ifdef TEST
if (verbose >= 2) {
printf("swap: current: ");
hufPrintNode(cur);
printf(" target: ");
hufPrintNode(target);
}
#endif
targetpar = huf_node[target].parent;
curpar = huf_node[cur].parent;
if (huf_node[targetpar].child[0] == target)
huf_node[targetpar].child[0] = cur;
else if (huf_node[targetpar].child[1] == target)
huf_node[targetpar].child[1] = cur;
else
fprintf(stderr, "Internal error in hufDecode()\n");
if (huf_node[curpar].child[0] == cur)
huf_node[curpar].child[0] = target;
else if (huf_node[curpar].child[1] == cur)
huf_node[curpar].child[1] = target;
else
fprintf(stderr, "Internal error in hufDecode()\n");
huf_node[target].parent = curpar;
huf_node[cur].parent = targetpar;
tmp = huf_node[target].order;
huf_node[target].order = huf_node[cur].order;
huf_node[cur].order = tmp;
/*
* 順序位置参照データを交換する
*/
tmp = huf_onode[huf_node[target].order];
huf_onode[huf_node[target].order] =
huf_onode[huf_node[cur].order];
huf_onode[huf_node[cur].order] = tmp;
#ifdef TEST
hufChangeStatus(huf_onode[huf_node[target].order]);
hufChangeStatus(huf_onode[huf_node[cur].order]);
#endif
}
/*
* 現在ノードの重みを1増やして親ノードに移動
*/
huf_node[cur].weight++;
cur = huf_node[cur].parent;
}
huf_node[cur].weight++;
#ifdef TEST
if (dodump)
hufDumpTree();
#endif
}
printf("\n");
#ifdef TEST
if (verbose)
printf("rdispmax = %ld\n", rdispmax);
#endif
return 0;
}
#ifdef TEST
void
hufDumpTree(void)
{
int i;
for (i = 1; i <= huf_nodenum; i++)
hufPrintNode(huf_onode[i]);
}
#endif
/*----------- 世界大百科事典の項目データファイルの処理 ------------*/
#define IT_FILE_LOC "itemloc.dat" /* 項目エントリファイル */
#define IT_FILE_ITEM "item.dat" /* 項目データファイル */
#define IT_NUM_LOCSIZ 16L /* 項目エントリのサイズ(itemloc.dat) */
#define IT_NUM_ITHDR 6L /* 項目ヘッダのサイズ(item.dat) */
static int it_locfd = -1; /* itemloc.datのファイル記述子 */
static int it_itemfd = -1; /* item.datのファイル記述子 */
static long it_unread; /* 項目データの未読バイト数 */
static int it_bufend; /* it_bufの終端 */
static int it_curoff; /* it_buf中の現在のオフセット */
static int it_curbyte; /* 現在読んでいるバイトデータ */
static int it_curbit; /* 現在読んでいるビット位置 */
static uchar it_buf[BUFSIZ]; /* 項目読み込み用バッファ */
/*
* 項目データをオープンする
*/
int
itemOpen(void)
{
/*
* 項目エントリファイルと項目データファイルを開く
*/
if ((it_locfd = open(IT_FILE_LOC, O_RDONLY|O_BINARY)) < 0) {
return -1;
}
if ((it_itemfd = open(IT_FILE_ITEM, O_RDONLY|O_BINARY)) < 0) {
close(it_locfd);
it_locfd = -1;
return -1;
}
return 0;
}
/*
* 項目データを読む準備をする
*/
long
itemSelect(long itemno)
{
int n, len;
ulong off, size, expand;
uchar loc[IT_NUM_LOCSIZ];
/*
* 項目エントリファイルから指定された項目に対する
* 項目データファイル中のオフセットとサイズを得る
*/
if (lseek(it_locfd, itemno * IT_NUM_LOCSIZ, SEEK_SET) < 0)
return -1L;
if (read(it_locfd, loc, IT_NUM_LOCSIZ) != IT_NUM_LOCSIZ)
return -1L;
off = ((ulong)loc[0] << 24) + ((ulong)loc[1] << 16)
+ ((ulong)loc[2] << 8) + (ulong)loc[3];
size = ((ulong)loc[4] << 24) + ((ulong)loc[5] << 16)
+ ((ulong)loc[6] << 8) + (ulong)loc[7];
/*
* 項目データファイルからバッファ1回分先読みする
*/
if (lseek(it_itemfd, off, SEEK_SET) < 0)
return -1L;
len = (size > (long)BUFSIZ)? BUFSIZ: (int)size;
if ((n = read(it_itemfd, it_buf, len)) < len)
return -1L;
if (it_locfd >= 0) {
close(it_locfd);
it_locfd = -1;
}
if (it_itemfd >= 0) {
close(it_itemfd);
it_itemfd = -1;
}
return 0;
}
/*--------- メイン ---------*/
void
usage(void)
{
#ifdef TEST
fprintf(stderr, "Usage: %s [-v] [-d] [itemno]\n", prog);
fprintf(stderr, " -v: verbose (-vv for double verbose)\n");
fprintf(stderr, " -d: dump tree each time\n");
#else
fprintf(stderr, "Usage: %s [itemno]\n", prog);
#endif
exit(1);
}
int
main(int ac, char **av)
{
int i;
char *s;
long itemno;
ulong expand;
#ifdef TEST
int verbose, dodump;
#endif
itemno = -1L;
ac--, av++;
#ifdef TEST
verbose = 0;
dodump = FALSE;
while (ac > 0 && **av == '-') {
for (s = *av + 1; *s; s++) {
switch (*s) {
case 'v':
verbose++;
break;
case 'd':
dodump = TRUE;
break;
default:
usage();
}
}
ac--, av++;
}
if (ac > 0 && **av >= '0' && **av <= '9') {
if ((itemno = strtol(*av, NULL, 10)) < 0L)
usage();
if (verbose)
printf("itemno=%ld\n", itemno);
ac--, av++;
}
#else
if (ac > 0 && **av >= '0' && **av <= '9') {
if ((itemno = strtol(*av, NULL, 10)) < 0L)
usage();
ac--, av++;
}
#endif
if (ac > 0)
usage();
if (itemOpen() < 0) {
fprintf(stderr, "%s: itemOpen() failed\n", prog);
exit(1);
}
if (itemno >= 0L) {
/*
* 指定番号の項目のみテキスト化する
*/
if (hufInitTree() < 0) {
fprintf(stderr, "%s: hufInitTree() failed\n", prog);
itemClose();
exit(1);
}
if ((expand = itemSelect(itemno)) < 0L) {
fprintf(stderr, "%s: itemSelect() failed\n", prog);
itemClose();
exit(1);
}
#ifdef TEST
hufDecode(expand, verbose, dodump);
#else
hufDecode(expand);
#endif
} else {
itemno = 0L;
while ((expand = itemSelect(itemno)) >= 0L) {
if (hufInitTree() < 0) {
fprintf(stderr, "%s: hufInitTree() failed\n", prog);
itemClose();
exit(1);
}
#ifdef TEST
hufDecode(expand, verbose, dodump);
#else
hufDecode(expand);
#endif
itemno++;
Jammingの今井さんのお世話にならずに何とか解析でき
ました。(^^;
しかし今井さんはひとりで世界大百科を解析されたんで
すよね。Jammingはほかにもたくさん独自フォーマット
辞書に対応してるし...。今井さん畏るべし。
ありました。ループが終わりません。(^^;
*** cx2text.c.orig 2003年 11月 18日 (火)
--- cx2text.c 2003年 11月 18日 (火)
***************
*** 1033,1040 ****
{
int i;
char *s;
! long itemno;
! ulong expand;
#ifdef TEST
int verbose, dodump;
#endif
--- 1033,1039 ----
{
int i;
char *s;
! long itemno, expand;
#ifdef TEST
int verbose, dodump;
#endif
Junn Ohtaさんの<bpc65k$41k$1...@ns.src.ricoh.co.jp>から
>Jammingの今井さんのお世話にならずに何とか解析でき
>ました。(^^;
おめでとうございます。
藤井さんとのやりとりをずっと拝見していましたが、暗号解読のドラマ
を見るようでとても楽しかったです。
>しかし今井さんはひとりで世界大百科を解析されたんで
>すよね。Jammingはほかにもたくさん独自フォーマット
>辞書に対応してるし...。今井さん畏るべし。
すごいですよね。
今井さんとは以前、MacWorld Tokyoでお会いしたことがあるんですが、
ワタシのことは忘れてるだろうなあ。
--
Tanaka-Qtaro-Yasuhiro mailto:ta...@ca2.so-net.ne.jp
しおざきかずひこさんがこのプログラムを使って、電子
辞書オープンラボでFreePWINGスクリプトを開発中です。
詳細はメーリングリストの過去記事を参照してください。
http://openlab.jp/edict/
またEBシリーズ・サポートページではhishidaさんが世
界大百科Toolkit 0.1を公開されました。
http://plaza3.mbn.or.jp/~h_ishida/
初版、第2版ベーシック版およびプロフェッショナル版
では問題なく変換できるようです。第2版モバイル対応
版、ライブラリリンク版で動作確認してくださる方はい
らっしゃいませんか?
今井さんのお名前を検索したらアップルユーザグループ
ニュースのページが見つかり、ご尊顔が拝見できました。
「私の開発の大部分は16進ダンプをスクロールして眺め
続けること」なんだそうで。(共感共感...)
世界大百科事典の解析のほうは、その後電子辞書オープ
ンラボとEBシリーズ・サポートページのほうで続けてま
す。図版もぶじに取り出せて、WindowsではEB Studioの
hishidaさん、FreePWING方面ではしおざきかずひこさん
がEPWING変換プログラムを開発してくださってます。