○ライブラリの構成

＊ ハンドルの種類
 hpdf.hにおいて、HPDF_HANDLE(void*のtypedef)として定義されている連中。

typedef HPDF_HANDLE   HPDF_Doc;
typedef HPDF_HANDLE   HPDF_Page;
typedef HPDF_HANDLE   HPDF_Pages;
typedef HPDF_HANDLE   HPDF_Stream;
typedef HPDF_HANDLE   HPDF_Image;
typedef HPDF_HANDLE   HPDF_Font;
typedef HPDF_HANDLE   HPDF_Outline;
typedef HPDF_HANDLE   HPDF_Encoder;
typedef HPDF_HANDLE   HPDF_3DMeasure;
typedef HPDF_HANDLE   HPDF_ExData;
typedef HPDF_HANDLE   HPDF_Destination;
typedef HPDF_HANDLE   HPDF_XObject;
typedef HPDF_HANDLE   HPDF_Annotation;
typedef HPDF_HANDLE   HPDF_ExtGState;
typedef HPDF_HANDLE   HPDF_FontDef;
typedef HPDF_HANDLE   HPDF_U3D;
typedef HPDF_HANDLE   HPDF_JavaScript;
typedef HPDF_HANDLE   HPDF_Error;
typedef HPDF_HANDLE   HPDF_MMgr;
typedef HPDF_HANDLE   HPDF_Dict;
typedef HPDF_HANDLE   HPDF_EmbeddedFile;
typedef HPDF_HANDLE   HPDF_OutputIntent;
typedef HPDF_HANDLE   HPDF_Xref;
 ドキュメントには出てこないものも多いが、ユーザー用でないのかnot yet documentedなだけか、は不明。

まずはHPDF_Docのインスタンスをいっこ作って、それを元にあれこれ操作して、が基本的な使い方らしい。
インタフェース(関数)は基本的に、対象インスタンス型名_操作、の体裁でネーミングされているようだ。
あと例外処理はsetjmp/lngjmpで処理されている。これは素直に例外機構で実装すればよいだろう。

＊ DLLからエクスポートされている関数
HEADのソースからできたDLLからDependency Walkerで引っこ抜いて、ヘッダファイルを参考に分類してみる。
2012/11/09現在、こんな感じ。
→ざっと見たところ、どうもhpdf.hとDEFファイルとエクスポート可能な関数がちぐはぐ。
何をインタフェースとして公開すべきかは、ソースから当たるしかないかな……

HPDF_GetVersion

HPDF_New
HPDF_NewEx
HPDF_SetErrorHandler
HPDF_Free

HPDF_NewDoc
HPDF_FreeDoc
HPDF_HasDoc
HPDF_FreeDocAll

HPDF_SaveToStream
HPDF_GetContents
HPDF_GetStreamSize
HPDF_ReadFromStream
HPDF_ResetStream
HPDF_SaveToFile

HPDF_GetError
HPDF_GetErrorDetail
HPDF_ResetError
HPDF_CheckError

HPDF_SetPagesConfiguration
HPDF_GetPageByIndex

HPDF_GetPageLayout
HPDF_SetPageLayout
HPDF_GetPageMode
HPDF_SetPageMode
HPDF_GetViewerPreference
HPDF_SetViewerPreference
HPDF_SetOpenAction

HPDF_GetCurrentPage
HPDF_AddPage
HPDF_InsertPage
HPDF_Page_SetWidth
HPDF_Page_SetHeight
HPDF_Page_SetSize
HPDF_Page_SetRotate
HPDF_Page_SetZoom

HPDF_GetFont
HPDF_LoadType1FontFromFile
HPDF_GetTTFontDefFromFile
HPDF_LoadTTFontFromFile
HPDF_LoadTTFontFromFile2
HPDF_AddPageLabel
HPDF_UseJPFonts
HPDF_UseKRFonts
HPDF_UseCNSFonts
HPDF_UseCNTFonts

HPDF_CreateOutline
HPDF_Outline_SetOpened
HPDF_Outline_SetDestination

HPDF_Page_CreateDestination
HPDF_Destination_SetXYZ
HPDF_Destination_SetFit
HPDF_Destination_SetFitH
HPDF_Destination_SetFitV
HPDF_Destination_SetFitR
HPDF_Destination_SetFitB
HPDF_Destination_SetFitBH
HPDF_Destination_SetFitBV

HPDF_GetEncoder
HPDF_GetCurrentEncoder
HPDF_SetCurrentEncoder
HPDF_Encoder_GetType
HPDF_Encoder_GetByteType
HPDF_Encoder_GetUnicode
HPDF_Encoder_GetWritingMode
HPDF_UseJPEncodings
HPDF_UseKREncodings
HPDF_UseCNSEncodings
HPDF_UseCNTEncodings
// HPDF_UseUTFEncodings // not exported?

HPDF_Page_Create3DAnnot
HPDF_Page_CreateTextAnnot
HPDF_Page_CreateFreeTextAnnot
HPDF_Page_CreateLineAnnot
HPDF_Page_CreateLinkAnnot
HPDF_Page_CreateURILinkAnnot
//HPDF_Page_CreateTextMarkupAnnot // not exported?
HPDF_Page_CreateHighlightAnnot
HPDF_Page_CreateUnderlineAnnot
HPDF_Page_CreateSquigglyAnnot
HPDF_Page_CreateStrikeOutAnnot
HPDF_Page_CreatePopupAnnot
HPDF_Page_CreateStampAnnot
//HPDF_Page_CreateProjectionAnnot // not exported?
HPDF_Page_CreateSquareAnnot
HPDF_Page_CreateCircleAnnot
HPDF_LinkAnnot_SetHighlightMode
HPDF_LinkAnnot_SetBorderStyle
HPDF_TextAnnot_SetIcon
HPDF_TextAnnot_SetOpened
HPDF_Annot_SetRGBColor
HPDF_Annot_SetCMYKColor
HPDF_Annot_SetGrayColor
HPDF_Annot_SetNoColor
HPDF_MarkupAnnot_SetTitle
HPDF_MarkupAnnot_SetSubject
HPDF_MarkupAnnot_SetCreationDate
HPDF_MarkupAnnot_SetTransparency
HPDF_MarkupAnnot_SetIntent
HPDF_MarkupAnnot_SetPopup
HPDF_MarkupAnnot_SetRectDiff
HPDF_MarkupAnnot_SetCloudEffect
HPDF_MarkupAnnot_SetInteriorRGBColor
HPDF_MarkupAnnot_SetInteriorCMYKColor
HPDF_MarkupAnnot_SetInteriorGrayColor
HPDF_MarkupAnnot_SetInteriorTransparent
HPDF_TextMarkupAnnot_SetQuadPoints
HPDF_Annot_Set3DView
HPDF_PopupAnnot_SetOpened
HPDF_FreeTextAnnot_SetLineEndingStyle
HPDF_FreeTextAnnot_Set3PointCalloutLine
HPDF_FreeTextAnnot_Set2PointCalloutLine
HPDF_FreeTextAnnot_SetDefaultStyle
HPDF_LineAnnot_SetPosition
HPDF_LineAnnot_SetLeader
HPDF_LineAnnot_SetCaption
HPDF_Annotation_SetBorderStyle
//HPDF_ProjectionAnnot_SetExData // not exported?

//HPDF_Page_Create3DC3DMeasure // not exported?
//HPDF_Page_CreatePD33DMeasure // not exported?
//HPDF_3DMeasure_SetName // not exported?
//HPDF_3DMeasure_SetColor // not exported?
//HPDF_3DMeasure_SetTextSize // not exported?
//HPDF_3DC3DMeasure_SetTextBoxSize // not exported?
//HPDF_3DC3DMeasure_SetText // not exported?
//HPDF_3DC3DMeasure_SetProjectionAnotation // not exported?

//HPDF_Page_Create3DAnnotExData // not exported?
//HPDF_3DAnnotExData_Set3DMeasurement // not exported?

HPDF_Page_Create3DView
//HPDF_3DView_Add3DC3DMeasure

HPDF_LoadPngImageFromMem
HPDF_LoadPngImageFromFile
HPDF_LoadPngImageFromFile2
HPDF_LoadJpegImageFromFile
HPDF_LoadJpegImageFromMem
HPDF_LoadU3DFromFile
//HPDF_Image_LoadRaw1BitImageFromMem
HPDF_LoadRawImageFromFile
HPDF_LoadRawImageFromMem
HPDF_Image_AddSMask
HPDF_Image_GetSize
HPDF_Image_GetSize2
HPDF_Image_GetWidth
HPDF_Image_GetHeight
HPDF_Image_GetBitsPerComponent
HPDF_Image_GetColorSpace
HPDF_Image_SetColorMask
HPDF_Image_SetMaskImage

HPDF_SetInfoAttr
HPDF_GetInfoAttr
HPDF_SetInfoDateAttr

HPDF_SetPassword
HPDF_SetPermission
HPDF_SetEncryptionMode
HPDF_SetCompressionMode

HPDF_Font_GetFontName
HPDF_Font_GetEncodingName
HPDF_Font_GetUnicodeWidth
HPDF_Font_GetBBox
HPDF_Font_GetAscent
HPDF_Font_GetDescent
HPDF_Font_GetXHeight
HPDF_Font_GetCapHeight
HPDF_Font_TextWidth
HPDF_Font_MeasureText

//HPDF_AttachFile

HPDF_CreateExtGState
HPDF_ExtGState_SetAlphaStroke
HPDF_ExtGState_SetAlphaFill
HPDF_ExtGState_SetBlendMode

