1/*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: savedata_calc.js 4 5 Copyright (C)2009 Nintendo Co., Ltd. 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 $Rev:$ 14 *---------------------------------------------------------------------------*/ 15 16/*===========================================================================*/ 17/*! 18 @brief アラインメント調整用関数 19*/ 20function AdjustAlignment(val, alignment) 21{ 22 return ((val + (alignment - 1)) & ~(alignment - 1)); 23}; 24 25/*===========================================================================*/ 26/*! 27 @brief ビット列の左側からの連続する 0 のビットの数を数えます。 28*/ 29function CntLz(val) 30{ 31 var x = 0; 32 33 var n = 32; 34 var c = 16; 35 do 36 { 37 x = val >> c; 38 if (x != 0) 39 { 40 n -= c; 41 val = x; 42 } 43 c >>= 1; 44 } while(c != 0); 45 46 return (n - val); 47}; 48 49/*---------------------------------------------------------------------------*/ 50/*! 51 @brief 値が 2 の整数乗かどうかを判定します。 52*/ 53function IsPwr2(val) 54{ 55 return (0 == (val & (val - 1))); 56}; 57 58/*---------------------------------------------------------------------------*/ 59/*! 60 @brief 整数の 2 を底とする対数を計算し、結果を整数で返します。 61*/ 62function ILog2(val) 63{ 64 return 31 - CntLz(val); 65}; 66 67/*---------------------------------------------------------------------------*/ 68/*! 69 @brief 例外定義 70*/ 71function ResultInvalidArgument() 72{ 73}; 74 75/*===========================================================================*/ 76/*! 77 @brief エントリマップテーブル 78 @ref EntryMapTable 79*/ 80function EntryMapTable() 81{ 82}; 83 84/*---------------------------------------------------------------------------*/ 85 86EntryMapTable.STORAGE_SYSTEM_RESERVED = 1; 87 88EntryMapTable.DIRECTORY_SYSTEM_RESERVED = 1; 89EntryMapTable.FILE_SYSTEM_RESERVED = 0; 90 91EntryMapTable.INDEX_SIZE = 4; // sizeof(u32) 92EntryMapTable.STORAGE_INDEX_SIZE = 4; // sizeof(u32) 93 94EntryMapTable.DIRECTORY_NAME_SIZE = 16; 95EntryMapTable.FILE_NAME_SIZE = 16; 96 97EntryMapTable.DIRECTORY_INFO_SIZE = 4; // sizeof(bit8[4]) 98 99EntryMapTable.FILE_SYSTEM_INFO_SIZE = 4 + // sizeof(u32) 100 8; // sizeof(S64) 101EntryMapTable.FILE_OPTIONAL_INFO_SIZE = 4; // sizeof(bit8[4]) 102EntryMapTable.FILE_INFO_SIZE = EntryMapTable.FILE_NAME_SIZE; 103 104EntryMapTable.DIRECTORY_KEY_SIZE = EntryMapTable.STORAGE_INDEX_SIZE + 105 EntryMapTable.DIRECTORY_NAME_SIZE; 106EntryMapTable.DIRECTORY_VALUE_SIZE = EntryMapTable.STORAGE_INDEX_SIZE + 107 EntryMapTable.STORAGE_INDEX_SIZE + 108 EntryMapTable.STORAGE_INDEX_SIZE + 109 EntryMapTable.DIRECTORY_INFO_SIZE; 110 111EntryMapTable.FILE_KEY_SIZE = EntryMapTable.STORAGE_INDEX_SIZE + 112 EntryMapTable.DIRECTORY_NAME_SIZE; 113EntryMapTable.FILE_VALUE_SIZE = EntryMapTable.STORAGE_INDEX_SIZE + 114 4 + // PADDING4 115 EntryMapTable.FILE_INFO_SIZE; 116 117EntryMapTable.DIRECTORY_STORAGE_ELEMENT_SIZE = EntryMapTable.DIRECTORY_KEY_SIZE + 118 EntryMapTable.DIRECTORY_VALUE_SIZE + 119 EntryMapTable.INDEX_SIZE; 120 121EntryMapTable.FILE_STORAGE_ELEMENT_SIZE = EntryMapTable.FILE_KEY_SIZE + 122 EntryMapTable.FILE_VALUE_SIZE + 123 EntryMapTable.INDEX_SIZE; 124 125/*---------------------------------------------------------------------------*/ 126 127EntryMapTable.QueryDirectoryEntryStorageSize = function(countDirectoryEntry) 128{ 129 return ((countDirectoryEntry + EntryMapTable.DIRECTORY_SYSTEM_RESERVED) 130 + EntryMapTable.STORAGE_SYSTEM_RESERVED) * EntryMapTable.DIRECTORY_STORAGE_ELEMENT_SIZE; 131}; 132 133/*---------------------------------------------------------------------------*/ 134 135EntryMapTable.QueryFileEntryStorageSize = function(countFileEntry) 136{ 137 return ((countFileEntry + EntryMapTable.FILE_SYSTEM_RESERVED) 138 + EntryMapTable.STORAGE_SYSTEM_RESERVED) * EntryMapTable.FILE_STORAGE_ELEMENT_SIZE; 139}; 140 141/*---------------------------------------------------------------------------*/ 142 143EntryMapTable.QueryDirectoryEntryBucketStorageSize = function(countDirectoryBucket) 144{ 145 return countDirectoryBucket * EntryMapTable.INDEX_SIZE; 146}; 147 148/*---------------------------------------------------------------------------*/ 149 150EntryMapTable.QueryFileEntryBucketStorageSize = function(countFileBucket) 151{ 152 return countFileBucket * EntryMapTable.INDEX_SIZE; 153}; 154 155/*===========================================================================*/ 156/*! 157 @brief アロケーションテーブル 158 @ref AllocationTableTemplate 159*/ 160function AllocationTable() 161{ 162}; 163 164/*---------------------------------------------------------------------------*/ 165 166AllocationTable.SECTOR_RESERVED_COUNT = 1; 167 168AllocationTable.TABLE_ELEMENT_SIZE = 4 // sizeof(u32) 169 + 4;// sizeof(u32) 170 171/*---------------------------------------------------------------------------*/ 172 173AllocationTable.QuerySize = function(blockCount) 174{ 175 return (blockCount + AllocationTable.SECTOR_RESERVED_COUNT) 176 * AllocationTable.TABLE_ELEMENT_SIZE; 177}; 178 179/*===========================================================================*/ 180/*! 181 @brief ファイルシステム管理情報 182 @ref HierarchicalDuplexFile 183*/ 184function FileSystemControlArea() 185{ 186}; 187 188/*---------------------------------------------------------------------------*/ 189 190FileSystemControlArea.STORAGE_INFO_SIZE = 8 // sizeof(s64) 191 + 4 // sizeof(u32) 192 + 4;// PADDING4 193 194FileSystemControlArea.ALLOCATION_INFO_SIZE = 4 // sizeof(u32) 195 + 4 // sizeof(size_t) 196 + 4 // sizeof(u32) 197 + 4;// PADDING4 198 199/*---------------------------------------------------------------------------*/ 200 201FileSystemControlArea.QuerySize = function() 202{ 203 var STORAGE_OR_ALLOCATION_INFO_SIZE = FileSystemControlArea.STORAGE_INFO_SIZE; 204 if (FileSystemControlArea.STORAGE_INFO_SIZE < FileSystemControlArea.ALLOCATION_INFO_SIZE) 205 { 206 STORAGE_OR_ALLOCATION_INFO_SIZE = FileSystemControlArea.ALLOCATION_INFO_SIZE; 207 } 208 209 return (4 210 + 4 211 + FileSystemControlArea.STORAGE_INFO_SIZE 212 + FileSystemControlArea.STORAGE_INFO_SIZE 213 + FileSystemControlArea.STORAGE_INFO_SIZE 214 + FileSystemControlArea.STORAGE_INFO_SIZE 215 + STORAGE_OR_ALLOCATION_INFO_SIZE 216 + STORAGE_OR_ALLOCATION_INFO_SIZE); 217}; 218 219/*===========================================================================*/ 220/*! 221 @brief 階層化二重化ファイル 222 @ref HierarchicalDuplexFile 223*/ 224function HierarchicalDuplexFile() 225{ 226}; 227 228/*---------------------------------------------------------------------------*/ 229 230HierarchicalDuplexFile.DPFS_BITMAP_ALIGN = 4; 231HierarchicalDuplexFile.MAX_LAYERS = 3; // Master, L1, BODY 232 233HierarchicalDuplexFile.LEVEL_INFO_SIZE = 8 // sizeof(Int64) 234 + 8 // sizeof(Int64) 235 + 4 // sizeof(s32) 236 + 4;// PADDING4 237 238HierarchicalDuplexFile.INFOMATION_SIZE = HierarchicalDuplexFile.LEVEL_INFO_SIZE 239 * HierarchicalDuplexFile.MAX_LAYERS; 240 241HierarchicalDuplexFile.META_INFO_SIZE = 4 // sizeof(u32) 242 + 4 // sizeof(u32) 243 + HierarchicalDuplexFile.INFOMATION_SIZE 244 245/*---------------------------------------------------------------------------*/ 246 247HierarchicalDuplexFile.InputParam = function() 248{ 249 this.sizeBlockLevel = new Array(2); 250}; 251 252/*---------------------------------------------------------------------------*/ 253 254HierarchicalDuplexFile.LevelInfomation = function() 255{ 256 this.offset = 0; 257 this.size = 0; 258 this.orderBlock = 0; 259}; 260 261/*---------------------------------------------------------------------------*/ 262 263HierarchicalDuplexFile.QuerySizeResult = function() 264{ 265 this.sizeControlArea = 0; 266 this.sizeBody = 0; 267}; 268 269/*---------------------------------------------------------------------------*/ 270 271HierarchicalDuplexFile.QuerySize = function( 272 outResult, 273 inputParam, 274 sizeData 275 ) 276{ 277 if (inputParam.sizeBlockLevel[0] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[0]) 278 || inputParam.sizeBlockLevel[1] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[1])) 279 { 280 throw new ResultInvalidArgument(); 281 } 282 283 if (0 != (sizeData % inputParam.sizeBlockLevel[1])) 284 { 285 throw new ResultInvalidArgument(); 286 } 287 288 if (inputParam.sizeBlockLevel[0] < HierarchicalDuplexFile.DPFS_BITMAP_ALIGN 289 || inputParam.sizeBlockLevel[1] < HierarchicalDuplexFile.DPFS_BITMAP_ALIGN) 290 { 291 throw new ResultInvalidArgument(); 292 } 293 294 // 管理領域サイズが確定 295 outResult.sizeControlArea = HierarchicalDuplexFile.META_INFO_SIZE; 296 297 var MAX_LEVEL = HierarchicalDuplexFile.MAX_LAYERS; 298 299 var sizeLevel = new Array(MAX_LEVEL); 300 // Body 301 sizeLevel[2] = sizeData; 302 // bit単位のデータサイズ 303 sizeLevel[1] = Math.floor(((sizeLevel[2] + inputParam.sizeBlockLevel[1] - 1) / inputParam.sizeBlockLevel[1])); 304 // bit -> byteに変換します 305 sizeLevel[1] = Math.floor((sizeLevel[1] + 7) / 8); 306 // サイズをL1ブロック境界に整合します 307 sizeLevel[1] = AdjustAlignment(sizeLevel[1], inputParam.sizeBlockLevel[0]); 308 // bit 309 sizeLevel[0] = Math.floor(((sizeLevel[1] + inputParam.sizeBlockLevel[0] - 1) / inputParam.sizeBlockLevel[0])); 310 // bit -> byte 311 sizeLevel[0] = Math.floor((sizeLevel[0] + 7) / 8); 312 // サイズを DPFS_BITMAP_ALIGN バイト境界に整合します 313 sizeLevel[0] = AdjustAlignment(sizeLevel[0], HierarchicalDuplexFile.DPFS_BITMAP_ALIGN); 314 315 var orderBlock = new Array(MAX_LEVEL); 316 317 orderBlock[0] = 0; 318 orderBlock[1] = ILog2(inputParam.sizeBlockLevel[0]); 319 orderBlock[2] = ILog2(inputParam.sizeBlockLevel[1]); 320 321 // Master, L1 は少なくとも DPFS_BITMAP_ALIGN に整合しています。 322 var offset = 0; 323 324 var levelInfo = new Array(MAX_LEVEL); 325 var level; 326 327 for (level = 0; level < MAX_LEVEL; level++) 328 { 329 levelInfo[level] = new HierarchicalDuplexFile.LevelInfomation(); 330 331 // 実データはL2ブロックサイズに整合しておきます。 332 if (level == MAX_LEVEL - 1) 333 { 334 offset = AdjustAlignment(offset, inputParam.sizeBlockLevel[1]); 335 } 336 337 levelInfo[level].offset = offset; 338 levelInfo[level].size = sizeLevel[level]; 339 levelInfo[level].orderBlock = orderBlock[level]; 340 offset += sizeLevel[level] * 2; 341 } 342 343 // 実データのサイズが確定 344 outResult.sizeBody = offset; 345}; 346 347/*===========================================================================*/ 348/*! 349 @brief 階層化完全性検証ファイル 350 @ref HierarchicalDuplexFile 351*/ 352function HierarchicalIntegrityVerificationFile() 353{ 354}; 355 356/*---------------------------------------------------------------------------*/ 357 358HierarchicalIntegrityVerificationFile.HASH_SIZE = Math.floor(256 / 8); 359HierarchicalIntegrityVerificationFile.MAX_LAYERS = 5; // Master, L1, L2, L3, BODY 360 361HierarchicalIntegrityVerificationFile.LEVEL_INFO_SIZE = 8 // sizeof(Int64) 362 + 8 // sizeof(Int64) 363 + 4 // sizeof(s32) 364 + 4;// PADDING4 365HierarchicalIntegrityVerificationFile.INFOMATION_SIZE = 4 // sizeof(u32) 366 + HierarchicalIntegrityVerificationFile.LEVEL_INFO_SIZE 367 * (HierarchicalIntegrityVerificationFile.MAX_LAYERS - 1); 368HierarchicalIntegrityVerificationFile.META_INFO_SIZE = 4 // sizeof(u32) 369 + 4 // sizeof(u32) 370 + 4 // sizeof(u32) 371 + HierarchicalIntegrityVerificationFile.INFOMATION_SIZE 372 + 4 // sizeof(u32) 373 + 4; // sizeof(u32) 374 375/*---------------------------------------------------------------------------*/ 376 377HierarchicalIntegrityVerificationFile.InputParam = function() 378{ 379 this.sizeOptionalInfo = 0; 380 this.sizeBlockLevel = new Array(HierarchicalIntegrityVerificationFile.MAX_LAYERS - 1); 381}; 382 383/*---------------------------------------------------------------------------*/ 384 385HierarchicalIntegrityVerificationFile.LevelInfomation = function() 386{ 387 this.offset = 0; 388 this.size = 0; 389 this.orderBlock = 0; 390}; 391 392/*---------------------------------------------------------------------------*/ 393 394HierarchicalIntegrityVerificationFile.QuerySizeResult = function() 395{ 396 this.sizeControlArea = 0; 397 this.sizeMasterHash = 0; 398 this.sizeLayerdHash = 0; 399 this.sizeBody = 0; 400 this.sizeTotal = 0; 401}; 402 403/*---------------------------------------------------------------------------*/ 404 405HierarchicalIntegrityVerificationFile.QuerySize = function( 406 outResult, 407 inputParam, 408 sizeData 409 ) 410{ 411 if (inputParam.sizeBlockLevel[0] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[0]) 412 || inputParam.sizeBlockLevel[1] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[1]) 413 || inputParam.sizeBlockLevel[2] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[2]) 414 || inputParam.sizeBlockLevel[3] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[3])) 415 { 416 throw new ResultInvalidArgument(); 417 } 418 419 var offset = 0; 420 offset += HierarchicalIntegrityVerificationFile.META_INFO_SIZE; 421 offset = AdjustAlignment(offset, 4); 422 423 offset += inputParam.sizeOptionalInfo; 424 // 管理領域サイズが確定 425 outResult.sizeControlArea = offset; 426 427 var MAX_LEVEL = HierarchicalIntegrityVerificationFile.MAX_LAYERS; 428 var HASH_SIZE = HierarchicalIntegrityVerificationFile.HASH_SIZE; 429 430 var sizeLevel = new Array(MAX_LEVEL); 431 432 // Body 433 sizeLevel[4] = sizeData; 434 // L3 435 sizeLevel[3] = Math.floor(((sizeLevel[4] + inputParam.sizeBlockLevel[3] - 1) / inputParam.sizeBlockLevel[3])) * HASH_SIZE; 436 // L2 437 sizeLevel[2] = Math.floor(((sizeLevel[3] + inputParam.sizeBlockLevel[2] - 1) / inputParam.sizeBlockLevel[2])) * HASH_SIZE; 438 // L1 439 sizeLevel[1] = Math.floor(((sizeLevel[2] + inputParam.sizeBlockLevel[1] - 1) / inputParam.sizeBlockLevel[1])) * HASH_SIZE; 440 // Master 441 sizeLevel[0] = Math.floor(((sizeLevel[1] + inputParam.sizeBlockLevel[0] - 1) / inputParam.sizeBlockLevel[0])) * HASH_SIZE; 442 443 var orderBlock = new Array(MAX_LEVEL); 444 445 orderBlock[1] = ILog2(inputParam.sizeBlockLevel[0]); 446 orderBlock[2] = ILog2(inputParam.sizeBlockLevel[1]); 447 orderBlock[3] = ILog2(inputParam.sizeBlockLevel[2]); 448 orderBlock[4] = ILog2(inputParam.sizeBlockLevel[3]); 449 450 // マスターハッシュサイズが確定 451 outResult.sizeMasterHash = sizeLevel[0]; 452 453 // レベル情報を構築 454 var levelInfo = new Array(MAX_LEVEL); 455 var level; 456 457 offset = 0; 458 for (level = 1; level < MAX_LEVEL; level++) 459 { 460 levelInfo[level - 1] = new HierarchicalIntegrityVerificationFile.LevelInfomation(); 461 462 if (sizeLevel[level] >= (4 << orderBlock[level])) 463 { 464 offset = AdjustAlignment(offset, 1 << orderBlock[level]); 465 } 466 else 467 { 468 offset = AdjustAlignment(offset, 8/*sizeof(s64)*/); 469 } 470 471 levelInfo[level - 1].offset = offset; 472 levelInfo[level - 1].size = sizeLevel[level]; 473 levelInfo[level - 1].orderBlock = orderBlock[level]; 474 offset += sizeLevel[level]; 475 } 476 477 // レイヤーハッシュサイズが確定 478 outResult.sizeLayeredHash = levelInfo[MAX_LEVEL - 3].offset 479 + levelInfo[MAX_LEVEL - 3].size 480 - levelInfo[0].offset; 481 482 // 実データのサイズが確定 483 outResult.sizeBody = levelInfo[MAX_LEVEL - 2].size; 484 485 // トータルサイズが確定 486 outResult.sizeTotal = levelInfo[MAX_LEVEL - 2].offset 487 + levelInfo[MAX_LEVEL - 2].size 488 - levelInfo[0].offset; 489}; 490 491/*===========================================================================*/ 492/*! 493 @brief 二重化+完全性検証ファイル 494 @ref DuplicatedIntegrityFile 495*/ 496function DuplicatedIntegrityFile() 497{ 498}; 499 500/*---------------------------------------------------------------------------*/ 501 502DuplicatedIntegrityFile.META_INFO_SIZE = 4 // sizeof(u32) 503 + 4 // sizeof(u32) 504 + 8 // sizeof(Int64) 505 + 8 // sizeof(Int64) 506 + 8 // sizeof(Int64) 507 + 8 // sizeof(Int64) 508 + 8 // sizeof(Int64) 509 + 8 // sizeof(Int64) 510 + 1 // sizeof(bool) 511 + 1 // sizeof(bool) 512 + 2 // PADDING2 513 + 8;// sizeof(Int64) 514 515/*---------------------------------------------------------------------------*/ 516 517DuplicatedIntegrityFile.QuerySizeResult = function() 518{ 519 this.sizeControlArea = 0; 520 this.sizeTotalBody = 0; 521}; 522 523/*---------------------------------------------------------------------------*/ 524 525DuplicatedIntegrityFile.QuerySize = function( 526 outResult, 527 inputParamDuplex, 528 inputParamIntegrity, 529 sizeOriginalData, 530 isDuplicateOnlyHash 531 ) 532{ 533 // 階層化完全性検証ファイルのサイズを計算します。 534 var resultIntegrity = new HierarchicalIntegrityVerificationFile.QuerySizeResult(); 535 536 HierarchicalIntegrityVerificationFile.QuerySize( 537 resultIntegrity, 538 inputParamIntegrity, 539 sizeOriginalData 540 ); 541 542 var sizeDuplicateOriginal = 0; 543 544 if (!isDuplicateOnlyHash) 545 { 546 sizeDuplicateOriginal = AdjustAlignment(resultIntegrity.sizeTotal, inputParamDuplex.sizeBlockLevel[1]); 547 } 548 else 549 { 550 sizeDuplicateOriginal = AdjustAlignment(resultIntegrity.sizeLayeredHash, inputParamDuplex.sizeBlockLevel[1]); 551 } 552 553 // 階層化二重化ファイルのサイズを計算します。 554 var resultDuplex = new HierarchicalDuplexFile.QuerySizeResult(); 555 556 HierarchicalDuplexFile.QuerySize( 557 resultDuplex, 558 inputParamDuplex, 559 sizeDuplicateOriginal 560 ); 561 562 // 二重化+完全性検証ファイルのサイズを計算します。 563 var offsetOriginalData; 564 if (!isDuplicateOnlyHash) 565 { 566 offsetOriginalData = 0; 567 outResult.sizeTotalBody = resultDuplex.sizeBody; 568 } 569 else 570 { 571 // 二重化した署名データの後ろに実データを配置 572 offsetOriginalData = AdjustAlignment(resultDuplex.sizeBody, inputParamIntegrity.sizeBlockLevel[3]); 573 outResult.sizeTotalBody = offsetOriginalData + sizeOriginalData; 574 } 575 576 // メタ情報 577 var offset = DuplicatedIntegrityFile.META_INFO_SIZE; 578 579 // 完全性検証レイヤー管理領域 580 offset = AdjustAlignment(offset, 4); 581 offset += resultIntegrity.sizeControlArea; 582 583 // 二重化レイヤー管理領域 584 offset = AdjustAlignment(offset, 4); 585 offset += resultDuplex.sizeControlArea; 586 587 // マスター署名 588 offset = AdjustAlignment(offset, 4); 589 offset += resultIntegrity.sizeMasterHash; 590 591 // 最終的な管理領域のサイズ 592 outResult.sizeControlArea = offset; 593}; 594 595/*===========================================================================*/ 596/*! 597 @brief 二重化+完全性検証フィルタファイル 598 @ref DuplicatedIntegrityFile 599*/ 600function DuplicatedIntegrityFilterFile() 601{ 602}; 603 604/*---------------------------------------------------------------------------*/ 605 606DuplicatedIntegrityFilterFile.ATOMIC_HEADER_SIZE = 512; 607 608/*---------------------------------------------------------------------------*/ 609 610DuplicatedIntegrityFilterFile.QuerySizeResult = function() 611{ 612 this.sizeTotalBody = 0; 613}; 614 615/*---------------------------------------------------------------------------*/ 616 617DuplicatedIntegrityFilterFile.QuerySize = function( 618 outResult, 619 inputParamDuplex, 620 inputParamIntegrity, 621 sizeOriginalData, 622 isDuplicateOnlyHash 623 ) 624{ 625 // フィルタファイルではオプション領域は使用しません。 626 inputParamDuplex.sizeOptionalInfo = 0; 627 628 // 検証機能つき二重化ファイル管理領域のサイズを取得します。 629 var resultDupInt = new DuplicatedIntegrityFile.QuerySizeResult(); 630 DuplicatedIntegrityFile.QuerySize( 631 resultDupInt, 632 inputParamDuplex, 633 inputParamIntegrity, 634 sizeOriginalData, 635 isDuplicateOnlyHash 636 ); 637 638 var offset = DuplicatedIntegrityFilterFile.ATOMIC_HEADER_SIZE; 639 640 // 二重化された管理領域A 641 offset = AdjustAlignment(offset, 8/*sizeof(s64)*/); 642 offset += resultDupInt.sizeControlArea; 643 644 // 二重化された管理領域B 645 offset = AdjustAlignment(offset, 8/*sizeof(s64)*/); 646 offset += resultDupInt.sizeControlArea; 647 648 var maxBlockSize = ((inputParamDuplex.sizeBlockLevel[0] - 1) | 649 (inputParamDuplex.sizeBlockLevel[1] - 1) | 650 (inputParamIntegrity.sizeBlockLevel[0] - 1) | 651 (inputParamIntegrity.sizeBlockLevel[1] - 1) | 652 (inputParamIntegrity.sizeBlockLevel[2] - 1) | 653 (inputParamIntegrity.sizeBlockLevel[3] - 1)) + 1; 654 655 // パディングを挿入しつつ、検証機能つき二重化ファイルの管理領域の後に 656 // データ部を配置します。 657 offset = AdjustAlignment(offset, maxBlockSize); 658 offset += resultDupInt.sizeTotalBody;; 659 660 // 最終的なサイズを返します。 661 outResult.sizeTotalBody = offset; 662}; 663 664/*===========================================================================*/ 665/*! 666 @brief ファイル ID をパスとするアーカイブを文字列パスを用いて透過的に扱うためのアーカイブクラス 667 @ref WStringOnBit64PathStorageArchive 668*/ 669function WStringOnBit64PathStorageArchive() 670{ 671}; 672 673/*---------------------------------------------------------------------------*/ 674 675WStringOnBit64PathStorageArchive.MAX_PATH_LENGTH = 256; 676 677WStringOnBit64PathStorageArchive.ARCHIVE_HEADER_SIZE = 4 // sizeof(u32) 678 + 4 // sizeof(u32) 679 + 8 // sizeof(s64) 680 + 8 // sizeof(s64) 681 + 4 // sizeof(u32) 682 + 4 // PADDING4 683 + 8 684 + ( 685 4 // sizeof(bit32) 686 + 8 // sizeof(FileId) -> sizeof(bit64) 687 + WStringOnBit64PathStorageArchive.MAX_PATH_LENGTH 688 ) // sizeof(transaction) 689 ; 690 691/*---------------------------------------------------------------------------*/ 692 693WStringOnBit64PathStorageArchive.QueryHeaderSize = function() 694{ 695 return WStringOnBit64PathStorageArchive.ARCHIVE_HEADER_SIZE; 696}; 697 698/*---------------------------------------------------------------------------*/ 699 700WStringOnBit64PathStorageArchive.QueryFileSystemControlAreaSize = function() 701{ 702 return FileSystemControlArea.QuerySize(); 703}; 704 705/*---------------------------------------------------------------------------*/ 706 707WStringOnBit64PathStorageArchive.QueryDirectoryEntryStorageSize = function(countDirectoryEntry) 708{ 709 return EntryMapTable.QueryDirectoryEntryStorageSize(countDirectoryEntry); 710}; 711 712/*---------------------------------------------------------------------------*/ 713 714WStringOnBit64PathStorageArchive.QueryDirectoryEntryBucketStorageSize = function(countDirectoryBucket) 715{ 716 return EntryMapTable.QueryDirectoryEntryBucketStorageSize(countDirectoryBucket); 717}; 718 719/*---------------------------------------------------------------------------*/ 720 721WStringOnBit64PathStorageArchive.QueryFileEntryStorageSize = function(countFileEntry) 722{ 723 return EntryMapTable.QueryFileEntryStorageSize(countFileEntry); 724}; 725 726/*---------------------------------------------------------------------------*/ 727 728WStringOnBit64PathStorageArchive.QueryFileEntryBucketStorageSize = function(countFileBucket) 729{ 730 return EntryMapTable.QueryFileEntryBucketStorageSize(countFileBucket); 731}; 732 733/*---------------------------------------------------------------------------*/ 734 735WStringOnBit64PathStorageArchive.QueryAllocationTableStorageSize = function(countDataBlock) 736{ 737 return AllocationTable.QuerySize(countDataBlock); 738}; 739 740/*---------------------------------------------------------------------------*/ 741 742WStringOnBit64PathStorageArchive.QueryOptimalBucketCount = function(countEntries) 743{ 744 if (countEntries <= 3) 745 { 746 // エントリー数が極めて少ない場合、バケット数は固定サイズを返します。 747 return 3; 748 } 749 if (countEntries <= 19) 750 { 751 // エントリー数が 20 個未満の場合、奇数にして返します。 752 return countEntries | 1; 753 } 754 755 // エントリー数が20個を超える場合、バケットの分散具合を考慮し、 756 // 小さな値の素数で枝狩りを行います。 757 var i; 758 for (i = 0;i < 100;i++) 759 { 760 var candidate = (countEntries + i); 761 if ( 762 (candidate % 2) != 0 && 763 (candidate % 3) != 0 && 764 (candidate % 5) != 0 && 765 (candidate % 7) != 0 && 766 (candidate % 11) != 0 && 767 (candidate % 13) != 0 && 768 (candidate % 17) != 0 769 ) 770 { 771 return candidate; 772 } 773 } 774 return countEntries | 1; 775}; 776 777/*---------------------------------------------------------------------------*/ 778 779WStringOnBit64PathStorageArchive.QueryTotalSize = function( 780 countDirectoryEntry, 781 countDirectoryEntryBucket, 782 countFileEntry, 783 countFileEntryBucket, 784 sizeBlock 785 ) 786{ 787 var sizeDirectoryEntry = WStringOnBit64PathStorageArchive.QueryDirectoryEntryStorageSize(countDirectoryEntry); 788 var blockCountDirectoryEntry = Math.floor((sizeDirectoryEntry + sizeBlock - 1) / sizeBlock); 789 var sizeFileEntry = WStringOnBit64PathStorageArchive.QueryFileEntryStorageSize(countFileEntry); 790 var blockCountFileEntry = Math.floor((sizeFileEntry + sizeBlock - 1) / sizeBlock); 791 var sizeFixed = 792 WStringOnBit64PathStorageArchive.QueryHeaderSize() + 793 WStringOnBit64PathStorageArchive.QueryFileSystemControlAreaSize() + 794 WStringOnBit64PathStorageArchive.QueryDirectoryEntryBucketStorageSize(countDirectoryEntryBucket) + 795 WStringOnBit64PathStorageArchive.QueryFileEntryBucketStorageSize(countFileEntryBucket) + 796 WStringOnBit64PathStorageArchive.QueryAllocationTableStorageSize(blockCountDirectoryEntry + blockCountFileEntry) 797 ; 798 sizeFixed = AdjustAlignment(sizeFixed, sizeBlock); 799 return sizeFixed + sizeBlock * (blockCountDirectoryEntry + blockCountFileEntry); 800} 801 802/*===========================================================================*/ 803/*! 804 @brief セーブデータアーカイブクラス 805 @ref SaveDataArchiveTemplate 806*/ 807function SaveDataArchive() 808{ 809}; 810 811/*---------------------------------------------------------------------------*/ 812 813SaveDataArchive.ARCHIVE_HEADER_SIZE = 4 // sizeof(u32) 814 + 4 // sizeof(u32) 815 + 8 // sizeof(s64) 816 + 8 // sizeof(s64) 817 + 4 // sizeof(u32) 818 + 4;// PADDING4 819 820/*---------------------------------------------------------------------------*/ 821 822SaveDataArchive.QueryHeaderSize = function() 823{ 824 return SaveDataArchive.ARCHIVE_HEADER_SIZE; 825}; 826 827/*---------------------------------------------------------------------------*/ 828 829SaveDataArchive.QueryFileSystemControlAreaSize = function() 830{ 831 return FileSystemControlArea.QuerySize(); 832}; 833 834/*---------------------------------------------------------------------------*/ 835 836SaveDataArchive.QueryDirectoryEntryStorageSize = function(countDirectoryEntry) 837{ 838 return EntryMapTable.QueryDirectoryEntryStorageSize(countDirectoryEntry); 839}; 840 841/*---------------------------------------------------------------------------*/ 842 843SaveDataArchive.QueryDirectoryEntryBucketStorageSize = function(countDirectoryBucket) 844{ 845 return EntryMapTable.QueryDirectoryEntryBucketStorageSize(countDirectoryBucket); 846}; 847 848/*---------------------------------------------------------------------------*/ 849 850SaveDataArchive.QueryFileEntryStorageSize = function(countFileEntry) 851{ 852 return EntryMapTable.QueryFileEntryStorageSize(countFileEntry); 853}; 854 855/*---------------------------------------------------------------------------*/ 856 857SaveDataArchive.QueryFileEntryBucketStorageSize = function(countFileBucket) 858{ 859 return EntryMapTable.QueryFileEntryBucketStorageSize(countFileBucket); 860}; 861 862/*---------------------------------------------------------------------------*/ 863 864SaveDataArchive.QueryAllocationTableStorageSize = function(countDataBlock) 865{ 866 return AllocationTable.QuerySize(countDataBlock); 867}; 868 869/*---------------------------------------------------------------------------*/ 870 871SaveDataArchive.QueryOptimalBucketCount = function(countEntries) 872{ 873 // TODO: WStringOnBit64PathStorageArchive.QueryOptimalBucketCount に統一することを検討 874 if (countEntries <= 3) 875 { 876 // エントリー数が極めて少ない場合、バケット数は固定サイズを返します。 877 return 3; 878 } 879 if (countEntries <= 19) 880 { 881 // エントリー数が 20 個未満の場合、奇数にして返します 882 return countEntries | 1; 883 } 884 885 // エントリー数が20個を超える場合、バケットの分散具合を考慮し、 886 // 小さな値の素数で枝狩りを行います。 887 var i; 888 for (i = 0; i < 100; i++) 889 { 890 var candidate = (countEntries + i); 891 if ( 892 (candidate % 2) != 0 && 893 (candidate % 3) != 0 && 894 (candidate % 5) != 0 && 895 (candidate % 7) != 0 && 896 (candidate % 11) != 0 && 897 (candidate % 13) != 0 && 898 (candidate % 17) != 0 899 ) 900 { 901 return candidate; 902 } 903 } 904 return countEntries | 1; 905}; 906 907/*---------------------------------------------------------------------------*/ 908 909SaveDataArchive.QueryMinDataSize = function( 910 countDirectoryEntry, 911 countFileEntry, 912 countDirectoryBucket, 913 countFileBucket, 914 sizeBlock, 915 countDataBlock 916 ) 917{ 918 if (countDirectoryBucket <= 0 || countFileBucket <= 0) 919 { 920 throw new ResultInvalidArgument(); 921 } 922/* 923 var sizeDirectoryEntry = SaveDataArchive.QueryDirectoryEntryStorageSize(countDirectoryEntry); 924 var blockCountDirectoryEntry = Math.floor((sizeDirectoryEntry + sizeBlock - 1) / sizeBlock); 925 var sizeFileEntry = SaveDataArchive.QueryFileEntryStorageSize(countFileEntry); 926 var blockCountFileEntry = Math.floor((sizeFileEntry + sizeBlock - 1) / sizeBlock); 927 return sizeBlock * (blockCountDirectoryEntry + blockCountFileEntry + countDataBlock); 928*/ 929 return sizeBlock * countDataBlock; 930}; 931 932/*---------------------------------------------------------------------------*/ 933 934SaveDataArchive.QueryMetaSize = function( 935 countDirectoryEntry, 936 countFileEntry, 937 countDirectoryBucket, 938 countFileBucket, 939 sizeBlock, 940 countDataBlock 941 ) 942{ 943 var sizeFixed = 944 SaveDataArchive.QueryHeaderSize() + 945 SaveDataArchive.QueryFileSystemControlAreaSize() + 946 SaveDataArchive.QueryDirectoryEntryBucketStorageSize(countDirectoryBucket) + 947 SaveDataArchive.QueryFileEntryBucketStorageSize(countFileBucket) + 948 SaveDataArchive.QueryAllocationTableStorageSize(countDataBlock) + 949 SaveDataArchive.QueryDirectoryEntryStorageSize(countDirectoryEntry) + 950 SaveDataArchive.QueryFileEntryStorageSize(countFileEntry); 951 return AdjustAlignment(sizeFixed, sizeBlock); 952}; 953 954/*---------------------------------------------------------------------------*/ 955 956SaveDataArchive.QueryTotalSize = function( 957 countDirectoryEntry, 958 countFileEntry, 959 countDirectoryBucket, 960 countFileBucket, 961 sizeBlock, 962 countDataBlock 963 ) 964{ 965 var sizeDirectoryEntry = SaveDataArchive.QueryDirectoryEntryStorageSize(countDirectoryEntry); 966 var blockCountDirectoryEntry = Math.floor((sizeDirectoryEntry + sizeBlock - 1) / sizeBlock); 967 var sizeFileEntry = SaveDataArchive.QueryFileEntryStorageSize(countFileEntry); 968 var blockCountFileEntry = Math.floor((sizeFileEntry + sizeBlock - 1) / sizeBlock); 969 var sizeFixed = 970 SaveDataArchive.QueryHeaderSize() + 971 SaveDataArchive.QueryFileSystemControlAreaSize() + 972 SaveDataArchive.QueryDirectoryEntryBucketStorageSize(countDirectoryBucket) + 973 SaveDataArchive.QueryFileEntryBucketStorageSize(countFileBucket) + 974 SaveDataArchive.QueryAllocationTableStorageSize(blockCountDirectoryEntry + blockCountFileEntry + countDataBlock); 975 sizeFixed = AdjustAlignment(sizeFixed, sizeBlock); 976 return sizeFixed + sizeBlock * (blockCountDirectoryEntry + blockCountFileEntry + countDataBlock); 977}; 978 979/*===========================================================================*/ 980/*! 981 @brief 二重化+完全性検証セーブデータアーカイブクラス 982 @ref DuplicatedIntegritySaveDataArchive 983*/ 984function DuplicatedIntegritySaveDataArchive() 985{ 986}; 987 988/*---------------------------------------------------------------------------*/ 989 990DuplicatedIntegritySaveDataArchive.DUPLICATE_FULL = 0x0001; //!< 全二重化 991DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META = 0x0002; //!< 半二重化 992 993DuplicatedIntegritySaveDataArchive.ATOMIC_HEADER_SIZE = 512; 994 995/*---------------------------------------------------------------------------*/ 996 997DuplicatedIntegritySaveDataArchive.QueryOptimalBucketCount = function(countEntries) 998{ 999 return SaveDataArchive.QueryOptimalBucketCount(countEntries); 1000}; 1001 1002/*---------------------------------------------------------------------------*/ 1003 1004DuplicatedIntegritySaveDataArchive.QuerySizeAsFullDuplication = function( 1005 inputParamDuplex, 1006 inputParamIntegrity, 1007 sizeArchiveBlock, 1008 countDirectoryEntry, 1009 countFileEntry, 1010 countDirectoryEntryBucket, 1011 countFileEntryBucket, 1012 countDataBlock 1013 ) 1014{ 1015 var sizeArchive = SaveDataArchive.QueryTotalSize( 1016 countDirectoryEntry, 1017 countFileEntry, 1018 countDirectoryEntryBucket, 1019 countFileEntryBucket, 1020 sizeArchiveBlock, 1021 countDataBlock 1022 ); 1023 1024 // 検証機能つき二重化ファイル管理領域のサイズを取得します。 1025 var resultDupInt = new DuplicatedIntegrityFile.QuerySizeResult(); 1026 DuplicatedIntegrityFile.QuerySize( 1027 resultDupInt, 1028 inputParamDuplex, 1029 inputParamIntegrity, 1030 sizeArchive, 1031 false 1032 ); 1033 1034 // ブロックサイズの最大値を計算 1035 var sizeBlock =((inputParamDuplex.sizeBlockLevel[0] - 1)| 1036 (inputParamDuplex.sizeBlockLevel[1] - 1)| 1037 (inputParamIntegrity.sizeBlockLevel[0] - 1)| 1038 (inputParamIntegrity.sizeBlockLevel[1] - 1)| 1039 (inputParamIntegrity.sizeBlockLevel[2] - 1)| 1040 (inputParamIntegrity.sizeBlockLevel[3] - 1)) + 1; 1041 1042 // 配置状態を再現しつつサイズを計算します。 1043 var offsetControlAreaA = DuplicatedIntegritySaveDataArchive.ATOMIC_HEADER_SIZE; 1044 var sizeControlAreaAB = resultDupInt.sizeControlArea; 1045 1046 var offset = offsetControlAreaA; 1047 offset += sizeControlAreaAB; 1048 offset = AdjustAlignment(offset, 8/*sizeof(s64)*/); 1049 offset += sizeControlAreaAB; 1050 1051 // 検証機能つき二重化ファイルの管理領域の後にデータ部分を配置します。 1052 // 最大のブロックサイズに合わせるためパディングを挿入します。 1053 offset = AdjustAlignment(offset, sizeBlock); 1054 offset += resultDupInt.sizeTotalBody; 1055 1056 // 総データサイズを返します。 1057 return offset; 1058}; 1059 1060/*---------------------------------------------------------------------------*/ 1061 1062DuplicatedIntegritySaveDataArchive.QuerySizeAsMetaDuplication = function( 1063 inputParamDuplex, 1064 inputParamIntegrity, 1065 sizeArchiveBlock, 1066 countDirectoryEntry, 1067 countFileEntry, 1068 countDirectoryEntryBucket, 1069 countFileEntryBucket, 1070 countDataBlock 1071 ) 1072{ 1073 // 実データのサイズを求めます。 1074 var sizeData = SaveDataArchive.QueryMinDataSize( 1075 countDirectoryEntry, 1076 countFileEntry, 1077 countDirectoryEntryBucket, 1078 countFileEntryBucket, 1079 sizeArchiveBlock, 1080 countDataBlock 1081 ); 1082 1083 // メタデータのサイズを求めます。 1084 var sizeMeta = SaveDataArchive.QueryMetaSize( 1085 countDirectoryEntry, 1086 countFileEntry, 1087 countDirectoryEntryBucket, 1088 countFileEntryBucket, 1089 sizeArchiveBlock, 1090 Math.floor(sizeData / sizeArchiveBlock) 1091 ); 1092 1093 // メタデータに対する検証機能つき二重化ファイル管理領域のサイズを取得します。 1094 var resultDupInt1 = new DuplicatedIntegrityFile.QuerySizeResult(); 1095 DuplicatedIntegrityFile.QuerySize( 1096 resultDupInt1, 1097 inputParamDuplex, 1098 inputParamIntegrity, 1099 sizeMeta, 1100 false 1101 ); 1102 1103 // 実データ領域に対する検証機能つき二重化ファイル管理領域のサイズを取得します。 1104 // 実データ領域の署名データのみ二重化します。 1105 var resultDupInt2 = new DuplicatedIntegrityFile.QuerySizeResult(); 1106 // 完全性検証パラメータを複製(付加情報サイズを 0 に固定) 1107 var inputParamIntegrity2 = new HierarchicalIntegrityVerificationFile.InputParam(); 1108 inputParamIntegrity2 = inputParamIntegrity; 1109 inputParamIntegrity2.sizeOptionalInfo = 0; 1110 1111 DuplicatedIntegrityFile.QuerySize( 1112 resultDupInt2, 1113 inputParamDuplex, 1114 inputParamIntegrity2, 1115 sizeData, 1116 true 1117 ); 1118 1119 // ブロックサイズの最大値を計算 1120 var sizeBlock =((inputParamDuplex.sizeBlockLevel[0] - 1)| 1121 (inputParamDuplex.sizeBlockLevel[1] - 1)| 1122 (inputParamIntegrity.sizeBlockLevel[0] - 1)| 1123 (inputParamIntegrity.sizeBlockLevel[1] - 1)| 1124 (inputParamIntegrity.sizeBlockLevel[2] - 1)| 1125 (inputParamIntegrity.sizeBlockLevel[3] - 1)) + 1; 1126 1127 // 配置状態を再現しつつサイズを計算します。 1128 var offsetDuplicatedIntegrityControlArea1 = DuplicatedIntegritySaveDataArchive.ATOMIC_HEADER_SIZE; 1129 var offsetDuplicatedIntegrityControlArea2 = 1130 AdjustAlignment(resultDupInt1.sizeControlArea, 8/*sizeof(s64)*/); 1131 var sizeControlAreaAB = 1132 offsetDuplicatedIntegrityControlArea2 + 1133 AdjustAlignment(resultDupInt2.sizeControlArea, 8/*sizeof(s64)*/); 1134 1135 var offset = offsetDuplicatedIntegrityControlArea1; 1136 offset += sizeControlAreaAB; 1137 offset += sizeControlAreaAB; 1138 1139 // 検証機能つき二重化ファイルの管理領域(実データ)の後にメタデータ領域を配置します。 1140 // 最大のブロックサイズに合わせるためパディングを挿入します。 1141 offset = AdjustAlignment(offset, sizeBlock); 1142 offset += resultDupInt1.sizeTotalBody; 1143 1144 // メタデータ領域の後に実データ領域を配置します。 1145 offset = AdjustAlignment(offset, sizeBlock); 1146 offset += resultDupInt2.sizeTotalBody; 1147 1148 // 総データサイズを返します。 1149 return offset; 1150}; 1151 1152/*---------------------------------------------------------------------------*/ 1153 1154DuplicatedIntegritySaveDataArchive.QuerySize = function( 1155 inputParamDuplex, 1156 inputParamIntegrity, 1157 sizeArchiveBlock, 1158 countDirectoryEntry, 1159 countFileEntry, 1160 countDirectoryEntryBucket, 1161 countFileEntryBucket, 1162 countDataBlock, 1163 option 1164 ) 1165{ 1166 var sizeTotal = 0; 1167 1168 if (option & DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META) 1169 { 1170 sizeTotal = DuplicatedIntegritySaveDataArchive.QuerySizeAsMetaDuplication( 1171 inputParamDuplex, 1172 inputParamIntegrity, 1173 sizeArchiveBlock, 1174 countDirectoryEntry, 1175 countFileEntry, 1176 countDirectoryEntryBucket, 1177 countFileEntryBucket, 1178 countDataBlock 1179 ); 1180 } 1181 else if (option & DuplicatedIntegritySaveDataArchive.DUPLICATE_FULL) 1182 { 1183 sizeTotal = DuplicatedIntegritySaveDataArchive.QuerySizeAsFullDuplication( 1184 inputParamDuplex, 1185 inputParamIntegrity, 1186 sizeArchiveBlock, 1187 countDirectoryEntry, 1188 countFileEntry, 1189 countDirectoryEntryBucket, 1190 countFileEntryBucket, 1191 countDataBlock 1192 ); 1193 } 1194 else 1195 { 1196 throw new ResultInvalidArgument(); 1197 } 1198 1199 return sizeTotal; 1200}; 1201 1202/*===========================================================================*/ 1203/*! 1204 @brief 拡張セーブデータフィルタアーカイブクラス 1205 @ref ExtSaveDataFilterArchive 1206*/ 1207function ExtSaveDataFilterArchive() 1208{ 1209}; 1210 1211/*---------------------------------------------------------------------------*/ 1212 1213ExtSaveDataFilterArchive.QueryFilteredFileSizeInternal = function( 1214 sizeOriginalData, 1215 isMetaFile 1216 ) 1217{ 1218 // 二重化パラメータ 1219 var inputParamDuplex = new HierarchicalDuplexFile.InputParam(); 1220 1221 inputParamDuplex.sizeBlockLevel[0] = 128; 1222 inputParamDuplex.sizeBlockLevel[1] = 4096; 1223 1224 // 完全性検証パラメータ 1225 var inputParamIntegrity = new HierarchicalIntegrityVerificationFile.InputParam(); 1226 1227 inputParamIntegrity.sizeBlockLevel[0] = 512; 1228 inputParamIntegrity.sizeBlockLevel[1] = 512; 1229 inputParamIntegrity.sizeBlockLevel[2] = 4096; 1230 inputParamIntegrity.sizeBlockLevel[3] = 4096; 1231 inputParamIntegrity.sizeOptionalInfo = 0; 1232 1233 // 二重化+完全性検証フィルタファイルのサイズを求めます。 1234 var resultDupIntFilter = new DuplicatedIntegrityFilterFile.QuerySizeResult(); 1235 1236 DuplicatedIntegrityFilterFile.QuerySize( 1237 resultDupIntFilter, 1238 inputParamDuplex, 1239 inputParamIntegrity, 1240 sizeOriginalData, 1241 !isMetaFile // メタファイルのみ全二重化 1242 ); 1243 1244 return resultDupIntFilter.sizeTotalBody; 1245}; 1246 1247/*---------------------------------------------------------------------------*/ 1248 1249ExtSaveDataFilterArchive.QueryFilteredMetaFileSize = function( 1250 sizeMetaData 1251 ) 1252{ 1253 return ExtSaveDataFilterArchive.QueryFilteredFileSizeInternal( 1254 sizeMetaData, 1255 true 1256 ); 1257}; 1258 1259/*---------------------------------------------------------------------------*/ 1260 1261ExtSaveDataFilterArchive.QueryFilteredFileSize = function( 1262 sizeOriginalData 1263 ) 1264{ 1265 return ExtSaveDataFilterArchive.QueryFilteredFileSizeInternal( 1266 sizeOriginalData, 1267 false 1268 ); 1269}; 1270 1271/*===========================================================================*/ 1272/*! 1273 @brief 拡張セーブデータストレージアーカイブクラス 1274 @ref ExtSaveDataStorageArchive 1275*/ 1276function ExtSaveDataStorageArchive() 1277{ 1278}; 1279 1280/*---------------------------------------------------------------------------*/ 1281 1282ExtSaveDataStorageArchive.ENTRY_SIZE = 32; 1283 1284/*---------------------------------------------------------------------------*/ 1285 1286ExtSaveDataStorageArchive.QueryMaxDirectoryEntryCount = function( 1287 sizeArchiveBlock, 1288 sizeEntry 1289 ) 1290{ 1291 // "."、".."のために 2 つ分除きます。 1292 return Math.floor(sizeArchiveBlock / sizeEntry) - 2; 1293} 1294 1295/*===========================================================================*/ 1296/*! 1297 @brief 拡張セーブデータ管理クラス 1298 @ref ExtSaveDataManager 1299*/ 1300function ExtSaveDataManager() 1301{ 1302}; 1303 1304/*---------------------------------------------------------------------------*/ 1305 1306ExtSaveDataManager.QueryMetaDataSize = function( 1307 sizeArchiveBlock, 1308 countDirectoryEntry, 1309 countFileEntry 1310 ) 1311{ 1312 var countDirectoryBucket = WStringOnBit64PathStorageArchive.QueryOptimalBucketCount(countDirectoryEntry); 1313 var countFileBucket = WStringOnBit64PathStorageArchive.QueryOptimalBucketCount(countFileEntry); 1314 return WStringOnBit64PathStorageArchive.QueryTotalSize( 1315 countDirectoryEntry, 1316 countDirectoryBucket, 1317 countFileEntry, 1318 countFileBucket, 1319 sizeArchiveBlock 1320 ); 1321}; 1322 1323/*---------------------------------------------------------------------------*/ 1324 1325ExtSaveDataManager.QueryTotalQuotaSize = function( 1326 sizeArchiveBlock, 1327 countDirectoryEntry, 1328 countFileEntry, 1329 sizeIcon, 1330 fileSizeArray, 1331 fileSizeArrayLength 1332 ) 1333{ 1334 countDirectoryEntry += 2; // user, boss ディレクトリの分を追加 1335 countFileEntry += 1; // icon ファイルの分を追加 TODO: 共有拡張セーブデータの場合ははずす? 1336 var sizeMetaData = ExtSaveDataManager.QueryMetaDataSize( 1337 sizeArchiveBlock, 1338 countDirectoryEntry, 1339 countFileEntry 1340 ); 1341 var resultDupIntFilter = new DuplicatedIntegrityFilterFile.QuerySizeResult(); 1342 var sizeFilteredMetaData = ExtSaveDataFilterArchive.QueryFilteredMetaFileSize(sizeMetaData); 1343 var filteredMetaDataBlocks = Math.floor((sizeFilteredMetaData + sizeArchiveBlock - 1) / sizeArchiveBlock); 1344 1345 var fileBlocks = 0; 1346 for (var i = 0; i < fileSizeArrayLength; i++) 1347 { 1348 var sizeFilteredFile = ExtSaveDataFilterArchive.QueryFilteredFileSize(fileSizeArray[i]); 1349 fileBlocks += Math.floor((sizeFilteredFile + sizeArchiveBlock - 1) / sizeArchiveBlock); 1350 } 1351 1352 // ディレクトリひとつ当たりに入るファイル数 1353 var countMaxEntryPerDirectory = ExtSaveDataStorageArchive.QueryMaxDirectoryEntryCount( 1354 sizeArchiveBlock, 1355 ExtSaveDataStorageArchive.ENTRY_SIZE 1356 ); 1357 1358 // ファイル数を最大まで(countFileEntry個)作成したときに作られるディレクトリの数 1359 var countMaxDirEntries = Math.floor((countFileEntry + countMaxEntryPerDirectory - 1) / countMaxEntryPerDirectory); 1360 if (countMaxDirEntries == 0) 1361 { 1362 countMaxDirEntries = 1; 1363 } 1364 // ルートが必要とするブロック数 1365 var rootEntryBlocks = Math.floor((countMaxDirEntries + countMaxEntryPerDirectory - 1) / countMaxEntryPerDirectory); 1366 1367 // メタファイルやアイコンファイルを含むファイルが格納されるディレクトリの数 1368 var countDirEntries = Math.floor(((fileSizeArrayLength + 2) + countMaxEntryPerDirectory - 1) / countMaxEntryPerDirectory); 1369 1370 var iconBlocks = 0; 1371 { 1372 var sizeFilterdIcon = ExtSaveDataFilterArchive.QueryFilteredFileSize(sizeIcon); 1373 iconBlocks = Math.floor((sizeFilterdIcon + sizeArchiveBlock - 1) / sizeArchiveBlock); 1374 } 1375 1376 return (filteredMetaDataBlocks 1377 + fileBlocks 1378 + countDirEntries 1379 + rootEntryBlocks 1380 + iconBlocks) * sizeArchiveBlock; 1381}; 1382 1383/*===========================================================================*/ 1384function ClearDebugPrint() 1385{ 1386 if (!document.FsDebug) return; 1387 1388 var out = document.FsDebug.output; 1389 if (!out) return; 1390 out.value = ""; 1391}; 1392 1393/*---------------------------------------------------------------------------*/ 1394 1395function DebugPrint(str) 1396{ 1397 if (!document.FsDebug) return; 1398 1399 var out = document.FsDebug.output; 1400 if (!out) return; 1401 out.value += str + "\n"; 1402}; 1403 1404/*===========================================================================*/ 1405 1406CalcFsSpaceResult = function() 1407{ 1408 this.sizeTotal = 0; 1409 this.countDataBlock = 0; 1410}; 1411 1412/*---------------------------------------------------------------------------*/ 1413 1414function calcFsSpaceInternal( 1415 outResult, 1416 countDirectoryEntry, 1417 countFileEntry, 1418 sizeArchiveBlock, 1419 sizeCapacity, 1420 option 1421 ) 1422{ 1423 // ディレクトリ/ファイルバケット数 1424 var countDirectoryEntryBucket = DuplicatedIntegritySaveDataArchive 1425 .QueryOptimalBucketCount(countDirectoryEntry); 1426 var countFileEntryBucket = DuplicatedIntegritySaveDataArchive 1427 .QueryOptimalBucketCount(countFileEntry); 1428 1429 // 二重化パラメータ 1430 var inputParamDuplex = new HierarchicalDuplexFile.InputParam(); 1431 1432 inputParamDuplex.sizeBlockLevel[0] = 128; 1433 inputParamDuplex.sizeBlockLevel[1] = 512 * 8; 1434 1435 // 完全性検証パラメータ 1436 var inputParamIntegrity = new HierarchicalIntegrityVerificationFile.InputParam(); 1437 1438 // 二重化タイプとブロックサイズに応じて変更 1439 switch (sizeArchiveBlock) 1440 { 1441 case 512: 1442 if (option & DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META) 1443 { 1444 inputParamIntegrity.sizeBlockLevel[0] = 512; 1445 inputParamIntegrity.sizeBlockLevel[1] = 512; 1446 inputParamIntegrity.sizeBlockLevel[2] = 512 * 8; 1447 inputParamIntegrity.sizeBlockLevel[3] = 512; 1448 inputParamIntegrity.sizeOptionalInfo = 0; 1449 } 1450 else if (option & DuplicatedIntegritySaveDataArchive.DUPLICATE_FULL) 1451 { 1452 inputParamIntegrity.sizeBlockLevel[0] = 512; 1453 inputParamIntegrity.sizeBlockLevel[1] = 512; 1454 inputParamIntegrity.sizeBlockLevel[2] = 512 * 8; 1455 inputParamIntegrity.sizeBlockLevel[3] = 512 * 8; 1456 inputParamIntegrity.sizeOptionalInfo = 0; 1457 } 1458 else 1459 { 1460 throw new ResultInvalidArgument(); 1461 } 1462 break; 1463 case 4096: 1464 { 1465 inputParamIntegrity.sizeBlockLevel[0] = 512; 1466 inputParamIntegrity.sizeBlockLevel[1] = 512; 1467 inputParamIntegrity.sizeBlockLevel[2] = 512 * 8; 1468 inputParamIntegrity.sizeBlockLevel[3] = 512 * 8; 1469 inputParamIntegrity.sizeOptionalInfo = 0; 1470 } 1471 break; 1472 default: 1473 throw new ResultInvalidArgument(); 1474 break; 1475 } 1476 1477 // トータルサイズ 1478 var sizeTotal = 0; 1479 1480 // キャパシティに合うように総ブロック数を調整します。 1481 var countDataBlockMin = 0; 1482 var countDataBlockMax = Math.floor(sizeCapacity / sizeArchiveBlock); 1483 var retryCount = 32; 1484 1485 while (1 <= (countDataBlockMax - countDataBlockMin) && (0 < retryCount--)) 1486 { 1487 var countDataBlock = Math.floor((countDataBlockMin + countDataBlockMax) / 2); 1488 1489 sizeTotal = DuplicatedIntegritySaveDataArchive.QuerySize( 1490 inputParamDuplex, 1491 inputParamIntegrity, 1492 sizeArchiveBlock, 1493 countDirectoryEntry, 1494 countFileEntry, 1495 countDirectoryEntryBucket, 1496 countFileEntryBucket, 1497 countDataBlock, 1498 option 1499 ); 1500 1501 DebugPrint("sizeCapacity = " + sizeCapacity 1502 + ", sizeTotal = " + sizeTotal 1503 + ", countDataBlockMax = " + countDataBlockMax 1504 + ", countDataBlockMin = " + countDataBlockMin); 1505 1506 if (sizeTotal > sizeCapacity) 1507 { 1508 countDataBlockMax = countDataBlock; 1509 } 1510 else 1511 { 1512 countDataBlockMin = countDataBlock; 1513 } 1514 1515 // 途中抜け判定(これ以上継続しても変化なし) 1516 if ((countDataBlockMax - countDataBlockMin) <= 1 1517 && (countDataBlock == countDataBlockMin)) 1518 { 1519 break; 1520 } 1521 } 1522 1523 // 計算されたブロック数 1524 outResult.countDataBlock = countDataBlockMin; 1525 1526 // 最終的なサイズを計算します。 1527 sizeTotal = DuplicatedIntegritySaveDataArchive.QuerySize( 1528 inputParamDuplex, 1529 inputParamIntegrity, 1530 sizeArchiveBlock, 1531 countDirectoryEntry, 1532 countFileEntry, 1533 countDirectoryEntryBucket, 1534 countFileEntryBucket, 1535 countDataBlock, 1536 option 1537 ); 1538 if (sizeTotal <= sizeCapacity) 1539 { 1540 outResult.sizeTotal = sizeTotal; 1541 } 1542 else 1543 { 1544 outResult.sizeTotal = sizeTotal; 1545 } 1546}; 1547 1548/*---------------------------------------------------------------------------*/ 1549 1550function calcFsSpace() 1551{ 1552 // デバッグ出力クリア 1553 ClearDebugPrint(); 1554 1555 if (!document.FsSpace) return; 1556 1557 var FsSpace = document.FsSpace; 1558 1559 if (FsSpace.fsblocksize[0].checked) 1560 { 1561 if (FsSpace.capacitytype[2].checked) 1562 { 1563 FsSpace.capacitytype[0].checked = true; 1564 } 1565 1566 FsSpace.capacitytype[0].disabled = false; 1567 FsSpace.capacitytype[0].readonly = true; 1568 1569 FsSpace.capacitytype[1].disabled = false; 1570 FsSpace.capacitytype[1].readonly = true; 1571 1572 FsSpace.capacitytype[2].disabled = true; 1573 FsSpace.capacitytype[2].readonly = false; 1574 } 1575 else 1576 { 1577 FsSpace.capacitytype[2].checked = true; 1578 1579 FsSpace.capacitytype[0].disabled = true; 1580 FsSpace.capacitytype[0].readonly = false; 1581 1582 FsSpace.capacitytype[1].disabled = true; 1583 FsSpace.capacitytype[1].readonly = false; 1584 1585 FsSpace.capacitytype[2].disabled = false; 1586 FsSpace.capacitytype[2].readonly = true; 1587 } 1588 1589 if (FsSpace.capacitytype[2].checked) 1590 { 1591 FsSpace.capacitytypeuser.disabled = false; 1592 FsSpace.capacitytypeuser.readonly = true; 1593 } 1594 else 1595 { 1596 FsSpace.capacitytypeuser.readonly = false; 1597 FsSpace.capacitytypeuser.disabled = true; 1598 } 1599 1600 // 全二重 or 半二重 1601 var option = 0; 1602 if (FsSpace.fstype[0].checked) 1603 { 1604 option |= DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; 1605 } 1606 else if (FsSpace.fstype[1].checked) 1607 { 1608 option |= DuplicatedIntegritySaveDataArchive.DUPLICATE_FULL; 1609 } 1610 1611 // ブロックサイズ 1612 var sizeArchiveBlock = 512; 1613 if (FsSpace.fsblocksize[1].checked) 1614 { 1615 sizeArchiveBlock = 4096; 1616 } 1617 1618 // 最大ディレクトリ/ファイル数 1619 var countDirectoryEntry = parseInt(FsSpace.CountDirectoryEntry.value); 1620 var countFileEntry = parseInt(FsSpace.CountFileEntry.value); 1621 1622 // 入力値の補正 1623 if (isNaN(countDirectoryEntry) || countDirectoryEntry < 0) 1624 { 1625 countDirectoryEntry = 0; 1626 } 1627 if (isNaN(countFileEntry) || countFileEntry < 1) 1628 { 1629 countFileEntry = 1; 1630 } 1631 1632 // 補正結果を書き戻す 1633 FsSpace.CountDirectoryEntry.value = countDirectoryEntry; 1634 FsSpace.CountFileEntry.value = countFileEntry; 1635 1636 // 全体容量 1637 var sizeCapacity = parseInt(FsSpace.capacitytypeuser.value) * 1024; 1638 1639 // 入力値の補正 1640 if (isNaN(sizeCapacity) || sizeCapacity < 0) 1641 { 1642 sizeCapacity = 0; 1643 } 1644 1645 // 補正結果を書き戻す 1646 FsSpace.capacitytypeuser.value = Math.floor(sizeCapacity / 1024); 1647 1648 if (FsSpace.capacitytype[0].checked) 1649 { 1650 sizeCapacity = 120 * 1024; 1651 } 1652 else if (FsSpace.capacitytype[1].checked) 1653 { 1654 sizeCapacity = 504 * 1024; 1655 } 1656 1657 // 得られたパラメータを元にセーブデータサイズを計算します。 1658 var result = new CalcFsSpaceResult(); 1659 1660 calcFsSpaceInternal( 1661 result, 1662 countDirectoryEntry, 1663 countFileEntry, 1664 sizeArchiveBlock, 1665 sizeCapacity, 1666 option 1667 ) 1668 1669 var sizeTotal = result.sizeTotal; 1670 var countDataBlock = result.countDataBlock; 1671 1672 FsSpace.SaveDataBlockSize.value = sizeArchiveBlock; 1673 FsSpace.SaveDataCapacities.value = countDataBlock * sizeArchiveBlock; 1674 FsSpace.SaveDataBlocks.value = countDataBlock; 1675 FsSpace.SaveDataCapacitiesKilloByte.value = Math.floor(countDataBlock * sizeArchiveBlock / 1024); 1676}; 1677 1678/*---------------------------------------------------------------------------*/ 1679 1680function calcFsSpaceExtMeta() 1681{ 1682 // デバッグ出力クリア 1683 ClearDebugPrint(); 1684 1685 if (!document.FsSpaceExtEntry) return; 1686 1687 var FsSpace = document.FsSpaceExtEntry; 1688 1689 // 全二重 or 半二重 1690 var option = DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; 1691 1692 // ブロックサイズ 1693 var sizeArchiveBlock = 4096; 1694 1695 // アイコンサイズ 1696 var sizeIcon = parseInt(FsSpace.IconSize.value); 1697 1698 // 入力値の補正 1699 if (isNaN(sizeIcon) || sizeIcon <= 0) 1700 { 1701 sizeIcon = 1; 1702 } 1703 1704 // 補正結果を書き戻す 1705 FsSpace.IconSize.value = sizeIcon; 1706 1707 // 最大ディレクトリ/ファイル数 1708 var countDirectoryEntry = parseInt(FsSpace.CountDirectoryEntry.value); 1709 var countFileEntry = parseInt(FsSpace.CountFileEntry.value); 1710 1711 // 入力値の補正 1712 if (isNaN(countDirectoryEntry) || countDirectoryEntry < 0) 1713 { 1714 countDirectoryEntry = 0; 1715 } 1716 if (isNaN(countFileEntry) || countFileEntry < 1) 1717 { 1718 countFileEntry = 1; 1719 } 1720 1721 // 補正結果を書き戻す 1722 FsSpace.CountDirectoryEntry.value = countDirectoryEntry; 1723 FsSpace.CountFileEntry.value = countFileEntry; 1724 1725 // ファイル一覧は空とします 1726 var arrayFileSize = []; 1727 1728 // 得られたパラメータを元にセーブデータサイズを計算します。 1729 var sizeTotal = ExtSaveDataManager.QueryTotalQuotaSize( 1730 sizeArchiveBlock, 1731 countDirectoryEntry, 1732 countFileEntry, 1733 sizeIcon, 1734 arrayFileSize, 1735 0); 1736 var countDataBlock = Math.floor((sizeTotal + sizeArchiveBlock - 1) / sizeArchiveBlock); 1737 1738 FsSpace.ExtSaveDataBlocks.value = countDataBlock; 1739 FsSpace.ExtSaveDataCapacities.value = sizeTotal; 1740 FsSpace.ExtSaveDataCapacitiesKilloByte.value = Math.floor(sizeTotal / 1024); 1741}; 1742 1743/*---------------------------------------------------------------------------*/ 1744 1745function calcFsSpaceExtFile() 1746{ 1747 // デバッグ出力クリア 1748 ClearDebugPrint(); 1749 1750 if (!document.FsSpaceExtFile) return; 1751 1752 var FsSpace = document.FsSpaceExtFile; 1753 1754 // 全二重 or 半二重 1755 var option = DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; 1756 1757 // ブロックサイズ 1758 var sizeArchiveBlock = 4096; 1759 1760 // 全体容量 1761 var sizeCapacity = parseInt(FsSpace.capacitytypeuser.value) * 1024; 1762 1763 // 入力値の補正 1764 if (isNaN(sizeCapacity) || sizeCapacity < 0) 1765 { 1766 sizeCapacity = 0; 1767 } 1768 1769 // 補正結果を書き戻す 1770 FsSpace.capacitytypeuser.value = Math.floor(sizeCapacity / 1024); 1771 1772 // 得られたパラメータを元にセーブデータサイズを計算します。 1773 var sizeTotal = ExtSaveDataFilterArchive.QueryFilteredFileSize(sizeCapacity); 1774 var countDataBlock = Math.floor((sizeTotal + sizeArchiveBlock - 1) / sizeArchiveBlock); 1775 1776 // 124 + 126 * n個のたびにディレクトリが1つ作られるので、消費される可能性のある最大値を表示しておく 1777 countDataBlock += 1; 1778 sizeTotal = countDataBlock * sizeArchiveBlock; 1779 1780 FsSpace.ExtSaveDataBlocks.value = countDataBlock; 1781 FsSpace.ExtSaveDataCapacities.value = sizeTotal; 1782 FsSpace.ExtSaveDataCapacitiesKilloByte.value = Math.floor(sizeTotal / 1024); 1783}; 1784