1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     font_ArchiveFontBase.cpp
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: 31311 $
16  *---------------------------------------------------------------------------*/
17 
18 #include "precompiled.h"
19 
20 #include <nw/font/font_ArchiveFontBase.h>
21 #include <nw/ut/ut_Inlines.h>
22 #include <nw/assert.h>
23 #include <nw/math/math_Arithmetic.h>
24 
25 #include <cstring>
26 #include <algorithm>
27 
28 namespace nw {
29 namespace font {
30 
31 const char ArchiveFontBase::LOAD_GLYPH_ALL[1] = "";
32 
33 
34 /* =======================================================================
35         ArchiveFontBase public
36    ======================================================================== */
37 
38 /* ------------------------------------------------------------------------
39         コンストラクタ/デストラクタ
40    ------------------------------------------------------------------------ */
41 
ArchiveFontBase()42 ArchiveFontBase::ArchiveFontBase()
43 :   m_pGlyphIndexAdjustArray(NULL)
44 {
45 }
46 
~ArchiveFontBase()47 ArchiveFontBase::~ArchiveFontBase()
48 {
49 }
50 
51 
52 
53 /* ------------------------------------------------------------------------
54         Fontクラスオーバーライド
55    ------------------------------------------------------------------------ */
56 
57 const CharWidths
GetCharWidths(CharCode c) const58 ArchiveFontBase::GetCharWidths(CharCode c) const
59 {
60     GlyphIndex index = GetGlyphIndex(c);
61 
62     // GetCharWidthsFromIndex に渡すグリフインデックスは補正前のインデックスだが
63     // シートが存在しない場合は代替文字の文字幅を取得しなければならないため
64     // AdjustIndex を使ってシートが存在するかテストする
65     if (AdjustIndex(index) == GLYPH_INDEX_NOT_FOUND)
66     {
67         index = GetFINF()->alterCharIndex;
68     }
69 
70     return GetCharWidthsFromIndex(index);
71 }
72 
73 bool
HasGlyph(CharCode c) const74 ArchiveFontBase::HasGlyph(CharCode c) const
75 {
76     GlyphIndex index = FindGlyphIndex(c);
77     if (index != GLYPH_INDEX_NOT_FOUND )
78     {
79         return ( GLYPH_INDEX_NOT_FOUND != AdjustIndex(index) );
80     }
81     return false;
82 }
83 
84 
85 
86 
87 
88 /* =======================================================================
89         ArchiveFontBase protected
90    ======================================================================== */
91 
92 /* ------------------------------------------------------------------------
93         構築/破棄
94    ------------------------------------------------------------------------ */
95 
96 void
SetResourceBuffer(void * pUserBuffer,FontInformation * pFontInfo,u16 * pAdjustTable)97 ArchiveFontBase::SetResourceBuffer(
98     void*               pUserBuffer,
99     FontInformation*    pFontInfo,
100     u16*                pAdjustTable )
101 {
102     NN_POINTER_ASSERT( pUserBuffer );
103     NN_POINTER_ASSERT( pFontInfo );
104     NN_POINTER_ASSERT( pAdjustTable );
105     NN_ASSERT( m_pGlyphIndexAdjustArray == NULL );
106 
107     ResFontBase::SetResourceBuffer(pUserBuffer, pFontInfo);
108     m_pGlyphIndexAdjustArray = pAdjustTable;
109 
110     GenTextureNames();
111 }
112 
113 void*
RemoveResourceBuffer()114 ArchiveFontBase::RemoveResourceBuffer()
115 {
116     m_pGlyphIndexAdjustArray = NULL;
117     return ResFontBase::RemoveResourceBuffer();
118 }
119 
120 
121 
122 /* ------------------------------------------------------------------------
123         グリフインデックス
124    ------------------------------------------------------------------------ */
125 
126 u16
AdjustIndex(u16 index) const127 ArchiveFontBase::AdjustIndex(u16 index) const
128 {
129     const FontTextureGlyph& tg  = *GetFINF()->pGlyph;
130     const int glyphsPerSheet    = internal::GetCellsInASheet(tg);
131     const int sheetNo           = index / glyphsPerSheet;
132 
133     const u16 adjustor = m_pGlyphIndexAdjustArray[sheetNo];
134 
135     return (adjustor == ADJUST_OFFSET_SHEET_NOT_LOADED) ?
136                 GLYPH_INDEX_NOT_FOUND: static_cast<u16>(index - adjustor);
137 }
138 
139 
140 
141 /* ------------------------------------------------------------------------
142         GLGRブロック走査
143    ------------------------------------------------------------------------ */
144 
145 bool
IncludeName(const char * nameList,const char * name)146 ArchiveFontBase::IncludeName(
147     const char* nameList,
148     const char* name
149 )
150 {
151     const u32 nameLen = std::strlen(name);
152     const char* found = nameList - 1;
153 
154     // return $nameList =~ m/(^|, *)$name *(,|$)/;
155     for (;;)
156     {
157         found = std::strstr(found+1, name);
158 
159         if (found == NULL)
160         {
161             return false;
162         }
163 
164         // 先頭か?
165         if (found != nameList)
166         {
167             // 先頭でなくても直前にデリミタがあればOK
168             const char* pos = found - 1;
169             while (nameList < pos && *pos == ' ')
170             {
171                 pos--;
172             }
173 
174             if (*pos != ',')
175             {
176                 continue;
177             }
178         }
179 
180         // 次のデリミタを探す
181         const char* delimitor = std::strchr(found, ',');
182         u32 foundLen;
183 
184         // 見つかった文字列の長さを求める
185         if (delimitor != NULL)
186         {
187             foundLen = static_cast<u32>(delimitor - found);
188         }
189         else
190         {
191             foundLen = std::strlen(found);
192         }
193 
194         // 長さが同じかその末尾に空白が加わっただけなら発見
195         {
196             const char* pos = found + nameLen;
197             const char* end = found + foundLen;
198             while (pos < end && *pos == ' ')
199             {
200                 pos++;
201             }
202             if (pos == end)
203             {
204                 return true;
205             }
206         }
207     }
208 
209     // ここには届きません。
210     // return false;
211 }
212 
213 bool
IsValidResource(const void * bfnt,u32 dataSize)214 ArchiveFontBase::IsValidResource(
215     const void* bfnt,
216     u32         dataSize
217 )
218 {
219     NW_FONT_MIN_ASSERT( dataSize, sizeof(ut::BinaryFileHeader) + sizeof(ut::BinaryBlockHeader) + reinterpret_cast<u32>(reinterpret_cast<FontGlyphGroups*>(0)->nameOffsets));
220     const ut::BinaryFileHeader* fileHeader = reinterpret_cast<const ut::BinaryFileHeader*>(bfnt);
221 
222     // バイナリファイルヘッダをチェック
223     if (! IsValidBinaryFile(fileHeader, BINFILE_SIG_FONTA, FONT_FILE_VERSION, 2))
224     {
225         // サポートしていない形式
226         NN_LOG("Invalid font resource.");
227         return false;
228     }
229 
230     const FontGlyphGroupsBlock* ggBlock = reinterpret_cast<const FontGlyphGroupsBlock*>(fileHeader + 1);
231 
232     // 先頭ブロックのタイプをチェック
233     if (ggBlock->header.kind != BINBLOCK_SIG_GLGR)
234     {
235         NN_LOG("invalid block header(%c%c%c%c) expect(%c%c%c%c)",
236             (ggBlock->header.kind >> 24) & 0xFF,
237             (ggBlock->header.kind >> 16) & 0xFF,
238             (ggBlock->header.kind >>  8) & 0xFF,
239             (ggBlock->header.kind >>  0) & 0xFF,
240             (BINBLOCK_SIG_GLGR >> 24) & 0xFF,
241             (BINBLOCK_SIG_GLGR >> 16) & 0xFF,
242             (BINBLOCK_SIG_GLGR >>  8) & 0xFF,
243             (BINBLOCK_SIG_GLGR >>  0) & 0xFF
244         );
245         return false;
246     }
247 
248     // 先頭ブロックを全て読み込めているかチェック
249     if (sizeof(ut::BinaryFileHeader) + ggBlock->header.size > dataSize)
250     {
251         NN_LOG("First stream block must include all of GLGP block. "
252                             "Please use laerger stream buffer.");
253         return false;
254     }
255 
256     return true;
257 }
258 
259 
260 
261 /* ------------------------------------------------------------------------
262         構築処理
263    ------------------------------------------------------------------------ */
264 
265 ArchiveFontBase::ConstructResult
RequestData(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader * pStream,u32 size)266 ArchiveFontBase::RequestData(
267     ArchiveFontBase::ConstructContext*      pContext,
268     ArchiveFontBase::CachedStreamReader*    pStream,
269     u32                                     size
270 )
271 {
272     pContext->streamOffset += pStream->GetOffset();
273     bool bSuccess = pStream->RequestData(pContext, size);
274     return bSuccess ? CONSTRUCT_MORE_DATA: CONSTRUCT_ERROR;
275 }
276 
277 ArchiveFontBase::ConstructResult
ConstructOpDispatch(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader * pStream)278 ArchiveFontBase::ConstructOpDispatch(
279     ArchiveFontBase::ConstructContext*      pContext,
280     ArchiveFontBase::CachedStreamReader*    pStream
281 )
282 {
283     if (! pContext->HasMoreBlock())
284     {
285         return CONSTRUCT_FINISH;
286     }
287 
288     const u32 requireSize = sizeof(ut::BinaryBlockHeader);
289     if (pStream->GetRemain() < requireSize)
290     {
291         return RequestData(pContext, pStream, requireSize);
292     }
293 
294     pStream->CopyTo(&pContext->header, sizeof(pContext->header));
295 
296     switch (pContext->header.kind)
297     {
298     case BINBLOCK_SIG_GLGR: pContext->op = ConstructContext::ANALYZE_GLGR;    break;
299     case BINBLOCK_SIG_FINF: pContext->op = ConstructContext::ANALYZE_FINF;    break;
300     case BINBLOCK_SIG_CMAP: pContext->op = ConstructContext::ANALYZE_CMAP;    break;
301     case BINBLOCK_SIG_CWDH: pContext->op = ConstructContext::ANALYZE_CWDH;    break;
302     case BINBLOCK_SIG_TGLP: pContext->op = ConstructContext::ANALYZE_TGLP;    break;
303     default:
304         NN_ASSERTMSG(false, "The font has unknown block(%c%c%c%c)",
305             (pContext->header.kind >> 24) & 0xFF,
306             (pContext->header.kind >> 16) & 0xFF,
307             (pContext->header.kind >>  8) & 0xFF,
308             (pContext->header.kind >>  0) & 0xFF );
309         pContext->op = ConstructContext::FATAL_ERROR;
310         return CONSTRUCT_ERROR;
311     }
312 
313     // カレントブロック番号を次に進める
314     pContext->NextBlock();
315 
316     // ブロックデータの先頭は 4 byte アライメントが必要
317     pContext->Align(4);
318 
319     return CONSTRUCT_CONTINUE;
320 }
321 
322 ArchiveFontBase::ConstructResult
ConstructOpAnalyzeFileHeader(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader * pStream)323 ArchiveFontBase::ConstructOpAnalyzeFileHeader(
324     ArchiveFontBase::ConstructContext*      pContext,
325     ArchiveFontBase::CachedStreamReader*    pStream
326 )
327 {
328     const u32 requireSize = sizeof(ut::BinaryFileHeader);
329 
330     if (pStream->GetRemain() < requireSize)
331     {
332         return RequestData(pContext, pStream, requireSize);
333     }
334     if (pContext->GetRemain() < requireSize)
335     {
336         // 出力先バッファのサイズが足らなかった
337         NN_LOG("buffer size too small");
338         return CONSTRUCT_ERROR;
339     }
340 
341     // 一時的にコピー
342     // CopyTo(pContext, ...) だとバッファ位置が進んでしまうので CopyTo(void*, ...) を使う
343     pStream->CopyTo(pContext->GetCurrentPtr<void*>(), requireSize);
344     pContext->op = ConstructContext::DISPATCH;
345 
346     return CONSTRUCT_CONTINUE;
347 }
348 
349 ArchiveFontBase::ConstructResult
ConstructOpAnalyzeGLGR(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader * pStream)350 ArchiveFontBase::ConstructOpAnalyzeGLGR(
351     ArchiveFontBase::ConstructContext*      pContext,
352     ArchiveFontBase::CachedStreamReader*    pStream
353 )
354 {
355     u8* pTempFileHead;
356     u8* pTempGLGRTail;
357 
358     // GLGR ブロックの確保
359     {
360         const ut::BinaryFileHeader& header = *pContext->GetCurrentPtr<const ut::BinaryFileHeader*>();
361         const u32 requireSize = pContext->header.size - sizeof(ut::BinaryBlockHeader);
362 
363         if (header.signature != BINFILE_SIG_FONTA)
364         {
365             // バイナリファイルヘッダがロードされていない or これはフォントリソースではない
366             NN_LOG("invalid font binary file.");
367             return CONSTRUCT_ERROR;
368         }
369 
370         if (pStream->GetRemain() < requireSize)
371         {
372             return RequestData(pContext, pStream, requireSize);
373         }
374 
375         if (pContext->GetRemain() < requireSize)
376         {
377             // 出力先バッファのサイズが足らなかった
378             NN_LOG("buffer size too small");
379             return CONSTRUCT_ERROR;
380         }
381 
382         // GLGR ブロックを一時的にコピー
383         // CopyTo(pContext, ...) だとバッファ位置が進んでしまうので CopyTo(void*, ...) を使う
384         const u32 infoSize = sizeof(ut::BinaryFileHeader) + pContext->header.size;
385 
386         pTempFileHead      = pContext->GetCurrentPtr<u8*>();
387         u8* blockHeaderPos = pTempFileHead + sizeof(ut::BinaryFileHeader);
388         u8* blockBodyPos   = blockHeaderPos + sizeof(ut::BinaryBlockHeader);
389         pTempGLGRTail      = blockHeaderPos + pContext->header.size;
390         std::memcpy(blockHeaderPos, &pContext->header, sizeof(ut::BinaryBlockHeader));
391         pStream->CopyTo(blockBodyPos, requireSize);
392 
393         //---- 妥当性のチェック
394         if (! IsValidResource(pTempFileHead, infoSize))
395         {
396             return CONSTRUCT_ERROR;
397         }
398     }
399 
400     u16 numSheet;
401     u16 numGlyphsPerSheet;
402     u32 numBlock;
403     u16* pTempAdjustArray;
404     u32 sizeAdjustTable;
405 
406     //---- グリフインデックス調整テーブルの構築
407     {
408         FontGlyphGroupsAcs gg(pTempFileHead);
409 
410         numSheet          = gg.GetNumSheet();
411         numGlyphsPerSheet = gg.GetNumGlyphsPerSheet();
412         numBlock          = gg.GetNumBlock();
413 
414         sizeAdjustTable = math::RoundUp(gg.GetNumSheet() * sizeof(u16), 4);   // 4 バイトアライメント
415         pTempAdjustArray = reinterpret_cast<u16*>(
416             math::RoundDown(reinterpret_cast<uptr>(pTempFileHead + pContext->GetRemain() - sizeAdjustTable), 2));
417         if (pContext->GetRemain() < (pTempGLGRTail - pTempFileHead) + sizeAdjustTable)
418         {
419             // 出力先バッファのサイズが足らなかった
420             NN_LOG("buffer size too small");
421             return CONSTRUCT_ERROR;
422         }
423 
424         // 以下 AdjustTable を一時的にフラグ配列として使う。
425         // フラグを全て落とす。
426         for (int sheetNo = 0; sheetNo < gg.GetNumSheet(); ++sheetNo)
427         {
428             pTempAdjustArray[sheetNo] = 0;
429         }
430 
431         // 使用するシートに対応するフラグを立てていく。
432         for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
433         {
434             const char* setName = gg.GetSetName(setNo);
435 
436             if ( IsNullString(pContext->GetGlyphGroups())
437               || IncludeName(pContext->GetGlyphGroups(), setName)
438             )
439             {
440                 for (int sheetNo = 0; sheetNo < gg.GetNumSheet(); ++sheetNo)
441                 {
442                     if (gg.IsUseSheet(setNo, sheetNo))
443                     {
444                         pTempAdjustArray[sheetNo] = 1;
445                     }
446                 }
447             }
448         }
449 
450         // フラグを元に AdjustTable を構築する。
451         u16 adjust = 0;
452         for (int sheetNo = 0; sheetNo < gg.GetNumSheet(); ++sheetNo)
453         {
454             u16 &entry = pTempAdjustArray[sheetNo];
455 
456             if (entry == 1)
457             {
458                 entry = adjust;
459             }
460             else
461             {
462                 entry = 0xFFFF;
463                 adjust += gg.GetNumGlyphsPerSheet();
464             }
465         }
466     }
467 
468     // 以下では一時的にコピーした GLGR ブロックを破壊するので以降アクセスする事はできない。
469 
470     // Context の構築
471     {
472         u16* pTrueAdjustArray = pContext->GetCurrentPtr<u16*>();
473         pContext->Advance(sizeAdjustTable);
474 
475         std::copy(pTempAdjustArray, pTempAdjustArray + numSheet,
476                   NW_CHECKED_ARRAY_ITERATOR(pTrueAdjustArray, numSheet));
477 
478         pContext->SetGLGR( pTrueAdjustArray,
479                            numSheet,
480                            numGlyphsPerSheet,
481                            numBlock );
482 
483         pContext->op = ConstructContext::DISPATCH;
484     }
485 
486     return CONSTRUCT_CONTINUE;
487 }
488 
489 ArchiveFontBase::ConstructResult
ConstructOpAnalyzeFINF(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader *)490 ArchiveFontBase::ConstructOpAnalyzeFINF(
491     ArchiveFontBase::ConstructContext*      pContext,
492     ArchiveFontBase::CachedStreamReader*    /* pStream */
493 )
494 {
495     // バイナリブロックヘッダはコピーしない
496     u32 copySize = pContext->header.size - sizeof(ut::BinaryBlockHeader);
497 
498     if (pContext->GetRemain() < copySize)
499     {
500         // 出力先バッファのサイズが足らなかった
501         NN_LOG("buffer size too small");
502         return CONSTRUCT_ERROR;
503     }
504 
505     // コピータスク起動
506     pContext->pFINF = pContext->GetCurrentPtr<FontInformation*>();
507     pContext->SetupCopyTask(copySize);
508     return CONSTRUCT_CONTINUE;
509 }
510 
511 ArchiveFontBase::ConstructResult
ConstructOpAnalyzeCMAP(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader *)512 ArchiveFontBase::ConstructOpAnalyzeCMAP(
513     ArchiveFontBase::ConstructContext*      pContext,
514     ArchiveFontBase::CachedStreamReader*    /* pStream */
515 )
516 {
517     // 前の CMAP ブロックまたは FINF ブロックのリンクを更新する
518     FontCodeMap* pDstCMAP = pContext->GetCurrentPtr<FontCodeMap*>();
519 
520     if (pContext->pPrevCMAP != NULL)
521     {
522         pContext->pPrevCMAP->pNext = pDstCMAP;
523     }
524     else
525     {
526         NN_POINTER_ASSERT( pContext->pFINF );
527         pContext->pFINF->pMap = pDstCMAP;
528     }
529     pContext->pPrevCMAP = pDstCMAP;
530 
531     // バイナリブロックヘッダはコピーしない
532     u32 copySize = pContext->header.size - sizeof(ut::BinaryBlockHeader);
533 
534     if (pContext->GetRemain() < copySize)
535     {
536         // 出力先バッファのサイズが足らなかった
537         NN_LOG("buffer size too small");
538         return CONSTRUCT_ERROR;
539     }
540 
541     // データ本体のコピータスク
542     pContext->SetupCopyTask(copySize);
543     return CONSTRUCT_CONTINUE;
544 }
545 
546 ArchiveFontBase::ConstructResult
ConstructOpAnalyzeCWDH(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader *)547 ArchiveFontBase::ConstructOpAnalyzeCWDH(
548     ArchiveFontBase::ConstructContext*      pContext,
549     ArchiveFontBase::CachedStreamReader*    /* pStream */
550 )
551 {
552     // 前の CWDH ブロックまたは FINF ブロックのリンクを更新する
553     FontWidth* pDstCWDH = pContext->GetCurrentPtr<FontWidth*>();
554 
555     if (pContext->pPrevCWDH != NULL)
556     {
557         pContext->pPrevCWDH->pNext = pDstCWDH;
558     }
559     else
560     {
561         NN_POINTER_ASSERT(pContext->pFINF);
562         pContext->pFINF->pWidth = pDstCWDH;
563     }
564     pContext->pPrevCWDH = pDstCWDH;
565 
566     // バイナリブロックヘッダはコピーしない
567     u32 copySize = pContext->header.size - sizeof(ut::BinaryBlockHeader);
568 
569     if (pContext->GetRemain() < copySize)
570     {
571         // 出力先バッファのサイズが足らなかった
572         NN_LOG("buffer size too small");
573         return CONSTRUCT_ERROR;
574     }
575 
576     // データ本体のコピータスク
577     pContext->SetupCopyTask(copySize);
578     return CONSTRUCT_CONTINUE;
579 }
580 
581 ArchiveFontBase::ConstructResult
ConstructOpAnalyzeTGLP(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader * pStream)582 ArchiveFontBase::ConstructOpAnalyzeTGLP(
583     ArchiveFontBase::ConstructContext*      pContext,
584     ArchiveFontBase::CachedStreamReader*    pStream
585 )
586 {
587     const u32 requireSize = sizeof(FontTextureGlyph);
588     const u32 copySize    = sizeof(FontTextureGlyph);
589 
590     if (pStream->GetRemain() < requireSize)
591     {
592         return RequestData(pContext, pStream, requireSize);
593     }
594     if (pContext->GetRemain() < copySize)
595     {
596         // 出力先バッファのサイズが足らなかった
597         NN_LOG("buffer size too small");
598         return CONSTRUCT_ERROR;
599     }
600     NN_POINTER_ASSERT(pContext->pFINF);
601 
602     // FINF ブロックのリンクを更新する
603     pContext->pFINF->pGlyph = pContext->GetCurrentPtr<FontTextureGlyph*>();
604 
605     // シート以外の部分をコピー
606     pStream->CopyTo(pContext, sizeof(FontTextureGlyph));
607 
608     // シートが圧縮されているかを取得
609     const bool bSheetCompressed = ((pContext->pFINF->pGlyph->sheetFormat & FONT_SHEET_FORMAT_COMPRESSED_FLAG) != 0);
610     pContext->pFINF->pGlyph->sheetFormat &= FONT_SHEET_FORMAT_MASK;
611 
612     // シート数を更新
613     {
614         u16 numLoadSheet = 0;
615         for (int i = 0; i < pContext->GetNumSheets(); ++i)
616         {
617             if (pContext->IsRequireSheet(i))
618             {
619                 numLoadSheet++;
620             }
621         }
622         pContext->pFINF->pGlyph->sheetNum = numLoadSheet;
623     }
624 
625     // シートのストリーム内オフセットを取得
626     u32 sheetOffset  = reinterpret_cast<u32>(pContext->pFINF->pGlyph->sheetImage);
627 
628     // シートにはアライメントが必要
629     pContext->Align(GlyphDataAlignment);
630     pContext->pFINF->pGlyph->sheetImage = pContext->GetCurrentPtr<u8*>();
631 
632     // シートが圧縮されているかに応じて分岐
633     const ConstructContext::Operation nextOp
634         = bSheetCompressed ? ConstructContext::PREPAIR_EXPAND_SHEET:
635                              ConstructContext::PREPAIR_COPY_SHEET;
636 
637     // シートのある位置までスキップ
638     u32 streamOffset = pContext->streamOffset + pStream->GetOffset();
639     u32 skipSize     = sheetOffset - streamOffset;
640     pContext->SetupSkipTask(skipSize, nextOp);
641 
642     return CONSTRUCT_CONTINUE;
643 }
644 
645 ArchiveFontBase::ConstructResult
ConstructOpPrepairCopySheet(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader *)646 ArchiveFontBase::ConstructOpPrepairCopySheet(
647     ArchiveFontBase::ConstructContext*      pContext,
648     ArchiveFontBase::CachedStreamReader*    /* pStream */
649 )
650 {
651     // 全てのシートに対して処理が終わっているか?
652     if (! pContext->HasMoreSheet())
653     {
654         pContext->op = ConstructContext::DISPATCH;
655         return CONSTRUCT_CONTINUE;
656     }
657 
658     const u32 copySize = pContext->pFINF->pGlyph->sheetSize;
659 
660     // ロードしなければならないシートか?
661     if (pContext->IsRequireSheet())
662     {
663         // ロードする
664         if (pContext->GetRemain() < copySize)
665         {
666             NN_LOG("buffer size too small");
667             return CONSTRUCT_ERROR;
668         }
669 
670         // コピー
671         pContext->SetupCopyTask(copySize, ConstructContext::PREPAIR_COPY_SHEET);
672     }
673     else
674     {
675         // ロードしない
676         pContext->SetupSkipTask(copySize, ConstructContext::PREPAIR_COPY_SHEET);
677     }
678 
679     // カレントシート番号を更新
680     pContext->NextSheet();
681 
682     return CONSTRUCT_CONTINUE;
683 }
684 
685 ArchiveFontBase::ConstructResult
ConstructOpPrepairExpandSheet(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader * pStream)686 ArchiveFontBase::ConstructOpPrepairExpandSheet(
687     ArchiveFontBase::ConstructContext*      pContext,
688     ArchiveFontBase::CachedStreamReader*    pStream
689 )
690 {
691     // 全てのシートに対して処理が終わっているか?
692     if (! pContext->HasMoreSheet())
693     {
694         pContext->op = ConstructContext::DISPATCH;
695         return CONSTRUCT_CONTINUE;
696     }
697 
698     u32 compSize;
699     u32 huffHead;
700 
701     const u32 requireSize = sizeof(compSize) + sizeof(huffHead);
702 
703     if (pStream->GetRemain() < requireSize)
704     {
705         return RequestData(pContext, pStream, requireSize);
706     }
707 
708     // 圧縮データサイズを読み込む
709     pStream->CopyTo(&compSize, sizeof(compSize));
710     std::memcpy(&huffHead, pStream->Get(0), sizeof(huffHead));
711         // Get(0) はよくないがストリーム位置を移動させないため
712 
713     const u32 srcSize = compSize;
714     const u32 dstSize = nn::cx::GetUncompressedSize(&huffHead);
715 
716     // ロードしなければならないシートか?
717     if (pContext->IsRequireSheet())
718     {
719         // ロードする
720 
721         if (pContext->GetRemain() < srcSize + sizeof(*pContext->GetUncompContext()))
722         {
723             NN_LOG("buffer size too small");
724             return CONSTRUCT_ERROR;
725         }
726 
727         // データ展開
728         nn::cx::InitUncompContextHuffman( pContext->GetUncompContext(),
729                                     pContext->GetCurrentPtr<u8*>());
730         pContext->SetupExtendTask(srcSize, ConstructContext::PREPAIR_EXPAND_SHEET);
731 
732         // ExtendTask では出力バッファ位置が更新されないので
733         // 展開されるサイズ分あらかじめ進めておく必要がある
734         pContext->Advance(dstSize);
735     }
736     else
737     {
738         // ロードしない
739         pContext->SetupSkipTask(srcSize, ConstructContext::PREPAIR_EXPAND_SHEET);
740     }
741 
742     // カレントシート番号を更新
743     pContext->NextSheet();
744 
745     return CONSTRUCT_CONTINUE;
746 }
747 
748 ArchiveFontBase::ConstructResult
ConstructOpCopy(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader * pStream)749 ArchiveFontBase::ConstructOpCopy(
750     ArchiveFontBase::ConstructContext*      pContext,
751     ArchiveFontBase::CachedStreamReader*    pStream
752 )
753 {
754     const u32 requireSize = pStream->ManagedCopy(pContext);
755 
756     if (requireSize == 0)
757     {
758         // コピー終了
759         pContext->EndTask();
760     }
761     else
762     {
763         // 更なるデータが必要
764         return RequestData(pContext, pStream, requireSize);
765     }
766 
767     return CONSTRUCT_CONTINUE;
768 }
769 
770 ArchiveFontBase::ConstructResult
ConstructOpSkip(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader * pStream)771 ArchiveFontBase::ConstructOpSkip(
772     ArchiveFontBase::ConstructContext*      pContext,
773     ArchiveFontBase::CachedStreamReader*    pStream
774 )
775 {
776     u32 skipSize = math::Min(pContext->TaskRemain(), pStream->GetRemain());
777 
778     pStream->Advance(skipSize);
779     pContext->TaskProceed(skipSize);
780 
781     if (pContext->TaskRemain() == 0)
782     {
783         // スキップ終了
784         pContext->EndTask();
785     }
786     else
787     {
788         // スキップ継続
789         return RequestData(pContext, pStream, pContext->TaskRemain());
790     }
791 
792     return CONSTRUCT_CONTINUE;
793 }
794 
795 ArchiveFontBase::ConstructResult
ConstructOpExpand(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader * pStream)796 ArchiveFontBase::ConstructOpExpand(
797     ArchiveFontBase::ConstructContext*      pContext,
798     ArchiveFontBase::CachedStreamReader*    pStream
799 )
800 {
801     NN_ASSERT(! pStream->HasBufData());
802     u32 extendSize = math::Min(pContext->TaskRemain(), pStream->GetRemain());
803 
804     s32 remain =
805         nn::cx::ReadUncompHuffman( pContext->GetUncompContext(),
806                                       reinterpret_cast<const u8*>(pStream->Get(extendSize)),
807                                       extendSize );
808     NN_ASSERT(remain >= 0);
809 
810     pContext->TaskProceed(extendSize);
811 
812     if (pContext->TaskRemain() == 0)
813     {
814         // 展開終了
815         NN_ASSERT(remain == 0);
816         pContext->EndTask();
817     }
818     else
819     {
820         // 更なるデータが必要
821         NN_ASSERT(remain != 0);
822         return RequestData(pContext, pStream, pContext->TaskRemain());
823     }
824 
825     return CONSTRUCT_CONTINUE;
826 }
827 
828 ArchiveFontBase::ConstructResult
ConstructOpFatalError(ArchiveFontBase::ConstructContext * pContext,ArchiveFontBase::CachedStreamReader *)829 ArchiveFontBase::ConstructOpFatalError(
830     ArchiveFontBase::ConstructContext*      pContext,
831     ArchiveFontBase::CachedStreamReader*    /* pStream */
832 )
833 {
834 
835     pContext->op = ConstructContext::FATAL_ERROR;
836     return CONSTRUCT_ERROR;
837 }
838 
839 
840 
841 
842 
843 /* =======================================================================
844         CachedStreamReader
845    ======================================================================== */
846 
847 void
Init()848 ArchiveFontBase::CachedStreamReader::Init()
849 {
850     mStreamBegin        = NULL;
851     mStreamPos          = NULL;
852     mStreamEnd          = NULL;
853     mpTempStrmBuf       = NULL;
854     mpTempStrmBufPos    = NULL;
855     mpTempStrmBufEnd    = NULL;
856     mRequireSize        = 0;
857 }
858 
859 void
Attach(const void * stream,u32 streamSize)860 ArchiveFontBase::CachedStreamReader::Attach(
861     const void* stream,
862     u32         streamSize
863 )
864 {
865     mStreamBegin    = reinterpret_cast<const u8*>(stream);
866     mStreamPos      = mStreamBegin;
867     mStreamEnd      = mStreamBegin + streamSize;
868 }
869 
870 u32
GetRemain() const871 ArchiveFontBase::CachedStreamReader::GetRemain() const
872 {
873     return static_cast<u32>((mStreamEnd - mStreamPos) + (mpTempStrmBufEnd - mpTempStrmBufPos));
874 }
875 
876 void
Advance(u32 dx)877 ArchiveFontBase::CachedStreamReader::Advance(u32 dx)
878 {
879     const u32 sizeTempStrm = mpTempStrmBufEnd - mpTempStrmBufPos;
880     if (sizeTempStrm > dx)
881     {
882         mpTempStrmBufPos += dx;
883     }
884     else
885     {
886         mpTempStrmBufPos = mpTempStrmBufEnd;
887         mStreamPos += (dx - sizeTempStrm);
888     }
889 }
890 
891 void
CopyTo(ArchiveFontBase::ConstructContext * pContext,u32 size)892 ArchiveFontBase::CachedStreamReader::CopyTo(
893     ArchiveFontBase::ConstructContext*  pContext,
894     u32                                 size
895 )
896 {
897     NN_ASSERT(pContext->GetRemain() >= size);
898 
899     CopyTo(pContext->GetCurrentPtr<void*>(), size);
900     pContext->Advance(size);
901 }
902 
903 void
CopyTo(void * buf,u32 size)904 ArchiveFontBase::CachedStreamReader::CopyTo(
905     void*   buf,
906     u32     size
907 )
908 {
909     NN_ASSERT(size <= GetRemain());
910     const u32 sizeTempStrm = mpTempStrmBufEnd - mpTempStrmBufPos;
911     u8* buf8 = reinterpret_cast<u8*>(buf);
912 
913     if (sizeTempStrm >= size)
914     {
915         std::memcpy(buf8, mpTempStrmBufPos, size);
916         mpTempStrmBufPos += size;
917     }
918     else
919     {
920         const u32 streamCopySize = size - sizeTempStrm;
921         std::memcpy(buf8, mpTempStrmBufPos, static_cast<u32>(sizeTempStrm));
922         std::memcpy(buf8 + sizeTempStrm, mStreamPos, streamCopySize);
923 
924         mpTempStrmBufPos = mpTempStrmBufEnd;
925         mStreamPos += streamCopySize;
926     }
927 }
928 
929 void
MoveTo(void * buf,u32 size)930 ArchiveFontBase::CachedStreamReader::MoveTo(
931     void*   buf,
932     u32     size
933 )
934 {
935     NN_ASSERT(size <= GetRemain());
936     const u32 sizeTempStrm = mpTempStrmBufEnd - mpTempStrmBufPos;
937     u8* buf8 = reinterpret_cast<u8*>(buf);
938 
939     if (sizeTempStrm >= size)
940     {
941         std::memmove(buf8, mpTempStrmBufPos, size);
942         mpTempStrmBufPos += size;
943     }
944     else
945     {
946         const u32 streamCopySize = size - sizeTempStrm;
947         std::memmove(buf8, mpTempStrmBufPos, static_cast<u32>(sizeTempStrm));
948         std::memmove(buf8 + sizeTempStrm, mStreamPos, streamCopySize);
949 
950         mpTempStrmBufPos = mpTempStrmBufEnd;
951         mStreamPos += streamCopySize;
952     }
953 }
954 
955 u32
ManagedCopy(ArchiveFontBase::ConstructContext * pContext)956 ArchiveFontBase::CachedStreamReader::ManagedCopy(ArchiveFontBase::ConstructContext* pContext)
957 {
958     NN_ASSERT(! HasBufData());
959     u32 copySize = math::Min(static_cast<u32>(mStreamEnd - mStreamPos), pContext->TaskRemain());
960 
961     std::memcpy(pContext->GetCurrentPtr<void*>(), mStreamPos, copySize);
962     mStreamPos += copySize;
963     pContext->Advance(copySize);
964     pContext->TaskProceed(copySize);
965 
966     return pContext->TaskRemain();
967 }
968 
969 const void*
Get(u32 size)970 ArchiveFontBase::CachedStreamReader::Get(u32 size)
971 {
972     NN_ASSERT(size <= GetRemain());
973     const void* p = mStreamPos;
974     mStreamPos += size;
975     return p;
976 }
977 
978 bool
RequestData(ArchiveFontBase::ConstructContext * pContext,u32 size)979 ArchiveFontBase::CachedStreamReader::RequestData(
980     ArchiveFontBase::ConstructContext*  pContext,
981     u32                                 size
982 )
983 {
984     // ストリームにはデータが足りない状態でなければならない
985     NN_ASSERT(GetRemain() < size);
986 
987     if (GetRemain() == 0)
988     {
989         // ストリームデータが全くない場合はテンポラリバッファを作成しない
990         mpTempStrmBuf       = NULL;
991         mpTempStrmBufPos    = NULL;
992         mpTempStrmBufEnd    = NULL;
993         mRequireSize        = 0;
994     }
995     else
996     {
997         // テンポラリバッファに必要な空き領域があるかチェック
998         if (pContext->GetRemain() < size * 2)
999         {
1000             // 無ければエラー
1001             return false;
1002         }
1003 
1004         u8* tempBuf = pContext->GetCurrentPtr<u8*>() + size;
1005         u32 curSize = GetRemain();
1006 
1007         // 既にテンポラリバッファが作られている場合があるので CopyTo は使えない
1008         MoveTo(tempBuf, curSize);
1009 
1010         mpTempStrmBuf       = tempBuf;
1011         mpTempStrmBufPos    = mpTempStrmBuf;
1012         mpTempStrmBufEnd    = mpTempStrmBuf + curSize;
1013         mRequireSize        = size;
1014     }
1015 
1016     return true;
1017 }
1018 
1019 u32
GetOffset() const1020 ArchiveFontBase::CachedStreamReader::GetOffset() const
1021 {
1022     return static_cast<u32>((mStreamPos - mStreamBegin) + (mpTempStrmBufPos - mpTempStrmBuf));
1023 }
1024 
1025 
1026 /* =======================================================================
1027         ConstructContext
1028    ======================================================================== */
1029 
1030 void
Init(void * outBuffer,u32 outBufferSize,const char * glyphGroups)1031 ArchiveFontBase::ConstructContext::Init(
1032     void*       outBuffer,
1033     u32         outBufferSize,
1034     const char* glyphGroups
1035 )
1036 {
1037     streamReader.Init();
1038     pGlyphGroups = glyphGroups;
1039     pGlyphIndexAdjustTable = NULL;
1040 
1041     targetBuffer        = reinterpret_cast<u8*>(outBuffer);
1042     targetBufferEnd     = targetBuffer + outBufferSize;
1043     targetBufferCur     = targetBuffer;
1044 
1045     extendContext   = reinterpret_cast<nn::cx::UncompContextHuffman*>(
1046                         math::RoundDown(
1047                             reinterpret_cast<uptr>(targetBufferEnd - sizeof(*extendContext)), 4 ));
1048 
1049     op2             = INVALID_OPERATION;
1050     opSize          = 0;
1051     resNumBlock     = 1;    // GLGR ブロックに DISPATCH するために必要
1052     currentBlock    = 0;
1053 
1054     sheetIndex      = 0;
1055     numSheets       = 0;
1056     glyphsPerSheet  = 0;
1057     streamOffset    = 0;
1058 
1059     pFINF           = NULL;
1060     pPrevCWDH       = NULL;
1061     pPrevCMAP       = NULL;
1062     op              = INVALID_OPERATION;
1063 }
1064 
1065 void
SetGLGR(u16 * pAdjustTable,u16 nSheets,u16 nPerSheet,u32 numBlock)1066 ArchiveFontBase::ConstructContext::SetGLGR(
1067     u16*        pAdjustTable,
1068     u16         nSheets,
1069     u16         nPerSheet,
1070     u32         numBlock
1071 )
1072 {
1073     pGlyphIndexAdjustTable  = pAdjustTable;
1074     numSheets               = nSheets;
1075     glyphsPerSheet          = nPerSheet;
1076     resNumBlock             = numBlock;
1077 }
1078 
1079 void
Finish(void ** ppData,FontInformation ** ppFontInfo,u16 ** ppAdjustTable)1080 ArchiveFontBase::ConstructContext::Finish(
1081     void**              ppData,
1082     FontInformation**   ppFontInfo,
1083     u16**               ppAdjustTable
1084 )
1085 {
1086     *ppData         = targetBuffer;
1087     *ppAdjustTable  = pGlyphIndexAdjustTable;
1088     *ppFontInfo     = pFINF;
1089 }
1090 
1091 
1092 /* =======================================================================
1093         FontGlyphGroupsAcs
1094    ======================================================================== */
1095 
FontGlyphGroupsAcs(const void * bfnt)1096 ArchiveFontBase::FontGlyphGroupsAcs::FontGlyphGroupsAcs(const void* bfnt)
1097 {
1098     mpHeader = reinterpret_cast<const ut::BinaryFileHeader*>(bfnt);
1099     mpData = reinterpret_cast<const FontGlyphGroupsBlock*>(mpHeader + 1);
1100 
1101     mSizeSheetFlags = sizeof(u32) * math::DivUp(mpData->body.numSheet, (u16)32);
1102     mSizeCWDHFlags  = sizeof(u32) * math::DivUp(mpData->body.numCWDH, (u16)32);
1103     mSizeCMAPFlags  = sizeof(u32) * math::DivUp(mpData->body.numCMAP, (u16)32);
1104 
1105     // FontGlyphGroups はヘッダでは中途半端に定義されているため
1106     // 正確なサイズを得るためにオフセットで計算する
1107     const u32 sizePreBlock      = sizeof(ut::BinaryFileHeader) + sizeof(ut::BinaryBlockHeader);
1108     const u32 sizeStatic        = reinterpret_cast<u32>(reinterpret_cast<FontGlyphGroups*>(0)->nameOffsets);
1109     const u32 sizeNameOffsets   = sizeof(u16) * mpData->body.numSet;
1110     const u32 sizeSizeSheets    = sizeof(u32) * mpData->body.numSheet;
1111     const u32 sizeSizeCWDH      = sizeof(u32) * mpData->body.numCWDH;
1112     const u32 sizeSizeCMAP      = sizeof(u32) * mpData->body.numCMAP;
1113     const u32 sizeUseSheets     = mSizeSheetFlags * mpData->body.numSet;
1114     const u32 sizeUseCWDH       = mSizeCWDHFlags * mpData->body.numSet;
1115 //            const u32 sizeUseCMAP       = mSizeCMAPFlags * numSet;
1116 
1117     const u32 offsetStatic      = math::RoundUp(sizePreBlock, 2);
1118     const u32 offsetNameOffsets = math::RoundUp(offsetStatic     + sizeStatic,        2);
1119     const u32 offsetSizeSheets  = math::RoundUp(offsetNameOffsets+ sizeNameOffsets,   4);
1120     const u32 offsetSizeCWDH    = math::RoundUp(offsetSizeSheets + sizeSizeSheets,    4);
1121     const u32 offsetSizeCMAP    = math::RoundUp(offsetSizeCWDH   + sizeSizeCWDH,      4);
1122     const u32 offsetUseSheets   = math::RoundUp(offsetSizeCMAP   + sizeSizeCMAP,      4);
1123     const u32 offsetUseCWDH     = math::RoundUp(offsetUseSheets  + sizeUseSheets,     4);
1124     const u32 offsetUseCMAP     = math::RoundUp(offsetUseCWDH    + sizeUseCWDH,       4);
1125 
1126     mpSizeSheetsArray   = reinterpret_cast<const u32*>(ut::AddOffsetToPtr(mpHeader, offsetSizeSheets));
1127     mpSizeCWDHArray     = reinterpret_cast<const u32*>(ut::AddOffsetToPtr(mpHeader, offsetSizeCWDH));
1128     mpSizeCMAPArray     = reinterpret_cast<const u32*>(ut::AddOffsetToPtr(mpHeader, offsetSizeCMAP));
1129     mpUseSheetArray     = reinterpret_cast<const u32*>(ut::AddOffsetToPtr(mpHeader, offsetUseSheets));
1130     mpUseCWDHArray      = reinterpret_cast<const u32*>(ut::AddOffsetToPtr(mpHeader, offsetUseCWDH));
1131     mpUseCMAPArray      = reinterpret_cast<const u32*>(ut::AddOffsetToPtr(mpHeader, offsetUseCMAP));
1132 }
1133 
1134 }   // namespace font
1135 }   // namespace nw
1136