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