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