HPDF_Page_TextWidth
HPDF_Page_MeasureText
HPDF_Page_GetWidth
HPDF_Page_GetHeight
HPDF_Page_GetGMode
HPDF_Page_GetCurrentPos
HPDF_Page_GetCurrentPos2
HPDF_Page_GetCurrentTextPos
HPDF_Page_GetCurrentTextPos2
HPDF_Page_GetCurrentFont
HPDF_Page_GetCurrentFontSize
HPDF_Page_GetTransMatrix
HPDF_Page_GetLineWidth
HPDF_Page_GetLineCap
HPDF_Page_GetLineJoin
HPDF_Page_GetMiterLimit
HPDF_Page_GetDash
HPDF_Page_GetFlat
HPDF_Page_GetCharSpace
HPDF_Page_GetWordSpace
HPDF_Page_GetHorizontalScalling
HPDF_Page_GetTextLeading
HPDF_Page_GetTextRenderingMode
HPDF_Page_GetTextRaise
HPDF_Page_GetTextRise
HPDF_Page_GetRGBFill
HPDF_Page_GetRGBStroke
HPDF_Page_GetCMYKFill
HPDF_Page_GetCMYKStroke
HPDF_Page_GetGrayFill
HPDF_Page_GetGrayStroke
HPDF_Page_GetStrokingColorSpace
HPDF_Page_GetFillingColorSpace
HPDF_Page_GetTextMatrix
HPDF_Page_GetGStateDepth

HPDF_Page_SetLineWidth
HPDF_Page_SetLineCap
HPDF_Page_SetLineJoin
HPDF_Page_SetMiterLimit
HPDF_Page_SetDash
HPDF_Page_SetFlat
HPDF_Page_SetExtGState
HPDF_Page_GSave
HPDF_Page_GRestore
HPDF_Page_Concat

HPDF_Page_MoveTo
HPDF_Page_LineTo

HPDF_Page_CurveTo
HPDF_Page_CurveTo2
HPDF_Page_CurveTo3
HPDF_Page_ClosePath
HPDF_Page_Rectangle

HPDF_Page_Stroke
HPDF_Page_ClosePathStroke
HPDF_Page_Fill
HPDF_Page_Eofill
HPDF_Page_FillStroke
HPDF_Page_EofillStroke
HPDF_Page_ClosePathFillStroke
HPDF_Page_ClosePathEofillStroke
HPDF_Page_EndPath

HPDF_Page_Clip
HPDF_Page_Eoclip

HPDF_Page_BeginText
HPDF_Page_EndText

HPDF_Page_SetCharSpace
HPDF_Page_SetWordSpace
HPDF_Page_SetHorizontalScalling
HPDF_Page_SetTextLeading
HPDF_Page_SetFontAndSize
HPDF_Page_SetTextRenderingMode
HPDF_Page_SetTextRise
HPDF_Page_SetTextRaise // obsolete

HPDF_Page_MoveTextPos
HPDF_Page_MoveTextPos2
HPDF_Page_SetTextMatrix
HPDF_Page_MoveToNextLine

HPDF_Page_ShowText
HPDF_Page_ShowTextNextLine
HPDF_Page_ShowTextNextLineEx

HPDF_Page_SetGrayFill
HPDF_Page_SetGrayStroke
HPDF_Page_SetRGBFill
HPDF_Page_SetRGBStroke
HPDF_Page_SetCMYKFill
HPDF_Page_SetCMYKStroke

HPDF_Page_ExecuteXObject

HPDF_Page_DrawImage
HPDF_Page_Circle
HPDF_Page_Ellipse
HPDF_Page_Arc
HPDF_Page_TextOut
HPDF_Page_TextRect
HPDF_Page_SetSlideShow
//HPDF_ICC_LoadIccFromMem
//HPDF_LoadIccProfileFromFile

// この辺はhpdf.hにはない。hpdf_u3d.hにある
HPDF_Create3DView
HPDF_3DAnnot_Set3DView
HPDF_3DView_AddNode
HPDF_3DView_SetBackgroundColor
HPDF_3DView_SetCamera
HPDF_3DView_SetLighting
HPDF_3DView_SetOrthogonalProjection
HPDF_3DView_SetPerspectiveProjection
HPDF_U3D_Add3DView
HPDF_U3D_SetDefault3DView

＊各c/hファイルに基づくクラス構成考察
元コードにおいて「オブジェクト」的扱いになっているものを単純にクラスに写像するとして。

まずHPDF_MMgrはおそらくメモリ管理オブジェクト。Javaで実装する分には基本ランタイムのGCに任せるんでとりあえず不要。
いくつか「基本型」的なものについて、読み書きの「メソッド」を定義するクラス的なものが多々ある。Boolean、Number、Realなど。
命名規約っぽいものとして
・namespace代わり？にHPDF_(なんとか_)*な接頭辞がつく。
・構造体は基本
typedef struct _HPDF_Hoge_Rec {
} HPDF_Hoge_Rec;
typedef struct _HPDF_Hoge_Rec *HPDF_Hoge;
な定義・宣言。

＊テキストの扱いについて
まずCにとって文字列とは単なるバイト列である。ソース中のリテラルであろうと実行時に取り込んだものであろうと。
何が言いたいかというとlibHaru内部ではおそらく文字列としてのバイト列に、エンコーディングを意識した変換処理等はしていない。libHaruの「エンコーディング」とはあくまでPDFを読み書きするときの「テキストということになってるバイト列に対する付帯情報」っぽい。というか、PDFにとっての「エンコーディング」とは「テキストの文字のコードとフォントの対応」という意味っぽくて、テキストよりむしろフォントに対する付帯情報っぽい(このフォントで描画されるバイト列は全てこの対応に従う、な感じ？)
一方Javaは実行時環境内部のString/charはすべてUnicodeで、別なエンコーディングはI/Oんときだけやってろな世界。
しかしlibHaruではI/Oより前の処理にテキストがバイト列であることを前提としたロジックがわんさとあって非常に困るorz
……うむむ。基本、ライブラリユーザーにはストリームへのI/Oとか内部オブジェクトであるHPdfStringの直接生成とかはさせない(クラスパス通したらできちゃうだろーけどさorz できれば外部に見せないようにしたいけど。)ということは、HPdfString#writeValue()とかHPdfAbstractWriteStream#writeHoge()はユーザが呼ぶなよ、という話でもある。
だからwriteStrの引数にリテラルがぽーんと渡されてるコードとかライブラリ内部にしかないはずだと。で、おそらくそういうのはASCII相当のエンコーディングが仮定されているだろう(少なくともASCIIの0x00-0xFF範囲内、一部文字が違うがおおよそJISとも共通)。であれば、writeStrの引数はISO-8859-1でバイトエンコードしていいんでなかろか。
じゃ日本語とかどーすんのということだが、「そのテキストをどういうエンコーディングでPDFに落とすかは、ユーザがテキスト描画を指示したタイミングが一番わかりやすい(そのテキストを描画すべきフォントが何か分かりやすい==そのテキストをバイトエンコードすべきエンコーディングがわかりやすい)」っぽいなあ。

というか、いろいろごっちゃにしてしまってる気がしてきたorz
libHaru内におけるStream#writeStrってのは(メモリストリームもあるけど)最終的にはPDFファイルそのものに対する出力なわけで、本来その時点でなんかエンコーディングするものではない(基本バイト列を垂れ流すだけ)。
で、コンテンツとしての「文字列」を出力するのはwriteEscapeNameでありwriteEscapeTextなわけだ。
でもってHPdfStringはHPdfEncodingを持つことができて、HPdfStringを出力する分にはHPdfEncodingで出力直前にエンコーディングができる。
が、テキスト出力の典型例であるところのHPDF_Page_ShowTextあたりを見ると、フォントがTrueTypeかCIDフォントなら渡ってきたバイト列をそのままHex形式の文字列として突っ込んでる(writeStr("<")→writeBinary(text)→writeStr(">"))。一方そうでなければwriteEscapeText(text)。
……ということは、writeEscapeText()にはシングルバイト文字列相当の文字列しか渡ってこない、と仮定してもいいんかな……
→writeEscapeText()の使用個所を再確認。「HPdfStringにエンコーダがないときー」とか「フォントがTrueTypeとかCIDじゃないときー」な使われ方だな。であれば、とりあえずそういう前提で考えるか。

一方で「バイト列を書きだす」ということになると、
  Javaの byte = Cのsigned char相当、 char = Cのunsigned short(int16)相当
  そしてStringをエンコードした結果はbyte[]、文字一個はchar
という辺りも厄介になってくる。
最近のコンパイラは緩くなってきたみたいで、byte b = -1;なんてのが通ったりするんだが、それにしたって上の仕様は気をつけんと足元すくわれるorz
　んーとちょいと試してみた。java.io.OutputStream#write(byte[])あたりをちまちま触ってみると、
・byte b = (byte)130; とか通る。(130=0x82のsigned char表現であるところの-126になる。System.out.println(b); で-126が出る)
・それを含んだ配列を上のwriteでファイルに吐かせると、ちゃんと0x82で書きこまれている。
……ランタイムかコンパイラかわからんけどがんばるようになったなあ。( (byte)-126を0x82として出力するのは昔からかもだけど)
であれば、元の*_Write(char*, int)を*#write(int[], int)とせんでも、write(byte[], int)でいけるか。

うーむ、まだlibHaru中のchar*をStringと見ていいのか、byte[]と見るべきか、の判断基準がつかん。
ライブラリユーザーから文字列を受け取るメソッドはStringで受けるべきだろう。
何がそのメソッドに当たるかというとhpdf.hに宣言された関数群に含まれるもの、と言ってよいと思う。多分。

