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/* Please see man pages for details 18 19*/ 20function AdjustAlignment(val, alignment) 21{ 22 return ((val + (alignment - 1)) & ~(alignment - 1)); 23}; 24 25/*===========================================================================*/ 26/* Please see man pages for details 27 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/* Please see man pages for details 51 52*/ 53function IsPwr2(val) 54{ 55 return (0 == (val & (val - 1))); 56}; 57 58/*---------------------------------------------------------------------------*/ 59/* Please see man pages for details 60 61*/ 62function ILog2(val) 63{ 64 return 31 - CntLz(val); 65}; 66 67/*---------------------------------------------------------------------------*/ 68/* Please see man pages for details 69 70*/ 71function ResultInvalidArgument() 72{ 73}; 74 75/*===========================================================================*/ 76/* Please see man pages for details 77 78 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/* Please see man pages for details 157 158 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/* Please see man pages for details 181 182 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/* Please see man pages for details 221 222 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 // Determine size of control area 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 // Data size in bits 303 sizeLevel[1] = Math.floor(((sizeLevel[2] + inputParam.sizeBlockLevel[1] - 1) / inputParam.sizeBlockLevel[1])); 304 // Convert bit -> byte 305 sizeLevel[1] = Math.floor((sizeLevel[1] + 7) / 8); 306 // Align size to border of L1 block 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 // Align size to border of DPFS_BITMAP_ALIGN bytes 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 // Align Master and L1 at least to 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 // Align actual data to L2 block size. 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 // Determine size of the actual data 344 outResult.sizeBody = offset; 345}; 346 347/*===========================================================================*/ 348/* Please see man pages for details 349 350 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 // Determine size of control area 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 // Determine master hash size 451 outResult.sizeMasterHash = sizeLevel[0]; 452 453 // Construct level information 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 // Determine size of layer hash 478 outResult.sizeLayeredHash = levelInfo[MAX_LEVEL - 3].offset 479 + levelInfo[MAX_LEVEL - 3].size 480 - levelInfo[0].offset; 481 482 // Determine size of the actual data 483 outResult.sizeBody = levelInfo[MAX_LEVEL - 2].size; 484 485 // Determine total size 486 outResult.sizeTotal = levelInfo[MAX_LEVEL - 2].offset 487 + levelInfo[MAX_LEVEL - 2].size 488 - levelInfo[0].offset; 489}; 490 491/*===========================================================================*/ 492/* Please see man pages for details 493 494 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 // Calculates the size of the hierarchical integrity verification file. 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 // Calculates the size of the hierarchical duplex file. 554 var resultDuplex = new HierarchicalDuplexFile.QuerySizeResult(); 555 556 HierarchicalDuplexFile.QuerySize( 557 resultDuplex, 558 inputParamDuplex, 559 sizeDuplicateOriginal 560 ); 561 562 // Calculates the size of duplex + integrity verification file. 563 var offsetOriginalData; 564 if (!isDuplicateOnlyHash) 565 { 566 offsetOriginalData = 0; 567 outResult.sizeTotalBody = resultDuplex.sizeBody; 568 } 569 else 570 { 571 // Place actual data behind the duplexed signature data. 572 offsetOriginalData = AdjustAlignment(resultDuplex.sizeBody, inputParamIntegrity.sizeBlockLevel[3]); 573 outResult.sizeTotalBody = offsetOriginalData + sizeOriginalData; 574 } 575 576 // meta information 577 var offset = DuplicatedIntegrityFile.META_INFO_SIZE; 578 579 // Control area for integrity verification layer 580 offset = AdjustAlignment(offset, 4); 581 offset += resultIntegrity.sizeControlArea; 582 583 // Control area for duplex layer 584 offset = AdjustAlignment(offset, 4); 585 offset += resultDuplex.sizeControlArea; 586 587 // Master signature 588 offset = AdjustAlignment(offset, 4); 589 offset += resultIntegrity.sizeMasterHash; 590 591 // Size of final control area 592 outResult.sizeControlArea = offset; 593}; 594 595/*===========================================================================*/ 596/* Please see man pages for details 597 598 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 // Option area is not used in the filter file. 626 inputParamDuplex.sizeOptionalInfo = 0; 627 628 // Get the size of the control area for the duplex file that has verification feature. 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 // Duplexed control area A 641 offset = AdjustAlignment(offset, 8/*sizeof(s64)*/); 642 offset += resultDupInt.sizeControlArea; 643 644 // Duplexed control area 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 // While inserting padding, place the data section after the control area for the duplex file that has verification feature. 656 // 657 offset = AdjustAlignment(offset, maxBlockSize); 658 offset += resultDupInt.sizeTotalBody;; 659 660 // Returns the final size. 661 outResult.sizeTotalBody = offset; 662}; 663 664/*===========================================================================*/ 665/* Please see man pages for details 666 667 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 // When the number of entries is extremely small, return a fixed size for the bucket number. 747 return 3; 748 } 749 if (countEntries <= 19) 750 { 751 // When the number of entries is less than 20, return an odd number 752 return countEntries | 1; 753 } 754 755 // When the number of entries exceeds 20, consider how the bucket is distributed, and then prune with small value prime numbers. 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/* Please see man pages for details 804 805 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: We will examine to standardize WStringOnBit64PathStorageArchive.QueryOptimalBucketCount. 874 if (countEntries <= 3) 875 { 876 // When the number of entries is extremely small, return a fixed size for the bucket number. 877 return 3; 878 } 879 if (countEntries <= 19) 880 { 881 // When the number of entries is less than 20, return an odd number 882 return countEntries | 1; 883 } 884 885 // When the number of entries exceeds 20, consider how the bucket is distributed, and then prune with small value prime numbers. 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/* Please see man pages for details 981 982 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 // Get the size of the control area for the duplex file that has verification feature. 1025 var resultDupInt = new DuplicatedIntegrityFile.QuerySizeResult(); 1026 DuplicatedIntegrityFile.QuerySize( 1027 resultDupInt, 1028 inputParamDuplex, 1029 inputParamIntegrity, 1030 sizeArchive, 1031 false 1032 ); 1033 1034 // Calculate the maximum value of block size 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 // Calculate the size while rebuilding the arrangement. 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 // Position the data portion after the control area for the duplexed file that has verification feature. 1052 // Insert padding to match the maximum block size. 1053 offset = AdjustAlignment(offset, sizeBlock); 1054 offset += resultDupInt.sizeTotalBody; 1055 1056 // Return the total data size. 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 // Find the actual data size. 1074 var sizeData = SaveDataArchive.QueryMinDataSize( 1075 countDirectoryEntry, 1076 countFileEntry, 1077 countDirectoryEntryBucket, 1078 countFileEntryBucket, 1079 sizeArchiveBlock, 1080 countDataBlock 1081 ); 1082 1083 // Find the metadata size. 1084 var sizeMeta = SaveDataArchive.QueryMetaSize( 1085 countDirectoryEntry, 1086 countFileEntry, 1087 countDirectoryEntryBucket, 1088 countFileEntryBucket, 1089 sizeArchiveBlock, 1090 Math.floor(sizeData / sizeArchiveBlock) 1091 ); 1092 1093 // Get the size of the control area for the duplex file that has metadata verification feature. 1094 var resultDupInt1 = new DuplicatedIntegrityFile.QuerySizeResult(); 1095 DuplicatedIntegrityFile.QuerySize( 1096 resultDupInt1, 1097 inputParamDuplex, 1098 inputParamIntegrity, 1099 sizeMeta, 1100 false 1101 ); 1102 1103 // Get the size of the control area for the duplex file that has verification feature for the actual data area. 1104 // Duplicate only the signature data of the actual data area. 1105 var resultDupInt2 = new DuplicatedIntegrityFile.QuerySizeResult(); 1106 // Duplicate the integrity verification parameters (additional information size is fixed at 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 // Calculate the maximum value of block size 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 // Calculate the size while rebuilding the arrangement. 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 // Position the metadata area after the control area (the actual data) for the duplexed file that has verification feature. 1140 // Insert padding to match the maximum block size. 1141 offset = AdjustAlignment(offset, sizeBlock); 1142 offset += resultDupInt1.sizeTotalBody; 1143 1144 // Position the actual data area after the metadata area. 1145 offset = AdjustAlignment(offset, sizeBlock); 1146 offset += resultDupInt2.sizeTotalBody; 1147 1148 // Return the total data size. 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/* Please see man pages for details 1204 1205 1206*/ 1207function ExtSaveDataFilterArchive() 1208{ 1209}; 1210 1211/*---------------------------------------------------------------------------*/ 1212 1213ExtSaveDataFilterArchive.QueryFilteredFileSizeInternal = function( 1214 sizeOriginalData, 1215 isMetaFile 1216 ) 1217{ 1218 // Duplex parameters 1219 var inputParamDuplex = new HierarchicalDuplexFile.InputParam(); 1220 1221 inputParamDuplex.sizeBlockLevel[0] = 128; 1222 inputParamDuplex.sizeBlockLevel[1] = 4096; 1223 1224 // Integrity verification parameters 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 // Find the size of duplex + integrity verification filter file. 1234 var resultDupIntFilter = new DuplicatedIntegrityFilterFile.QuerySizeResult(); 1235 1236 DuplicatedIntegrityFilterFile.QuerySize( 1237 resultDupIntFilter, 1238 inputParamDuplex, 1239 inputParamIntegrity, 1240 sizeOriginalData, 1241 !isMetaFile // Full duplex only for metafile 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/* Please see man pages for details 1273 1274 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 // Exclude two parts for "." and ".." 1292 return Math.floor(sizeArchiveBlock / sizeEntry) - 2; 1293} 1294 1295/*===========================================================================*/ 1296/* Please see man pages for details 1297 1298 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; // Add entries for "user" and "boss" directories 1335 countFileEntry += 1; // Add entry for icon file TODO: Remove entries for shared expanded save data? 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 // Number of files per directory 1353 var countMaxEntryPerDirectory = ExtSaveDataStorageArchive.QueryMaxDirectoryEntryCount( 1354 sizeArchiveBlock, 1355 ExtSaveDataStorageArchive.ENTRY_SIZE 1356 ); 1357 1358 // Number of directories to create when the max number of files was created (the number of countFileEntry) 1359 var countMaxDirEntries = Math.floor((countFileEntry + countMaxEntryPerDirectory - 1) / countMaxEntryPerDirectory); 1360 if (countMaxDirEntries == 0) 1361 { 1362 countMaxDirEntries = 1; 1363 } 1364 // Number of blocks needed for roots 1365 var rootEntryBlocks = Math.floor((countMaxDirEntries + countMaxEntryPerDirectory - 1) / countMaxEntryPerDirectory); 1366 1367 // Number of directories that store files that contain metafiles and icon files. 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 // Number of directories/file buckets 1424 var countDirectoryEntryBucket = DuplicatedIntegritySaveDataArchive 1425 .QueryOptimalBucketCount(countDirectoryEntry); 1426 var countFileEntryBucket = DuplicatedIntegritySaveDataArchive 1427 .QueryOptimalBucketCount(countFileEntry); 1428 1429 // Duplex parameters 1430 var inputParamDuplex = new HierarchicalDuplexFile.InputParam(); 1431 1432 inputParamDuplex.sizeBlockLevel[0] = 128; 1433 inputParamDuplex.sizeBlockLevel[1] = 512 * 8; 1434 1435 // Integrity verification parameters 1436 var inputParamIntegrity = new HierarchicalIntegrityVerificationFile.InputParam(); 1437 1438 // Modify based on duplex type and block size 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 // Total size 1478 var sizeTotal = 0; 1479 1480 // Adjust the total number of blocks to match the capacity. 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 // Detect exit while in progress (no changes if continued beyond this point) 1516 if ((countDataBlockMax - countDataBlockMin) <= 1 1517 && (countDataBlock == countDataBlockMin)) 1518 { 1519 break; 1520 } 1521 } 1522 1523 // Calculated number of blocks 1524 outResult.countDataBlock = countDataBlockMin; 1525 1526 // Calculate the final size. 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 // Clear debug output 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 // Full duplex or half duplex 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 // Block size 1612 var sizeArchiveBlock = 512; 1613 if (FsSpace.fsblocksize[1].checked) 1614 { 1615 sizeArchiveBlock = 4096; 1616 } 1617 1618 // Maximum number of directories/files 1619 var countDirectoryEntry = parseInt(FsSpace.CountDirectoryEntry.value); 1620 var countFileEntry = parseInt(FsSpace.CountFileEntry.value); 1621 1622 // Correct input value 1623 if (isNaN(countDirectoryEntry) || countDirectoryEntry < 0) 1624 { 1625 countDirectoryEntry = 0; 1626 } 1627 if (isNaN(countFileEntry) || countFileEntry < 1) 1628 { 1629 countFileEntry = 1; 1630 } 1631 1632 // Rewrite correction result. 1633 FsSpace.CountDirectoryEntry.value = countDirectoryEntry; 1634 FsSpace.CountFileEntry.value = countFileEntry; 1635 1636 // Total capacity 1637 var sizeCapacity = parseInt(FsSpace.capacitytypeuser.value) * 1024; 1638 1639 // Correct input value 1640 if (isNaN(sizeCapacity) || sizeCapacity < 0) 1641 { 1642 sizeCapacity = 0; 1643 } 1644 1645 // Rewrite correction result. 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 // Calculate the save data size based on the obtained parameters. 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 // Clear debug output 1683 ClearDebugPrint(); 1684 1685 if (!document.FsSpaceExtEntry) return; 1686 1687 var FsSpace = document.FsSpaceExtEntry; 1688 1689 // Full duplex or half duplex 1690 var option = DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; 1691 1692 // Block size 1693 var sizeArchiveBlock = 4096; 1694 1695 // Icon size 1696 var sizeIcon = parseInt(FsSpace.IconSize.value); 1697 1698 // Correct input value 1699 if (isNaN(sizeIcon) || sizeIcon <= 0) 1700 { 1701 sizeIcon = 1; 1702 } 1703 1704 // Rewrite correction result. 1705 FsSpace.IconSize.value = sizeIcon; 1706 1707 // Maximum number of directories/files 1708 var countDirectoryEntry = parseInt(FsSpace.CountDirectoryEntry.value); 1709 var countFileEntry = parseInt(FsSpace.CountFileEntry.value); 1710 1711 // Correct input value 1712 if (isNaN(countDirectoryEntry) || countDirectoryEntry < 0) 1713 { 1714 countDirectoryEntry = 0; 1715 } 1716 if (isNaN(countFileEntry) || countFileEntry < 1) 1717 { 1718 countFileEntry = 1; 1719 } 1720 1721 // Rewrite correction result. 1722 FsSpace.CountDirectoryEntry.value = countDirectoryEntry; 1723 FsSpace.CountFileEntry.value = countFileEntry; 1724 1725 // Empty the file list 1726 var arrayFileSize = []; 1727 1728 // Calculate the save data size based on the obtained parameters. 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 // Clear debug output 1748 ClearDebugPrint(); 1749 1750 if (!document.FsSpaceExtFile) return; 1751 1752 var FsSpace = document.FsSpaceExtFile; 1753 1754 // Full duplex or half duplex 1755 var option = DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; 1756 1757 // Block size 1758 var sizeArchiveBlock = 4096; 1759 1760 // Total capacity 1761 var sizeCapacity = parseInt(FsSpace.capacitytypeuser.value) * 1024; 1762 1763 // Correct input value 1764 if (isNaN(sizeCapacity) || sizeCapacity < 0) 1765 { 1766 sizeCapacity = 0; 1767 } 1768 1769 // Rewrite correction result. 1770 FsSpace.capacitytypeuser.value = Math.floor(sizeCapacity / 1024); 1771 1772 // Calculate the save data size based on the obtained parameters. 1773 var sizeTotal = ExtSaveDataFilterArchive.QueryFilteredFileSize(sizeCapacity); 1774 var countDataBlock = Math.floor((sizeTotal + sizeArchiveBlock - 1) / sizeArchiveBlock); 1775 1776 // One directory is created for each 124 + 126 * n. Accordingly, display the maximum value that could be used. 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