Entry

プログラミングメモ - PDF ライブラリ製作進捗メモ

2009年09月22日

地味に続けている PDF ライブラリ。昨日,目的地に向かって,かなりきつい上り坂をひたすら自転車で上る夢を見てうなされたんだけれども,まさにそういう状況です。夢では,頂上に着いたと思ったら別の場所に着いていたという,不吉なオチがあったんだけれども,なんだかなあ。

ともあれ現実はというと,とりあえず,この連休を使って,基本的なデータ型をクラスで実装するところまでできたのでした。これ,かなりしんどかった。PDF には,次の8つの型があって,これらが組み合わさって,PDF ファイルが作られるんですけれど(括弧内は実装したクラス名),もともと PDF のデータ型は,あまり体系立っていないもんで(ストリーム型の作りとか),共通部分を生かしつつひとつの体系にまとめるのが辛かったです。

  • 実数型:数値型(PDFReal : PDFNumeric<double>)
  • 整数型:数値型(PDFInteger : PDFNumeric<UInt32>)
  • 論理型(PDFBoolean)
  • 文字列型(PDFString)
  • 名前型(PDFName)
  • 配列型(PDFArray)
  • 辞書型(PDFDictionary)
  • ストリーム型(PDFStream)

さらに,これらの型を特殊化した形で,いくつかの構造(日付,矩形など)も定義されている。これも作りました。

やってることは単純で,値クラス(値オブジェクト)を作るだけの話です。少し工夫したのは,これらの型を,すべて PDFObject クラスから派生させることにしたこと。こうすことで,各クラスで共通する部分については,統一的に扱うことができます。継承の基本なので,そんなに強調するほどのことでもないんですが。また,型安全の視点から見ても,オブジェクトをコンテナに収める際,std::vector<PDFObject*> とかすることで,異なる型をひとつのコンテナに詰めることができます(取り出すときはダウンキャストする)。

結局,PDF ライブラリを作るときの躓きの石は,どうやってそれぞれの型を統一的に扱うか,といった点に集約されていると思っていて,他の PDF ライブラリ実装でもそれなりに苦労して実装しているみたい。あるところでは,void* 型や共用体(union)で作ったりしているところもあるんですけれど,根本的に型安全じゃないので,これは詰んだ手と見ました。特に,値オブジェクトでデータ構造を作る場合,デストラクタがしっかり起動してくれないと,とんでもないリソース漏れや修正の難しいアクセス違反に悩まされることになります。void* 型から reinterpret_cast した場合,キャストミスによるリークやアクセス違反が頻発しそうな感じ。親クラスにまとめることで,これが完全に解決するわけじゃないんですけれど,少なくとも軽減することはできるはず。また,PDFObject 型にまとめておけば,ファイルに書き出すメソッドのような,全体に共通するメソッドを仮想化できるので,コンテナ(PDFArray など)内にコンテナ型のオブジェクトがある場合も,型を気にすることなく,再帰的に同じメソッドを呼ぶことで処理することができます。便利だなー。仮想関数。

少しはまってたのは,配列や辞書の値コピー。配列なり辞書なりの要素は,すべて PDFObject* 型として格納しているんですけれど,実際の派生クラスのコピーコンストラクタを動かすには,ダウンキャストしなくちゃいけません。でも,どの型にダウンキャストすればいいのか分からない。これ,どうしようかな,と悩んでたんですけど,結局,とりあえずは実際に dynamic_cast したときの戻りを見ながら,ダウンキャストすることにしました。これはかなり安全。だけど,ものすごく遅くなるんだと思う。時間計ってないけど。ま,動くのを作るのが先だろう,と。

連休で面倒なところが片付いたので,これからはこれらを使って,文書構造(ページクラスとか文書クラスとか)の製作に入ります。基本要素のひとつ上のレイヤーを作るというわけ。またしばらくは,リファレンス本と格闘する予定。ある程度できたら,公開するかも。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN