/*---------------------------------------------------------------------------* Project: NintendoWare File: font_ArchiveFontBase.h Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 25413 $ *---------------------------------------------------------------------------*/ #ifndef NW_FONT_ARCHIVEFONTBASE_H_ #define NW_FONT_ARCHIVEFONTBASE_H_ #include #include #include #include #include #include #define NW_FONT_FLOAT_ASSERT(exp) ((void)0) #define NW_FONT_BUFFERSIZE_ASSERT(size) ((void)0) namespace nw { namespace font { //--------------------------------------------------------------------------- //! @brief グリフグループが定義されているフォントリソースを扱うクラスです。 //--------------------------------------------------------------------------- class ArchiveFontBase : public ResFontBase { public: struct ConstructContext; protected: struct CachedStreamReader { friend struct ConstructContext; public: //! @brief 読み出されたストリームデータの残りサイズを取得します。 //! //! @return 読み出されたストリームデータの残りサイズを返します。 //! u32 GetRemain() const; //! @brief ストリームを読み捨てます。 //! //! @param[in] dx 読み捨てるバイト数。 //! void Advance(u32 dx); //! @brief ConstructContext にストリームをコピーします。 //! //! @param[in] pContext コピー先の構築コンテキスト //! @param[in] size コピーするサイズ。 //! void CopyTo( ConstructContext* pContext, u32 size); //! @brief ストリームをコピーします。 //! //! @param[in] buf コピー先のバッファ。 //! @param[in] size コピーするサイズ。 //! void CopyTo( void* buf, u32 size); //! @brief ストリームを移動します。 //! キャッシュされているストリームをキャッシュに書き込む場合に //! 使用します。 //! //! @param[in] buf 移動先のバッファ。 //! @param[in] size 移動するサイズ。 //! void MoveTo( void* buf, u32 size); //! @brief 構築コンテキストへ必要な分のデータをコピーします。 //! //! @param[in] pContext コピー先の構築コンテキスト。 //! //! @return 必要な分に足りないサイズを返します。 //! u32 ManagedCopy(ConstructContext* pContext); //! @brief キャッシュされたデータが存在するか判定します。 //! //! @return キャッシュされたデータが存在するなら true を返します。 //! bool HasBufData() const { return mpTempStrmBufPos < mpTempStrmBufEnd; } //! @brief ストリーム中のデータを直接参照します。 //! キャッシュされたデータが存在する場合は使用できません。 //! //! @param[in] size 参照するデータサイズです。 //! 参照されるデータは既に読み取られた物として扱われます。 //! //! @return ストリームデータへのポインタを返します。 //! const void* Get(u32 size); //! @brief バッファに読み出されたストリームの一部を取り込みます。 //! //! @param[in] stream 読み出されたストリームデータ。 //! @param[in] streamSize stream に格納されているバッファのバイト数。 //! void Attach( const void* stream, u32 streamSize); //! @brief ストリームにデータの追加を要求します。 //! //! @param[in] pContext データ要求を管理する構築コンテキスト。 //! @param[in] size 必要なデータサイズ。 //! //! @return 要求に成功した場合に true を返します。 //! bool RequestData( ConstructContext* pContext, u32 size); //! @brief 現在管理しているストリーム断片中の現在位置を返します。 //! //! @return ストリーム断片先頭から現在までに読み取ったバイト数。 //! u32 GetOffset() const; private: //! 初期化します。 void Init(); private: const u8* mStreamBegin; const u8* mStreamPos; const u8* mStreamEnd; u8* mpTempStrmBuf; u8* mpTempStrmBufPos; u8* mpTempStrmBufEnd; u32 mRequireSize; }; public: /* ------------------------------------------------------------------------ 型 ------------------------------------------------------------------------ */ // 構築処理の返り値 enum ConstructResult { CONSTRUCT_MORE_DATA, CONSTRUCT_FINISH, CONSTRUCT_ERROR, CONSTRUCT_CONTINUE, NUM_OF_CONSTRUCT_RESULT }; struct ConstructContext { public: enum Operation { DISPATCH, // 0 ANALYZE_FILE_HEADER, // 1 ANALYZE_GLGR, // 2 ANALYZE_FINF, // 3 ANALYZE_CMAP, // 4 ANALYZE_CWDH, // 5 ANALYZE_TGLP, // 6 PREPAIR_COPY_SHEET, // 7 PREPAIR_EXPAND_SHEET, // 8 COPY, // 9 SKIP, // 10 EXPAND, // 11 FATAL_ERROR, // 12 NUM_OF_OPERATION, // INVALID_OPERATION }; public: void Init( void* outBuffer, u32 outBufferSize, u16* pAdjustTable, u16 nSheets, u16 nPerSheet, u32 numBlock ) { Init(outBuffer, outBufferSize, NULL); SetGLGR(pAdjustTable, nSheets, nPerSheet, numBlock); } void Init( void* outBuffer, u32 outBufferSize, const char* glyphGroups); void SetGLGR( u16* pAdjustTable, u16 nSheets, u16 nPerSheet, u32 numBlock); // 出力先バッファ位置走査 template PtrT GetCurrentPtr() { return reinterpret_cast(targetBufferCur); } u32 GetRemain() const { return static_cast(targetBufferEnd - targetBufferCur); } void Align(u32 align) { targetBufferCur = reinterpret_cast(math::RoundUp(reinterpret_cast(targetBufferCur), align)); } void Advance(u32 dx) { targetBufferCur += dx; } #ifdef NW_DEBUG u32 offset() const { return static_cast(targetBufferCur - targetBuffer); } u32 sIndex() const { return sheetIndex; } #endif // 展開完了 void Finish( void** ppData, FontInformation** ppFontInfo, u16** ppAdjustTable); // メンバ取得 u16 GetNumSheets() const { return numSheets; } u16 GetNumGlyphsPerSheet() const { return glyphsPerSheet; } CachedStreamReader& GetStreamReader() { return streamReader; } nn::cx::UncompContextHuffman* GetUncompContext() { return extendContext; } const char* GetGlyphGroups() const { return pGlyphGroups; } // メンバインクリメント void NextBlock() { currentBlock++; } void NextSheet() { sheetIndex++; } // 条件判定 bool IsRequireSheet(int sheetNo) const { NN_ASSERT( sheetNo < numSheets ); return pGlyphIndexAdjustTable[sheetNo] != ADJUST_OFFSET_SHEET_NOT_LOADED; } bool IsRequireSheet() const { return IsRequireSheet(sheetIndex); } bool HasMoreSheet() const { return sheetIndex < numSheets; } bool HasMoreBlock() const { return currentBlock < resNumBlock; } // 共通タスク void SetupCopyTask( u32 copySize, Operation nextOp = DISPATCH ) { NW_FONT_BUFFERSIZE_ASSERT( copySize ); opSize = copySize; op = ConstructContext::COPY; op2 = nextOp; } void SetupSkipTask( u32 skipSize, Operation nextOp = DISPATCH ) { NW_FONT_BUFFERSIZE_ASSERT( skipSize ); opSize = skipSize; op = ConstructContext::SKIP; op2 = nextOp; } void SetupExtendTask( u32 extendSize, Operation nextOp = DISPATCH ) { NW_FONT_BUFFERSIZE_ASSERT( extendSize ); opSize = extendSize; op = ConstructContext::EXPAND; op2 = nextOp; } void EndTask() { op = op2; } u32 TaskRemain() const { return opSize; } void TaskProceed(u32 size) { opSize -= math::Min(size, opSize); } public: FontInformation* pFINF; FontWidth* pPrevCWDH; FontCodeMap* pPrevCMAP; Operation op; ut::BinaryBlockHeader header; u32 streamOffset; private: CachedStreamReader streamReader; nn::cx::UncompContextHuffman* extendContext; const char* pGlyphGroups; u16* pGlyphIndexAdjustTable; u8* targetBuffer; u8* targetBufferEnd; u8* targetBufferCur; Operation op2; u32 opSize; u32 resNumBlock; u32 currentBlock; u16 sheetIndex; u16 numSheets; u16 glyphsPerSheet; u16 padding[1]; }; /* ------------------------------------------------------------------------ 定数 ------------------------------------------------------------------------ */ static const char LOAD_GLYPH_ALL[1]; static const int HEADER_SIZE = 16 * 1024; /* ------------------------------------------------------------------------ 関数 ------------------------------------------------------------------------ */ //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 ArchiveFontBase(); //! デストラクタです。 virtual ~ArchiveFontBase(); //@} //! @name 文字情報の取得 //@{ //---- ResFontBase のオーバーライド virtual const CharWidths GetCharWidths(CharCode c) const; virtual bool HasGlyph(CharCode c) const; //@} protected: /* ------------------------------------------------------------------------ 型 ------------------------------------------------------------------------ */ class FontGlyphGroupsAcs { public: FontGlyphGroupsAcs(const void* brfnt); u16 GetNumBlock() const { return mpHeader->dataBlocks; } u32 GetFileSize() const { return mpHeader->fileSize; } u32 GetGLGRSize() const { return mpData->header.size; } const char* GetSetName(int setNo) const { return reinterpret_cast( ut::AddOffsetToPtr(mpHeader, mpData->body.nameOffsets[setNo]) ); } u32 GetSizeCompSheet(int sheetNo) const { return mpSizeSheetsArray[sheetNo]; } u32 GetSizeCWDH(int cwdhNo) const { return mpSizeCWDHArray[cwdhNo]; } u32 GetSizeCMAP(int cmapNo) const { return mpSizeCMAPArray[cmapNo]; } bool IsUseSheet( int setNo, int sheetNo ) const { return GetBit(mpUseSheetArray, setNo * mSizeSheetFlags * 8 + sheetNo); } bool IsUseCWDH( int setNo, int cwdhNo ) const { return GetBit(mpUseCWDHArray, setNo * mSizeCWDHFlags * 8 + cwdhNo); } bool IsUseCMAP( int setNo, int cmapNo ) const { return GetBit(mpUseCMAPArray, setNo * mSizeCMAPFlags * 8 + cmapNo); } u32 GetUseSheetFlags( int setNo, int flagSetNo ) const { return mpUseSheetArray[setNo * mSizeSheetFlags / 4 + flagSetNo]; } u32 GetUseCWDHFlags( int setNo, int flagSetNo ) const { return mpUseCWDHArray [setNo * mSizeCWDHFlags / 4 + flagSetNo]; } u32 GetUseCMAPFlags( int setNo, int flagSetNo ) const { return mpUseCMAPArray [setNo * mSizeCMAPFlags / 4 + flagSetNo]; } u32 GetSheetSize() const { return mpData->body.sheetSize; } u16 GetNumGlyphsPerSheet() const { return mpData->body.glyphsPerSheet; } u16 GetNumSheet() const { return mpData->body.numSheet; } u16 GetNumSet() const { return mpData->body.numSet; } u16 GetNumCWDH() const { return mpData->body.numCWDH; } u16 GetNumCMAP() const { return mpData->body.numCMAP; } const ut::BinaryBlockHeader* GetNextBlock() const { return reinterpret_cast( ut::AddOffsetToPtr(mpData, mpData->header.size)); } private: static bool GetBit(const u32* bits, u32 index) { u32 wordIndex = index / 32; u32 bitIndex = index % 32; return ((bits[wordIndex] << bitIndex) & (1u << 31)) != 0; } const ut::BinaryFileHeader* mpHeader; const FontGlyphGroupsBlock* mpData; const u16* mpNameOffsetArray; const u32* mpSizeSheetsArray; const u32* mpSizeCWDHArray; const u32* mpSizeCMAPArray; const u32* mpUseSheetArray; const u32* mpUseCWDHArray; const u32* mpUseCMAPArray; u32 mSizeSheetFlags; u32 mSizeCWDHFlags; u32 mSizeCMAPFlags; }; /* ------------------------------------------------------------------------ 定数 ------------------------------------------------------------------------ */ static const u16 ADJUST_OFFSET_SHEET_NOT_LOADED = 0xFFFF; /* ------------------------------------------------------------------------ 関数 ------------------------------------------------------------------------ */ //---- 構築/破棄 //! @brief 割り当てられたバッファとそこに配置されている FINF ブロックへの //! ポインタ, グリフインデックス調整テーブルを設定します。 //! //! @param[in,out] pUserBuffer 割り当てられたバッファへのポインタ。 //! @param[in] pFontInfo FINF ブロックへのポインタ。 //! @param[in] pAdjustTable グリフインデックス調整テーブルへのポインタ。 //! void SetResourceBuffer( void* pUserBuffer, FontInformation* pFontInfo, u16* pAdjustTable); //! @brief SetResourceBuffer で設定されたパラメータをリセットし、 //! 割り当てられていたバッファへのポインタを返します。 //! //! @return 設定されていたバッファへのポインタ。 //! void* RemoveResourceBuffer(); //---- グリフインデックス //! @brief CMAP ブロックから取得したグリフインデックスに対して //! ロードしていないシート分の補正を行います。 //! CWDH ブロックでの文字幅情報取得には補正前のグリフインデックスを、 //! シートからのグリフイメージ切り出しには補正後の //! グリフインデックスを使用します //! //! @param[in] index 補正するグリフインデックス //! //! @return 補正後のグリフインデックスを返します。 //! GLYPH_INDEX_NOT_FOUND ではないグリフインデックスが //! 補正によって GLYPH_INDEX_NOT_FOUND になることがあります。 //! u16 AdjustIndex(u16 index) const; //---- GLGRブロック探査用 static bool IsNullString(const char* str) { return *str == '\0'; } //! @brief nameList に name が含まれているか判断します。 //! //! @param[in] nameList 文字列のカンマ区切りリスト。 //! @param[in] name 探索する文字列。 //! //! @return nameList に name が含まれているなら true を返します。 //! static bool IncludeName( const char* nameList, const char* name); //! @brief 与えられたバイナリデータが圧縮済みフォントリソースの //! GLGR ブロック部分までを含んでいるか判断します。 //! //! @param[in] brfnt 判断するバイナリデータへのポインタ。 //! @param[in] dataSize brfnt で渡されたデータのサイズ。 //! @return brfnt が GLGR ブロックを完全に含んだ圧縮済みフォントリソースなら //! true を返します。 //! static bool IsValidResource( const void* brfnt, u32 dataSize); //---- 構築処理 //! @brief 入力ストリームのデータが足りない場合の処理を行います。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! @param[in] size 必要なデータのサイズ。 //! //! @return 処理状態を返します。 //! static ConstructResult RequestData( ConstructContext* pContext, CachedStreamReader* pStream, u32 size); //! @brief バイナリファイル中のブロックごとに処理を振り分けます。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpDispatch( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief バイナリファイルヘッダを処理します。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpAnalyzeFileHeader( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief GLGR ブロックを処理します。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpAnalyzeGLGR( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief FINF ブロックを処理します。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpAnalyzeFINF( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief CMAP ブロックを処理します。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpAnalyzeCMAP( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief CWDH ブロックを処理します。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpAnalyzeCWDH( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief TGLP ブロックを処理します。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpAnalyzeTGLP( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief シートのコピー処理をセットアップします。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpPrepairCopySheet( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief シートの展開処理をセットアップします。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpPrepairExpandSheet( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief データを入力ストリームから構築コンテキストの //! 出力バッファへコピーします。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpCopy( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief 入力ストリームを読み捨てます。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpSkip( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief 入力ストリームを展開しつつ構築コンテキストの //! 出力バッファに書き出します。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpExpand( ConstructContext* pContext, CachedStreamReader* pStream); //! @brief 既に致命的なエラーが発生している場合にも関わらず //! 処理が継続された場合に呼び出されます。 //! //! @param[in] pContext ストリーム構築コンテキスト。 //! @param[in] pStream 入力ストリーム。 //! //! @return 処理状態を返します。 //! static ConstructResult ConstructOpFatalError( ConstructContext* pContext, CachedStreamReader* pStream); private: /* ------------------------------------------------------------------------ 変数 ------------------------------------------------------------------------ */ u16* m_pGlyphIndexAdjustArray; }; } // namespace font } // namespace nw #endif // NW_FONT_ARCHIVEFONTBASE_H_