ひとつよーわからんのが、フォントと関係ない文字列(たとえばinfoとか)のエンコーディングはどうなっとればよいのだ。
→ver1.3仕様だと'3.8.1 Text Strings'に規定がある。アノテーションとかブックマーク・アーティクル・文書情報とかはPDFDocEncodingかUnicodeでエンコードされる、だそうな。(PDFDocEncodingはISO Latin 1のスーパーセット(Appendix Dにて記述、だとさ))
なんで、作る方としてはUnicodeでやっときゃおｋ、か。ただし、そのどっちになるかはわからんので、文字列ごとにBOM必須。そしてBigEndianで。
(参考: http://qune.cside.com/archives/001330.html )
……そーいやBOM書き出してるとこあったよな、と思って調べると……HPdfStringのwriteValue (HPDF_String_Write)。
で、これテキスト書き出す前にEncoderのsetParseTextしとる。
……あー、なるほど。つまりEncoderって、必要なときは生文字列(何かしらのエンコーディングに則った文字列を現すバイト列)をUnicodeに変換する機構があるのんか。
てことは少なくともJavaのStringを元にする分にはgetBytes("UTF-16BE")でええわな。(StandardCharsetsなるクラスに定義済みの「標準サポート済みCharset」を使えば例外投げないgetBytesも使える。……って、StandardsCharsetって1.7からかよorz)
しかし、そーするとC libHaruにとってEncoderとは「普段は素のバイト列で吐きだせるものを必要ならUnicode化する」機能をもつものであって、「Encoderが絡まなければ'文字列'は生のバイト列のままやりとりするだけ」という発想だとすると、Javaとはきっちり逆('文字列'はUnicodeシーケンス以外ではありえず、Encoderが絡むのはそれを生のバイト列にしたいときだけ)なんで、そこいら辺注意しないとまずいなorz
……むむむ。たとえばHPDF_*Annot_SetTitle()なんて見てるとconst char*でもらった引数をHPDF_Stringでラップしてるが、そのとき当然ながらEncoderはNULLを渡している。Java側実装ではsetTitle()なんてStringを渡したいところで、そこでASCII範囲外の文字列を突っ込んだらHPDF_String_Write()でUnicode変換しない方の処理に分岐するから確実に化ける(か、下手するとバイトエンコーディング失敗で例外が発生する)。
むむむむ。libHaruの原版に忠実なポーティングを目指すのであれば、PDF内部で各種エンコーディングされる状況もサポートすべきではあるが、書き出すときは文字列は全部ISO-8859-1相当かUTF-16BEです、にしないとかなり大ナタふるうことになるかなあ……
　ちとlibHaru内で「文字列を出力する」処理を洗い出して考える必要があるか。つまりストリームに出力するところ。
　
　CentOSの動く環境ができたのでそっちでライブラリをビルドしてデモプログラムもビルドしてみる。
　で、ちょいと実験。アノテーションを入れるデモプログラムで、アノテーション文字列にUTF-8の日本語を混ぜてみた。
　結果、激しく文字化け。そらそーだわな。
　
　で、あらためてまずはHPDF_Stream_WriteStr()の参照箇所を確認してみる。
　……大体英数字の直値か、数値の文字列化を引数として与えている。ので、ISO-8859-1とみなしちゃっていいか、と思いかけたが、ひとまずPDF/Aのサポート関数(HPDF_PDFA_SetPDFaConformance())でドキュメントのタイトルとか作成者とかの情報を渡してる。この辺、ISO-8859-1では収まらんよねuu; ……が、その辺除けば基本ISO-8859-1範囲内の、それも実質リテラルばっかし。
　うむむ。writeStrに「これはISO-8859-1でいいよ」「これはUnicodeでね」と指定できるようにしようかと思ったが、一続きの文字列の中にUnicode/非Unicodeが存在することは認められてないよなぁorz (PDF仕様に「Unicode BOMはPDFEncodingのコードと被るけど、このコードが文字列の頭に来るこたぁなかろ(ーから無視)」と書いてある箇所があるんで)
　むしろ「普段はISO-8859-1決め打ちでいくけど、Unicodeエンコーディングの開始と終了を指示できる」とした方がましかなあ。
　とりあえず、WriteStr()に「ライブラリユーザーが突っ込んだ文字列」が渡される可能性があるのはPDF/Aだけっぽいということは判明した……と思う。

　でわ続いてHPDF_Stream_WriteEscapeText/2()。
　WriteEscapeTextはWriteEscapeText2のラッパー(文字列長指定の省略)で、まず2の方はというと、WriteEscapeTextとPageのInternalShowTextNextLineでのみ使われている。で、InternalShowTextNextLineでの使用個所を見ると、フォントがTYPE0_TTかTYPE0_CIDなら別処理、そうでないときにWriteEscapeText2、という形。
　……ってちと待て。http://blog.antenna.co.jp/PDFTool/archives/2006/05/05/ によると、
　・マルチバイト文字に対するフォントは"composite font"と呼ばれ、PDFでは=CID-Keyedフォントである。
　・CID-Keyedフォントはフォントのグリフ記述の形式によって
　　Type0 : アドビのType1フォント形式
　　Type2 : TrueTypeフォント形式
　　の２種類がある。
　……ぢゃType0のTrueTypeってなんやねん。……というと、どうもCIDどうこうの前段階というか、
　・Type1フォント : いわゆるシングルバイト用フォント
　・Type0フォント : いわゆるマルチバイト用フォント
　という区分がある、らしい？
　libHaru内部の定数定義としてはTYPE0_CIDとCID_TYPE0が併存してるんだが、
　TYPE0_CID …… 前段階の方の「Type0」のうちフォント定義がCIDのもの？(HPDF_Type0Font_New()参照)
　CID_Type0 …… コード中未使用
　……となってる。CID_TYPE2も定義はあるがコード中で未使用。
　一方TYPE0_TTは前段階の方の「Type0」のうちフォント定義がCIDでないもの？らしい。(HPDF_Type0Font_New()参照)
　ふむむ。ちなみにTYPEn付かない「TRUETYPE」もあるがHPDF_TTFont_New()でattr->typeに設定されてる以外どこでも参照されてない。
　そこいら辺の仕掛けをサンプルのttfont_demo_jp.cを起点に追っかけてみると
　・フォントの「ロード」の段階ではHPdfFontDefを生成、保持するだけ。
　・フォントを使う段になって(getFont()が呼ばれた時点で) HPdfFontを生成(してキャッシュ)する。で、そのときFontDefが
　　TYPE1→Type1Font_New
　　TRUETYPE→指定されたエンコーダがマルチバイト(ENCODER_TYPE_DOUBLE_BYTE)ならType0Font_New、でなければTTFont_New
　　TYPE_CID→Type0Font_New
　というようになっている。
　こうしてみると、WriteEscapeText2も基本、シングルバイト文字列だけが来る想定っぽいな。

　一方WriteEscapeTextはPageのInternalWriteText、そしてHPDF_String_Write()で呼ばれている。前者はやっぱしフォントがTYPE0_TTかTYPE0_CID、のどっちでもないときのみ。そして後者は(そもそもここのコードをポートしようとしてこんぐらがったんだorz)「Stringに紐付くEncoderが存在せず、暗号化指定もない場合」に呼ばれる。てこたあ、やっぱしシングルバイト文字列前提？
　(なおEncoderがあったらどーすっかというと、それを使って「文字列をUTF-16BEにエンコードして出力」しているようだ。これJavaならgetBytes("UTF-16BE")で済む話だなorz)

　あとはWriteEscapeNameってのもあった。これはあちこちで使われてるが、HPDF_Dict_Write(これはDictのキーを出力)、HPdfFontTtとHPdfFontType1のOnWrite(これはどっちもリテラルの"Widths"。なんでEscape'Name'なんだ)、この辺りはまあシングルバイト文字だけと考えていいかもだが、PageのsetExtGState(ExtGStateNameを出力)、setFontAndSize(フォントのローカル名を出力)、executeXObject(これもXObjectのローカル名を出力)、HPDF_BasicEncoder_Write(エンコーダのbaseEncodingを出力)、そしてそもそもHPDF_Name_Write、この辺は何が来るかわからんorz
　(ライブラリ内部ではシングルバイト文字列しか渡してないっぽいけど。)
　とはいえ、'Name'である以上、特定のエンコーディングやフォントでレンダリングする文字列ではない、だろう多分。であれば、やっぱし非シングルバイトならUnicodeで出せばOK、という対処でいけるか。というか仕様読む限りじゃNameにシングルバイト文字以外使っていいのか分からんぞこれorz (3.1 Lexical Conventionsによると"The tokens that delimit objects and that describe the structure of a PDF file are all written in the ASCII character set, as are all the reserved words and the names used as keys in standard dictionaries." Nameは"describe the structure of a PDF file"に当たるかなぁ……)
　あと実装上の制限も気をつけんといかん。結構文字列長とか細かく上限決まっとるのだuu;

　さらにPDF仕様(1.3)に当たってみる。どうも「文字列」の扱いがいろいろあるんだなあuu; (ISO-8859-1で収まる文化圏の人は「結局全部同じじゃねーか」で済んじゃうんだろうけど……)
　で、Unicodeエンコーディングが許されるのは3.8.1で規定される"text string"。人間可読であることを企図した情報(text annotations, bookmark names, article names, document information, and so forth)は"text strings"である、らしい。
　一方、3.1.1 にはCharacter Setの規定がある。ここではPDFの文字にはregular, delimier, white-spaceの3種類があり、文字の集まりをトークンに分けるときこの種類によって行われるとある(ただしstrings, streams, commentsについては異なるルールが適用される、のだそうな)
　……しかしこのwhite-space characterがシングルバイトで規定されている(さらにこの節の直前に「この章でcharacterというのはbyteのシノニムで、時には特定の8ビット値を指す」とある)ということはここではUnicodeの相当文字は関係ないと考えていいのだろうかuu;
　そしてObjectとしてのStringは()でくくったシングルバイト文字の並びor<>でくくったHex表現の並び。どちらにしても0-255のバイト値の並び。
　
　と、いうところでちょいと http://www.kobu.com/docs/pdf/pdfxhand.htm を参照。
　これによるとAcrobat Distillerが「ＭＳゴシック」というフォント名を"/#82l#82r#83S#83V#83b#83N"と出力したらしい。
　実際そのように手書きPDFに記述してReader Xに食わせると「ＭＳゴシック」と表示する。
　だがどう見てもms932エンコードです本当に(ry
　→TrueTypeフォントはフォント名を内部に持っているようだ(naming tableなるものがある)。
　ただ、同じフォントファイルを窓で見たときとCentで見たときではフォント名の表示が違う(たとえば窓では「IPAexゴシック」、centでは「IPAexGothic」)ということがあるので、複数の名前を持てる……のだろう。
　libHaruでは実行時にTrueTypeフォントを使う場合フォントファイルそのものを指定する。とゆーことはフォント名はファイルから読み取っているのだろう(実装見りゃわかるが)。
　で、そのnaming tableの構造はというと…… http://www.microsoft.com/typography/otspec/name.htm
　……うん、長い&&ややこしい==わからん。で、http://www28095u.sakura.ne.jp/webmozi/fdv/ こーゆーサイトがあるのでつらつらと。……ふーむ、どうやらプラットフォーム/エンコーディング/言語、で複数の名前情報を定義できるのか。
　で、libHaruがその辺を読んでるのはhpdf_fontdef_tt.cのParseName()らしいが、……貴様定数定義さぼりやがったなorz
　まあともあれ、
　・Mac/RomanのPostScript name for the font があれば、それがBaseFont名
　　なければ、
　・Windows/Unicode BMP (UCS-2)/0x0409(en-US)のPostScript name for the fontがBaseFont名
　それに
　・Mac/Roman(なければWindows/Unicode BMP (UCS-2)/0x0409(en-US))のFont Subfamily nameを見て、
　　'Regular'でないならBaseFont名に追加
　てことで、フォント名としては英語名ベースでやってるとゆーことらしい。
　なんで、「どうしてもPDFにフォント名を英語名以外で記録したいんですですっ＞＜」って要望でもなければフォント名はISO-8859-1 compat. でよかろ。ああ疲れたorz
　
　話を戻して、結局「文字列」を扱う時に
　・ISO-8859-1 compat. でないとNG
　・ISO-8859-1 compat. でないならUTF-16BE(BOM付き)で出力
　・そもそも特定のエンコーディングのバイト列として<>くくりでおｋ
　の区分はどこでつければいいのかと。
　上のケースで考えると、/... (これ名前だっけ)については、「バイト列はプラットフォームのデフォルトエンコーディングに従って解釈する」ということになってる？(Centへ件のPDF持っていったら、本体の表示はできたがフォント情報は表示できなかった。)ただ、PDF仕様にそれらしい記述が見当たらんつーかどこにあるかわからんので、Readerの実装仕様かもだが。(もしかするとより新しいPDFバージョンの仕様書ならなんか書いてるかも？)うーむ、であればISO-8859-1というよりプラットフォームデフォルトエンコーディングに任せた方がむしろ適切なのか。(文書の相互運用考えたらNGだが、現にそうなってるんじゃなあ。相互運用性は作る方で担保せい、という方針なのか)

　そーいやせっかく手書きPDFのサンプルなんてものがあるのだからこれでいろいろやってみればいいじゃまいか。
　で、
　・Infoの/Titleの値をUnicodeで書いてみる
　　→OK。(Reader Xでちゃんと表示できる) なお、
　　　・BOM+UTF-16BEの「バイト列そのまま」で書くなら()でくくる
　　　・BOM+UTF-16BEの「バイト列をHex表現」で(つまり、文字で"FEFF～"と)書くなら<>でくくる
　　ReaderはどっちにしてもUnicodeエンコーディングとして解釈してくれる。
　・Infoの/Titleの値をcp932で書いてみる
　　・<>のHex表現は通らない(化ける)
　　・()でHex/Octalエンコード表現をしてもダメ(そのまま出る)
　
　……で、<>でくくったり()でくくったりというのはこりゃHPdfString(PDFのStringオブジェクト)だな。
　つまり、HPdfStringについては、ISO-8859-1 compat.でない文字列ならUnicodeで突っ込めと。
　そしてコンテントストリーム内の文字列ってのは基本特定のフォントでレンダリングされるはずで、それならフォントに紐付いたエンコーディングでエンコードされたバイト列が<Hex>で書いてあるはずだろう。
　ということで、
　・コンテントストリーム中の文字列をBOM+UTF-16BEの<Hex>で書いて、フォント定義の/Encodingを「UniJIS-UCS2-HW-H」にしてみる
　　→OK。もっとも、あおりを受けて(Hello World)が化けてしまったが。
　　ちなみにこのときフォント名はいじっていない(#82l#82r#83S#83V#83b#83N)。うーむ、ここのエンコード解釈が謎だ。
　そこで、
　・フォント名をBOM+UTF-16BEで#Hex表現にして書いてみる
　　→NG。フォント名を識別できなかったらしく(プロパティのフォントで見ると化けてる)、小塚ゴシック相当？のフォントで代替された。
　　……ってことは、NameにUnicodeは使えない、か。
　んー、とりあえず、Nameは「ライブラリユーザが自由に設定しない」前提でISO-8859-1 compat.を前提にしよか。

　あとはフォントが絡まない文字列は基本PDFのtext stringなので「シングルバイトならISO-8859-1、そうでなきゃUnicode」原則。
　そしてフォントが絡むところはHPdfFontかHPdfFontDefがHPdfEncodingを持ってるはずなので、それを元にバイトエンコーディングは可能だろう(というか、そういうよーに作る)。
　
　で、libHaruはなんかエンコーディングごとにでっかい配列を持っているのだが、これが
　・非Unicodeエンコーディング→Unicode(UTF-16)の変換表
　・CMAP
　そんでもってこのCMAPというのはAdobeが独自に各種文字(の字形)に振った番号(CID)と各エンコーディングとのマップ。
　(基本的に (range_start, range_end, cid_start) のトリプレットの集合から成っていて、元エンコーディングでrange_startからrange_endの範囲内のコードはcode - range_start + cid_startでCIDが求まるよ、という構造)
　これはAdobeが決めたコード体系との対応表なので当然出所はAdobe。で、iTextあたりは元ファイルをそのまま配布しているよーだ(iTextAsian.jarとかiTextAsianCmap.jarの中に入ってる)。
　ふむぅ。こりゃ、Java的にもAdobeのライセンス的にも、元ファイルから実行時に読むほうが筋がいいよなあ。
　ただ、それをやると厳密なところでlibHaruとの互換性が崩れる可能性がある(libHaruのソースにあるCMapはある時点でAdobeが配布したデータのスナップショットだが、たまーにアップデートされるらしいので)。とはいえUTF-16と各エンコーディングへの変換もJavaランタイム標準にまかせちゃう予定なので、そこはもう非互換、でいいとするか。
　とはいえCMapって激しくテキストのPostScriptなんで、実行時にはバイナリコンパイルとかしたほーがよかろうなあ。ライセンス上は「バイナリで配布してもいいけど著作権表示とか内蔵or添付しとけよ」だそうだから、ソース(もちろん件の表示は入ってる)で配布して実行前にコンパイルしちゃうのがよいか。
　……とりあえずその辺はEncodingとかの実装を始めてから改めて検討しよう。
　ちなみにCMap関係の総本山は http://www.adobe.com/devnet/font.html
　
　あと備忘録、UTF16→CIDのマッピングはUniJIS-UCS2-うんたらかんたら。
　windows-31j相当のが90ms-RKSJ-あーだこーだ。
　
　というところで、いちおーほぼJava Stringとライブラリでの文字列の扱いのすり合わせはOK……かな、ほんまに。

　いっぺん、demo連中を全部Javaで書いてみて、足りないクラスやらメソッドやらをスタブでごりごり足して、埋める……という方針で行ってみよか。第一目標は「Javaで書いたdemo連中がとりあえず全部コンパイル通る」こととして。
　
　で、image_demo.cをポートしようとしてちと思案。
　image(HPdfImageってことになるか)の生成、たとえばHPDF_Image_LoadJpegImage()とか見てみると、
　HPDF_Dict image = HPDF_DictStream_New()
　とやっている。が、その直後に
　image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT
　がある。
　このHPDF_OSUBCLASS_XOBJECTはJPEG、PNG、Raw(ってカメラのRaw? まさかな)、etc.etc.のImage連中のほかにu3dとかいう正体不明の奴にも付与されている。で、一方それを確認するコードはというとHPDF_Page_ExecuteXObject()にあったりするんだが、この引数型がHPDF_XObjectだったりするuu;
　はて、HPdfImage < HPdfXObject < HPdfStreamDict
　ってやっちゃっていいものかどうか。XObjectがDictであることは間違いなさそうなんだが……正直XObjectというものに固有の振る舞いとかなさそうなので、マーカーインタフェースと見てimplementだけさせたものだろうか？
　と思ったら、PDF仕様TABLE 3.20 によるとXObjectってのはむしろstreamらしい。
　あと、HPDF_Page_DrawImage()の処理を見てると、HPDF_Imageで受け取ったimageをHPDF_Page_ExecuteXObject()へXObjectとして丸投げしてるので、HPdfImage is a HPdfXObject は確実。そしてLoadJpegImageの処理を見てるとimage->streamへWriteしてるんで、少なくともHPdfImageはStreamを持つDictである必要がある。
　うーむ。とりあえず、HPdfXObject extends HPdfStreamDict、HPdfImage extends HPdfXObject、で実装してみるか。不都合があればそんとき考えるとして。

　サンプルを全部Javaで書きなおして、足りないクラスやらメソッドやらスタブで追加しまくって、割とガワはできてきた、が。
　Annotation、Font、Encoder辺りがすっからかんだなorz
　で、Annotationがやたら種類が多い。忘れたらアホなのでちょいと整理しておこう。
　HPdfAnnotation - 一応基本の抽象スーパークラス。
　　HPdfTextAnnotation
　　HPdfLinkAnnotation
　　HPdfSoundAnnotation
　　HPdfFreeTextAnnotation
　　HPdfStampAnnotation
　　HPdfSquareAnnotation
　　HPdfCircleAnnotation
　　HPdfStrikeOutAnnotation
　　HPdfHighlightAnnotation
　　HPdfUnderlineAnnotation
　　HPdfInkAnnotation
　　HPdfFileAttachmentAnnotation
　　HPdfPopupAnnotation
　　HPdf3DAnnotation
　　HPdfSquigglyAnntation
　　HPdfLineAnnotation
　　HPdfProjectionAnnotation
　……と、enum値HPDF_AnnotTypeから推定できるのがまあ、これだけ。
　で、実際コード追ってみると間にHPdfAnnotationから間に抽象クラス挟むっぽいのがいくつかある(めっさ実装継承やけどorz)のと、Sound/Ink/FileAttachmentは実装されてないっぽい。
　ともあれ、器(class)だけはできた。メソッドとかすっからかんやけどねorz

　さていよいよフォントの沼に踏み込むとするか。
　どうもFont/FontDef/FontAttrと三段構えになってるっぽいが……
　ほんでFontの具象クラスが
　HPdfCIDFont
　HPdfTrueTypeFont
　HPdfType1Font
　……てなとこか。
　というか、FontDefにもFontDefAttrがあって、さらにEncoderにもEncoderAttrがある。
　……うーん、いわゆる「サブクラスごとの挙動」を*Attrに持たせてる感じなのかこれ？
　FontについてはオリジナルコードではDictのtypedefにすぎないので、attrを使ってextendしてる、という感じだなあ。
　FontDefもstruct _HPDF_FontDef_Recをひとつぽんと決めて、Attrであれこれ追加、な感じ。
　であれば、Javaなら素直に？abstractからのextendsでいいかという気はする。ということでそうしてみよう。
　……と思ったが、FontDefにもそのAttrにもbase_fontがあったりする??(TTFont)
　うーむ。TTFontの場合なぜかFontDefのbase_fontは基本使わず(データ取得時にattrのbase_fontからちょいとコピーしてそれっきり？)attrのbase_fontばかり使っている。
　……Type1/TrueType/CIDとFontDefを当たってみたが、こんなややこしいことになっとるのはTrueTypeだけだなuu;
　うーむ。一旦、Attr継ぎ足しの構造をそのまま模倣してみるか……とりあえず、FontDefのみ。
　
　でもってごりごりと必要最低限だけのスタブ実装を進めてみたが。
　わりとFontは話をFontDefへ丸投げ(委譲とも言う:p) しとるのでFontDefをぐりぐり作るのが先決だのう。
　
　で、TrueTypeはアホほどややこしいのでType1あたりからそろそろとやろうと思ったが……
　AFMフォントファイルのロード処理、実にCらしいトークナイズをしているorz
　じゃあStringTokenizerの出番か、と思ったがJavaDoc見たら「もう使わんといて、代わりにString.splitとかjava.util.regex連とか使っといて」だそうな。……なんで？
　確かにString.splitだとメソッド一発でString[]にぶっかいてくれて便利なのだが、今回は
　・まず先頭トークンを切り出す
　・先頭トークンの内容によっては、その後を「そのまま」使う
　という用途がちょこちょこあって。「そのまま」というのは、普通に分割したら区切り文字になるとこもそのままという意味で。
　これだとString.splitでは区切り文字を復元できないので使いにくい。まあ、多分u+0020でつないどけばOKだろうが。
　じゃあregex連でやろうとしたらどーなるんだろう、と調べてみたが、……うん、とってもややこしいorz
　まあ、総本家がそう言ってるんじゃいつdeprecated付けられるか分からんのでorz regexでがんがるか……

　続いてhpdf_fontdef_type1.cのLoadFontData()。PFBファイルを読み込むものらしい、が……
　なぜかまず11バイト読んで、そこからこの11バイトの差があっちゃこっちゃ(といっても関数内だけど)で出てくる。
　バイナリエディタでPFBファイル覗いてみても先頭11バイトがなんかのシグニチャになってるわけでもないよーだし……
　うーむ。読み違えてなければ、この関数の処理は
　・読み込んだファイル内容をそのままメモリ(MemStream)に格納する。
　・その途中で、特定のキーワードを見つけたら値を読み取って別途保持する。
　……あ、そっか。一定のバイト数ずつ読み込むんで、「特定のキーワード」が読み込みの切れ目をまたいだら検出できんわな。
　で、検出したいキーワードは最大11文字か。なるほど。
　さて、「キーワード」といってもここではバイト列で読み込むんでString#indexOf()ってわけにはいかない。
　じゃあ配列でそういう検索ができるかとゆーと無理orz
　Collections.indexOfSubList()というのはあるが。あくまでこれList<>の検索だからなuu;
　そしてbyte[]をList<Byte>にするのは茨の道だったりするorz(まあいちいちユーザーコードでループ回さんといかんってだけだが、オブジェクト生成とか効率がががが。)
　ああもうjakarta primitives使っちゃう？……っても、よさげなサーチメソッドないなorz
　しょうがないのでbyte[]→List<Byte>のメソッド書いたりいろいろやってみたが……もしかしてindexOfSubArray(byte[], byte[])を書くのが一番手間がない気もしてきたuu;
　実際したいことは上記のとおり。その前提でもう一度処理を考えてみるか……バッファの再利用の問題もあるし。
　
　Cだとハードコードされてるフォントのデータとかたんまりあるんだが、Java的にはリソースファイルにでも突っ込むべきだろうなあ……(iTextなんかだとそうしてる) 確実に使うと分かってるデータなら、クラスのstaticフィールドにでも持たせればいいのかもしらんけど。
　ただ、「リソースファイル」と言ったところでバイナリのリソースについてランタイムで面倒見てくれる機構なんてないんで、自前で考えにゃいかんが……(ファイルの検索までは面倒みてくれるだろうけど)
　で、バイト列と数値周りの変換コードをぐりぐり書いてたら、こんな便法がorz
　http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=19243&forum=12
　
int value = 0x208040FF;
byte[] byteArray = new byte[4];
ByteBuffer.wrap(byteArray).putInt(value); // big endian
ByteBuffer.wrap(byteArray).order(ByteOrder.LITTLE_ENDIAN).putInt(value); // little endian
ByteBuffer.wrap(byteArray).order(ByteOrder.nativeOrder()).putInt(value); // 実行環境依存

TrueTypeフォントのチェックサム計算がよーわからんので実例に当たってみた。
基本該当バイト列をBigEndianで先頭からuint32で切り出しては足すのだが、
・残りバイト数が4未満の場合……後ろに不足バイトを0で付加して4バイトとみなす？
　(例: 8D 1D と残っていたら、0x8D1D0000 として計算。)
・計算結果の桁あふれ……単純に捨て。
……らしい。バイト列 B1 30 01 B8 01 24 18 85 8D 1D のチェックサム値が3F711A3Dだったんで。
(0xB13001B8 + 0x01241885 + 0x8D1D0000 = 0x13F711A3D 。)

TTFontDefの仕組みを見てるとどうもファイルから読ませるとそのファイルを開きっぱなし(HPDF_FileReader_NewしてそれをFontDefが受け取ってAttrに保持してそのまま)になってる。いつ閉じるんだこれ。
そーいやCのランタイムって開いたファイルはプログラム正常終了時に全部閉じる保証があったよーななかったよーな……
Javaの場合そんな面倒は見てくれないよな確かorz
……というか、Free系で全部処理してるのか……ぐぬぬ。メモリのfreeなんてJavaにないからDocumentでfreeDoc()書いた以外なんも実装しとらんぞorz
finalize()なんて使うもんじゃないしなあorz (呼ばれる保証すらない上に、「ファイナライズが必要=即GCできない」と判断されてメモリに長々と居残ることにも……)

ぐりぐり実装したFontDefを動かしてみたくなったがそーすっとI/O周り実装せにゃいかんな……
ってんでFileReadStreamから始めてみたが……うえ、java.io.InputStream連ってtell()もseek()もなかったっけorz
mark()、reset()、skip()はあるものの、mark()は常に戻れる上限指定せんといかんしorz
……nioのFileChannel使えば素でtell()とかseek()相当の機能はあるけど、Buffered*と一緒に使ってそんなコードで大丈夫か？
ちょいとGroovyで試してみたが、
・FileInputStreamをこさえてFileChannnelを取り、BufferedInputStreamでくるむ
・BufferedInputStreamで100バイトほど読んでみる
→FileChannel#position()取ったら8192とか返してくるorz やっぱしバッファリングで読んだ分進んどるしorz
これはseek()相当やったらバッファと整合が取れなくなってわやになるな……orz
と、なると道はぱっと思いつくので3つ。
1. FileChannel主体でI/Oして自力でバッファリングする。
2. BufferedInputStream主体でI/Oして自力で位置管理する。
3. JNI(ry

3.はそれくらいなら素直に？libHaruそのものをラップするわい、ってことで、1. と2. どっちが大変かのう……
バッファリングは特に行ったり来たりが入ると非常にめどい。境界またぐともうねorz
一方位置管理はというと、tell()は位置覚えとけば済む話だけど、seekがな……orz
(mark(),reset(),skip()を駆使することになるが、mark()でマーキングしておける限界はInteger.MAX_VALUE。ファイルサイズがそれを超えたらアウトorz)
→FileChannel#map()でMappedByteBuffer取れば楽だよーって話があって、確かに楽っぽいんだけど、これも一度にマップできるサイズはInteger.MAX_VALUEらしいorz
と思ったら、1.7以降だけどSeekableByteChannelとかゆーのがあった。……しかしバッファリングされてるとは思えんなこれ。
一応、ファイルを元に生成された場合はこれを実装したFileChannel(の具象インスタンス)が取れるらしいから、そっからマップするなり好きにすれば？ってことらしいが、マップの範囲は結局Integer.MAX_VALUEに限られるんで、その範囲越えてシークしたけりゃどのみち範囲変えて再マップせにゃいかんわなorz

ちとファイルマップを使ったバッファリングの方式を考えてみる。
必要な要素:
　・ファイル中での現在位置→マップ領域先頭+バッファ内位置で取れる。
　・マップドバッファ内の現在位置→バッファのposition()で取れる。
　・マップドバッファがファイルのどこからどこまでをマップしているか
　　→先頭だけ持ってれば先頭～先頭+バッファ長。

・シークのロジック
　1. シーク先が現在のマップ範囲(後方に余裕を見込む)を外れる場合、
　　前方に外れる……
　　シーク先を起点のデルタ分先としてマップ範囲を更新する。
　　(続くシークが主に小規模な前方シークであることを想定し一応小規模な戻りシークも考慮。正直、TrueTypeFontDefの実装に影響されてるが)
　2. マップ内位置を更新。

・読み込みのロジック
　1. 読み込みサイズが現在のマップ範囲(後方に余裕を見込む)を超える場合、
　　現在位置を起点としてマップ範囲を更新する。
　2. マップから読み込み実行。
　
・マップ範囲の更新

……えーと。もしかしてシークのときは何も考えずに「現在位置」だけ変更して、読み込み時にマップ範囲外ならマップ範囲更新、の方が面倒ないか、これ。
　ほんでもって範囲更新はどーしたらよいか……んむ、図でも描いて考えようorz

・ちょいと待った。fseek(fp, 0, SEEK_END)してftell(fp)でファイルサイズが取れるって？ (http://d.hatena.ne.jp/shikaku/20120515/p1)
ちとCentで試してみたら確かにそのとーり。(一応、バイナリストリームに対するfseek()でのSEEK_END指定は規格上未定義ではあるが…… https://www.jpcert.or.jp/sc-rules/c-fio19-c.html によるとこのファイルサイズ取得方法は禁じ手。)
じゃあoffset0でSEEK_ENDしたときってfpはどこに居るんだ？→未定義なんだからなんとも言えん、はずだが、一応ftell()は「ファイル先頭からのオフセット」を指すので、ファイルサイズぴったりのオフセットを返すということはファイル末の「次」に居るということになるか。
　ということでシーク周りの実装が間違ってたので一応修正。

・……どーも考えてもこんがらがる(andいろいろと頭が回らんorz)。
　シークについては、結果fpがファイルの中から抜けなければよい。
　で、読み込み時に、「fpから指定サイズ分のバイト列が読み出せる(ただし、途中でファイル末に到達する場合はそこまででよい)」ことが保証できればよい。
　この際前後の余裕とか置いといて、まずはちゃんとシークできて読めることを考えるか……
　えーと。なぜ終業後に頭が回りだすしorz
　・ファイル全体をマップしている場合→動かす必要なし。
　・後方へマップ範囲を動かす場合はちょっと前に戻る可能性が高いので、「現在位置より少し前」を新マップの起点とし、新しいマップ内の位置は「現在位置より少し前」の分。
　・前方へマップ範囲を動かす場合は現在位置をそのまま起点にすれば(とりあえず)おｋ。
　あと「後方へマップを動かす」場合の条件だな……要求されたバイト数の範囲は確保しないといかんが、それがファイル末を突き抜けてはいけない。

　またこんぐらがってきたのでMemStreamのrewrite()を実装しようとして大勘違い発見。
　libHaruのMemStreamは言ってみれば"ByteArrayRandamAccessStream"なのだ。書く方ではヒープの許す限り書けるし、基本的にR/Wのポインタは独立している。rewriteはすでに書きこまれた範囲を上書きしてR/Wのポインタを同期する機構のようだ。じゃあコンストラクタに渡すサイズってなんなのかというと、コンテナがバイト配列を要素とする可変長リストで実装されていて、その各要素の配列長がコンストラクタで取るサイズ。
　さあて、こんなんどう実装するかね。まんまList<byte[]>ってやっちゃうのがむしろ素直かもorz (ByteArrayOutputStreamを使えばフラットなバッファで持てそうだが、シークとかできないし上書きもできない(巻き戻しはできるが既存の内容は全て無効……)。List<Byte>ではバイト配列とのやりとりがバルクでできないし、Commons PrimitivesのArrayByteListも素の配列との協業がいまいち。サイズがめったに伸長しないのであれば、配列をByteBufferでくるむのが一番いいかもしらんが……→てか、「サイズがめったに伸長しないから、万が一延びたら配列再生成」であれば、別に何かでくるむこたないよな。
　さらに言えばrewrite自体TrueTypeFontDefの処理で一回呼ばれるだけ、だから少々効率が悪くても全体のパフォーマンスにはあまり影響しないはず……とはいえ、ByteArrayOutputStreamの内部バッファは作法上はお触り禁止(finalじゃないからサブクラス作っちゃえばどうとでもなるけど、ねえ……)で、読みだすためにはtoByteArray()でコピーを作る必要があるんで読み書き繰り返すようなことするとすさまじく遅くなるorz
　→オープン化されたJava6のByteArrayOutputStreamのソース見たらどのみち伸ばすときはベタに伸ばしてるなorz (Arrays.copyOf使ってるのは流石だが)じゃ、もうそれに倣いますか。

　改めてFileReadStream。
　まず前提として、シークは別途ガードされているので、シークによって読み込みポインタがファイル先頭(オフセット==0)より前に行くことはないし、ファイル末+1(オフセット==ファイルサイズ)を超えて後に行くこともない。
・ファイルサイズがビューサイズ以下の場合
　最初にファイル全体がビューにマップされ、以後再マップは行わない。ビュー内ポインタの値は読み込みポインタの値と常に等しい(もしシークによってずれが生じたならば、ビュー内ポインタは読み込みポインタの値そのままで更新できる)。
・ファイルサイズがビューサイズを超える場合
　ビューはファイルの一部をマップする。
　シークによって読み込みポインタとビュー内ポインタがずれた場合、
　* 読み込みポインタがビュー内にある
　　ビュー内ポインタはビュー先頭から読み込みポインタまでのオフセット。
　* 読み込みポインタがビューより前にある
　　読み込みポインタ位置を先頭としてビューを再マップし、ビュー内ポインタはビュー先頭となる。
　* 読み込みポインタがビューより後にある
　　もし読み込みポインタがファイル末+1にあれば、これはEOFであるので何もしない。
　　読み込みポインタ位置より少し前を先頭としてビューを再マップし、ビュー内ポインタはビュー先頭から読み込みポインタまでのオフセット。(前方シークの後小規模な戻りシークが発生するケースを考慮。)
　　前方への再マップの場合、ビューサイズは先頭位置～ファイル末に限定される。
　
　ここで読み込みを実行する場合、
　* もし読み込みポインタがファイル末+1にあれば、これはEOFであるので読み込みは実行しない(有効読み出しバイト数として-1を返す)。
　* ビュー内ポインタ + 希望読み取りサイズが
　　* ビュー内に収まる→そのまま読み取って読み込み/ビュー内ポインタを進める。
　　* ビュー末を超える→
　　　* 希望読み取りサイズがビューのサイズ以下である→ビューをずらす
　　　* 希望読み取りサイズがビューのサイズを超える→ビューを伸ばす
　　　ただし、いずれもファイル末を越えない。

……というか、こういうちまちまと再マップするようなやり方の場合FileChannel#map()はやばげorz (VMが実行環境へ公開するヒープ領域とは別口に確保されるので、GCのタイミングとかが異なる。下手するとプロセス生存中消えないのでものすごいメモリの無駄食いを生じかねない、らしいorz)
　64ビット環境ならどんだけでっかいファイルをどーんとマップしても即座にそれだけの物理メモリを食うわけではない、らしいが……まだまだ32ビット環境多いしなあ。
　むむ。バッファを自前で持ってFileChannelから都度read()してビューを作った方が安全かなぁuu;
　仮にファイル全体を一括mapするとしても、map可能なサイズ上限は0x7FFFFFFFまでに制限されている。いわゆる2Gの壁。まあPDFで扱うファイルが(PDFそれ自体を除けば)2G超えることは滅多とあるまいが……(PDFに動画でも埋め込むならともかく。画像やフォントが1G超えたらそれだけで大概だ)とはいえ、フォントファイル含めたら場合によってはかなりのファイルを開くことになるだろうから、ヒープ外のメモリをドカ食いするようなことは流石にまずかろう。
　やっぱFileChannelを開きっぱにして、ByteBuffer(ダイレクトアロケートしない)をビューとして持つ構成にした方が無難かなあuu;で、バッファはいっときがーっとアクセスしたらしばらくほっとかれる感じ？(少なくともFontDef周りの処理見てると)なので、WeakREf(→SoftRefの方がよさそう)あたり使って要らん時は消してもらうようにした方がいいかなー。
　とりあえずメモ。チャンネルの読み残しがnバイトでバッファがnバイト超のサイズ(てかlimit)のとき、ch.read(buf)ってしても普通に読み残し分だけ読んでくれる。
　あと、ストリームとチャンネルは一蓮托生(どっちかclose()すればもう一方も閉じている)。

　まだFileReadStreamが形になってない内から何だがorz
　テスト用にバイナリファイルを用意したとして、どういうパスで開けばいいのだろーか。
　gradle -q testでやってる限りは、logback.xmlに指定するパス同様、でいけるのかな？
　たしかクラスパスの通ったディレクトリにあるファイルは固有の読み方ができたよーな……と思って調べたが、要はClassLoader#getResource()/getResourceAsStream()で、これはURL/InputStreamでしか取れないのでgetChannel()できないorz

　やっぱし実装になると行き詰まるなorz どうもいろいろ状況が複合したらややこしくてかなわん……
　・要求された読み取りサイズがビューのサイズを超える場合
　　→ビューサイズ拡大。

　……というか、もう少し責務を切り分けたら分かりやすくなる……か？
　たとえば「ビュー」をクラスとして切り出す(っても他で使わんからインナークラスだけど)とか。
　となると「ビュー」の責務とはなんだ。
　・それがファイル末を越えない限り、指定位置から指定サイズのバイトストリームを確実に読み出せること
　・ファイルの先頭から末まで任意の範囲を切り出せること
　究極的には、byte[] getContent(filePos, sizeToRead) にいつでも応じてくれればよい。
　(EOFを例外以外で報告してほしいとなると、size(as int) getContent(filePos, sizeToRead, buffer(as byte[]))かな)
　「ビュー」は
　・今自分が対象ファイルのどこからどこまでを見ているのかを知っている。
　・指定された位置がそこからずれていたら適切に見ている場所をずらす。
　・読み取り位置の更新には関与しない。(それは使う側で管理してくれ)
　……かな。ちっとは形が見えてきたような。
　……で書き始めてみたが、ランダムアクセスを意識しすぎるとシーケンシャルなアクセスに対してものすごいオーバーヘッドになるなーorz (極端な話、バッファの現在位置を読み出しごとに再設定してるんで……)
　まあ、おそらく回り回ってByteBufferの内部ポインタが行ったり来たりするだけなんだし、1バイトずつのシーケンシャルアクセスでもなきゃ目くじら立てるほどじゃなかろうが……
　
　「ビュー」について
・指定された位置がそこからずれていたら適切に見ている場所をずらす。
　まで責務としたらReadStreamの大半がそっちへ移って結局ごちゃごちゃに……orz
　位置管理は使う側でやった方がいいか？
　
　……なんか、もう下手にバッファリングとか考えずに、素でFileChannelからぐりぐり読めばいい気もしてきた……
　とはいえ、メモリマップせずにFileChannelを使うだけだと、直接byte[]へ読み込めないのもあってBufferedInputStreamに比べたらパフォーマンスはガタ落ちするっぽいが……
　えい、「動かないきれいな設計より腐っても動くコードに価値がある」。もうFileChannel素でいこう。
　メモリをドカ食いするわけじゃないからSoftReferenceでどーのこーのも止め。
　……つっても、Channelからの読み込みは結局ByteBuffer相手になるわけで、一旦バッファにためこむ動作にはなるんだよな……
　そのバッファを使いまわしてなんぼなわけで、そうなると結局「ビュー」を構築するということに……
　と思ったが、バカ実装でよければByteBufferは渡されたbyte[]をwrap()しちゃえばいいのか。
　ということで、本格的にバッファリングはあきらめてorz バカ実装でひとまず体裁を整える。

　AbstractReadStreamに置いたwriteToStreamの実装に掛かったはいいがDeflateの場合どーすりゃいいのかで一苦労。
　Javaは標準ランタイムでzlibをサポートしてくれている、のだが、びみょーにzlibの作法と合ってんだかずれてんだかで、どっちも使ったことがない身で移植しようとすっと何が何だかわからんorz
　ということで、groovyshで対話的にてきとーなファイルを圧縮してみた。そのときの状況。
　1. I/Oともわざと小さいバッファを用意。
　2. is.read(inbuf)してcompressor.setInput(inbuf)。で、compressor.deflate(outbuf)ってすると2が返る。
　　これはつまりヘッダだな、てことは次のdeflateはオフセット2でsizeがoutbuf-2かよややこしい、と続けて
　3. 念のためcompressor.needInput() == trueを確認して、is.read(inbuf) -> compressor.setInput(inbuf)。
　　そしてcompressor.deflate(outbuf, 2, outbuf.length - 2)すると……あれ？戻り値0？
　　てことは、出力バッファに何も書かれてない？
　　でもってcompressor.needInput()は……trueですか。このいやしんぼ。
　4. 入力が尽きるまで繰り返してみたが、deflateは何度やっても0を返すばかり。なんじゃそりゃ。
　　で、入力尽きたのでcompressor.finish()してdeflateしたら……いきなりoutbuf一杯に書き込んできた。
　5. 今度はcompressor.finished() == trueになるまで(てか、finish()は入力バッファに対する話で、finished()は内部出力バッファが尽きたかどうかの話なのか……)ひたすらdeflate(しつつ、適当なファイルへ出力)。
　うーん。まさか、入力がfinish()されるまでヘッダ2バイト以降は書きこまないとかそんな実装なのかこれ？
　そうと決まったわけではない(入力サイズがしょぼいので溜まるまで待ってたかも)が……具体的にzlibの'API'のどれがどれに相当するんだこれは。
　ぐぐってみても、Javaでのサンプルは数バイトの文字列を圧縮してみるよーな話ばっかで、一発setInput()したら即finish()→deflate()ってな奴ばっかで、こういうちょっとずつ進めるような話は見つからんorz
　とりあえず、zstream->avail_in == 0 がcompressor.needsInput() == trueに相当し、zstream->avail_out == 0がcompressor.finished()に相当するっぽい？→でもないな。avail_outに相当する公開インタフェースはないかも。使う側で渡すバッファがいっぱいになったかどうか管理しとけ、なスタンス？(finished()はもうdeflate()呼ばれても返すもんないよ、な意味っぽい)
　でもって一番ややこしいDeflater#deflate()のJavadocに書いてあったが、「flush引数がNO_FLUSH(注:flush引数指定しないdeflateではこれが指定される)のとき、deflate()が0を返したら、さらに入力が必要かどうかneedsInput()で検査せよ」てなことが書いてある。ふむん。(てか、その一番ややこしいdeflate()は1.7からとか書いてあるんだが、してみると1.6まではflushを指定できなかったってことかいな。まあ、普通はNO_FLUSHでおｋらしいが)
　……ああ、flush引数つきdeflate()は1.7から……と考えるとなんとなく腑に落ちる気がしてきた。C zlibはdeflate()に常にflush引数付けて呼ぶからそのとき指定すればいいけど、1.6までのDeflaterはdeflate()ではflush方式を指定できなくて、そのかわり
　・普段はZ_NO_FLUSH固定
　・一度finish()呼んだら今度はZ_FINISH固定
　・おそらく、reset()でまたZ_NO_FLUSH固定に戻る。
　てな感じかね。
　そうすると使い方としては、
　・まず読む
　・setInput(inbuf)
　・ファイルが尽きてればfinish()。
　　そうでなければ、needsInput()でないかぎり、deflate()を繰り返す。
　　もしdeflate()に与えたバッファが満杯になったら(このバッファチェックは呼び出し側で)一旦吐く。
　　needsInput()になったらまた読む。
　・finished()になるまで、deflate()を呼んで内部バッファを読み出し、吐く。

　ついでにWriteStream系も一通り実装して、多分I/Oはできるようになった。
　ということは、一応TruetypeFontDefは動かしてみることができるはず……なのか。
　……しかしフォント周りをきちんと動かしたかったらEncoder周りをちゃんとしないとだめっぽいなあ。
　そしてそろそろフォント定義(というかCMap定義？)をどう扱うか決めないとorz
　でもって改めてEncoder回りを見ると……abstractなEncoderとBasicEncoderとCMapEncoderがちゃんと切り分けできてないなーこれorz
　ちょいと整理せにゃだめだこりゃ。
　
　そもそもEncoderってのは何をやってるのかというと、libHaruはCなんで「文字列」とはバイト列でしかない。まずはこれとUnicodeとの橋渡しが必要で、それを自前でやっているのがひとつ。
　で、「型名」として見えてるのはHPDF_EncoderとHPDF_BasicEncoder、HPDF_CMapEncoderだが、これを「インスタンス化」するときに具体「メソッド」とかを与えて個別に「クラス」を作ってる。Javaで言うとクラスはabstractにしといて、newするときに全部匿名クラスで具象化する感じ。
　問題なのはバイト列とUnicodeの変換テーブルを自前で持っているということで、これとJavaのランタイムが標準で持ってる変換テーブルに齟齬があると話が一気に面倒になる。
　で、BasicEncoder#writeを見てると……なんだこれ。has_differencesがTRUEならUnicode変換表からコードを順に取ってグリフ名を持ってきて出力するようなことしとるな……じゃhas_differencesがTRUEってのはどういうときだ、というとOverrideMap()が呼ばれたとき。で、OverrideMap()というのは、Unicode変換表をインスタンスごとに差し替える処理。
　そもそもこれはPDF的になにやってんのかというと、PDF仕様5.5.1 Type 1 Fontに書いてある"Encoding"の実装らしい(5.5.2でTrueType Fontでも書くことは同じということになってる)。PDFの標準エンコーディングと差異がある場合は違いをArrayで書いておけ、ということのようだ。
　うーん。一応PDFに「任意のエンコーディング文字列」を埋め込むのには対応したいのだが、結局それってlibHaru本来の「エンコード」処理とまったくの逆方向になるんだよな……そろそろそこいら辺の齟齬が見えてきたが、はてどう解消するか。
　libHaru……バイト列は指定のエンコーディングによるものとみなして素通し。ただし、Unicodeに変換する必要がある場合変換する。
　Java……実行環境に存在する時点で文字列はすべてUnicode。I/Oの際に特定のエンコーディングにする必要があれば変換する。
　ちとlibHaruのEncoderがどこでなにしてるか洗い直した方がいいか？
　
　まずEncoder共通のインタフェースが
　#validate()
　~ #toUnicode(int code)
　#setParseText(HPdfParseText state, byte[] text, int len)
　#getWritingMode()
　#getUnicode(int code)
　#getType()
　#getByteType(byte[] text, int index)
　#checkJWWLineHead(int code)
　~ #byteType(HPdfParseText state)
　~ #write
　~ #init
　
　今までのところ、Stream連中への「文字列出力」はなんだかんだでISO-8859-1コンパチな面々ばかりだった。
　で、エンコーディングを意識しないといかんのはページにテキストを描画する場合とか、だという認識だったが……
　実際にその「ページにテキストを描画する場合」を見てみると……うん。ふつーに内部ストリームにwriteEscapeTextとかしとる。
　
　でもって、PDFにおいて「エンコーディング」はフォントと密接な関係にある、というのはいつぞや調べたとおり。
　つまりフォントが絡まない文字列には特殊なエンコーディングはない(ISO-8859-01かUTF-16BE)。
　……ってそうか。結局文字列の扱いどーすんべ、って困ったときに、Encoder周りは独自の機構にするしかないよね、ということにしたんだっけか。だからdecode()なんてメソッド作ったんだよな……
　
　はてさて、こうなったらPageのテキスト出力系を埋めてそこからどうすりゃいいか探るか？
　あるいはFontDefに見通しがついた(具象クラスはまだだけどorz)んだからFontの方をちょいと掘り進むか。
　
　とりあえずFontにとりかかってみる。……で、Type0とCIDのこのこんぐらがった関係はなんじゃこりゃ。
　このライブラリは関数ポインタで「多態」めいたことを実現してるのだが、こいつは実行時に差し替えできるうえにCにゃアクセス制限なんてあってなきがごとし(とまで言ったら言い過ぎか……)なもんで、
　Type0のメンバとしてCID Type2を設定すると、*持ち主の*beforeWriteエントリをType2のそれで差し替える
なんてことをしてくれている。なんか自由すぎてこっちのがよっぽど柔軟に見えてくるなorz
(差し替えなので、this相当のオブジェクトはType0フォントの方だったりするのだこれが)
　Dictのサブクラスは数々あれど、これほど変態的？な仕掛けはほかにないよなあ。これを素直にJavaで実装しようと思ったら、beforeWrite()の実行主体を別クラスにして各インスタンスに持たせて……とかなってえらいことになる。
　その他、アクセス制限がらみでどうにもヘンテコなことになってきたので(パッケージの切り方とかクラスの配置がまずいだけなんだが、いらんとこまでpublicにしないと通らなくなるorz)、FontとFontImplを切り離してFontImplはpdfobject.font配下に置く。
　よそから呼ばれるFontのメソッドがあれば、都度Implから引き上げるということで。
　
　……で、結局CIDFontに至ってEncoderをどうするか、の問題が再燃orz
　なんにせよJavaで使う以上、実行時の「文字列」は使う側がよっぽどひねくれてない限りjava.lang.String(か、少なくともClass<T extends java.lang.CharSequence>)なはずだ。
　一方、PDFの方では、文字列とは()か<>でくくられた表現内のバイトシーケンスであって、それを「文字」にマップする必要がある場合、文字列がフォントと結びついていれば？そのフォントに指定された「エンコーディング」からグリフIDを得てグリフを見つけ出し、ラスタライズする。フォントと結び付いてない連中はBOMがなければISO-8859-1 (実際は「システムデフォルト」になるっぽいが)、あればUTF-16BEとみなして処理。
　
　実際に「文字列」を出力してる処理を確認せんとらちが空かん、ということでいよいよもってPageの各処理をのぞいてみる。
　まずはPage#showText()。……からざっとテキスト描画系を当たってみると、
　・InternalWriteText
　・InternalShowTextNextLine
　のどちらかに帰着する。で、どっちにしても、
　・現在のフォントがTYPE0_TTもしくはTYPE0_CIDなら、<>でくくって間はwriteBinary(=16進文字列表記)。
　・フォントが上のどちらでもなければwriteEscapeText(=()でくくって間は基本ISO-8859-1決め打ちのテキスト出力)。
　……なのか。ふむ。
　であれば、やはりフォント→エンコーダ→#decode()で必要なバイト列を引っ張り出すのがいいのかな。
　(オリジナルコードだと素でchar*を食わせてるところを、#decode()の結果のbyte[]を食わせる感じで)
　……てか、Java的にはencode()だな、これ。
　
　もうひとつ文字列と言えば、なAnnotationだが……テキストを指定する場合は必ずEncoderが引数上セットになっているぽい。
　そしてそのとき指定されたEncoderがNULLでなかったらそれを使ってUnicodeにしてwriteBinary。
　……ってなんか既視感がひどいんだがこないだもこの辺調べてメモったっけ？orz
　ちなみに現状JHPdfのHPdfStringの出力実装では、Encoderの有無にかかわらず「全文字が0-255で収まればISO_8859_1でwriteBinary、そうでなければBOM付けてUTF-16BEでwriteBinary」としている。(オリジナルコードでもHPDF_StringについてはwriteEscapeTextとか使ってないのよね)

　む。「欲しいのってdecode()じゃなくencode()じゃね？」と思ったが、サンプルで「計算で作ったバイト列を(文字列として)出力する」箇所があって、そのためにdecode()要るよねってことになったんだったorz
　つまりencode()は別途要る、と。
　とりあえず枠(abstractメソッド定義)だけ作成……
　
　さて、libHaruだとめっさハードコードしてるコード表というか対照表というか。
　前も書いたが本来はAdobe配布のCMapテーブルを見てうんたらすべきではある。(ライセンス的にも)
　……が、BasicEncoder連中(WinAnsiEncodingとか)の対照表ってPDF仕様(1.3だとAppendix D)に書いてあるだけ。これはハードコードしちゃってもいいか、もう……
　(いちおうWinAnsiEncodingはWindowsコードページ1252相当と書いてあるが、JREのCharset"windows-1252"と一致するかどうかわからんし、MacRomanEncodingは"Mac OS standard encoding for Latin text in western European languages."とだけある。JREにはCharset "x-MacRoman" があるけどこれと一致するのかどーか……)
　……いや待て。このどかっと定義されてる表はあくまで「元の文字コードをインデクスとしてUnicodeの対応コードを引っ張ってくる表」だ。でもって、必要なのはむしろその逆なわけで。
　……あ、でも出力時には差異を出力せにゃならんのか。その書式はというと、キーが/Differences、値は配列で「違う文字のコード /対応するグリフ名」のペアを必要なだけ。で、その差異ってのが「標準的なエンコード(baseEncode)」との差で、実行時に取ってたりするんだこれが。(同じ文字コード(そのエンコーディングでの)が異なるUnicodeのコードにマップされるものが「差異」となる)
　……うー。もうこの辺りからlibHaruの構造をなぞる形では実装できんかなあ……
　
　PDF仕様見たりlibHaruのソース見たりしてみるが方針が定まらん。
　……というか、HPDF_UNICODE_MAP_STANDARD(hpdf_encoder.c)の定義が妙だ。0x0020から始まって0x0026まで来て、次がいきなり0x2019になっとる。でその次は0x0028。0x0027どこいった？
　と思ったら、Unicode的には0x0027は黒歴史らしいorz (アポストロフィとシングルクオートに両用されてきて紛らわしいのでそれぞれ別のコードを振って0027禁止っ、ということにしたいらしい)……が、手元のJRE7でキーボードからシングルクオート打ってコード見たら0x0027。じゃあbyte[]の{0x27}ってのを持ってきてnew Stringでデコードしたらどうなんべと思ったらやっぱり0x0027。
　つまり、このHPDF_UNICODE_MAP_STANDARDはJRE標準のCharsetでは対応できない？
　