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