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 // Management region size is determined 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 // Converts bit -> byte 305 sizeLevel[1] = Math.floor((sizeLevel[1] + 7) / 8); 306 // Align the size with the L1 block boundary 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 the size with the DPFS_BITMAP_ALIGN byte boundary 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 and L1 is aligned to DPFS_BITMAP_ALIGN at least. 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 // The actual data is aligned to the 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 // The actual data size is determined 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 // Management region size is determined 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 // Master hash size is determined 451 outResult.sizeMasterHash = sizeLevel[0]; 452 453 // Build the 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 // Layer hash size is determined 478 outResult.sizeLayeredHash = levelInfo[MAX_LEVEL - 3].offset 479 + levelInfo[MAX_LEVEL - 3].size 480 - levelInfo[0].offset; 481 482 // The actual data size is determined 483 outResult.sizeBody = levelInfo[MAX_LEVEL - 2].size; 484 485 // Total size is determined 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 // Calculate 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 // Calculate 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 // Calculate the size of the 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 the actual data after the duplicated 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 // Integrity verification layer management region 580 offset = AdjustAlignment(offset, 4); 581 offset += resultIntegrity.sizeControlArea; 582 583 // Duplex layer management region 584 offset = AdjustAlignment(offset, 4); 585 offset += resultDuplex.sizeControlArea; 586 587 // Master signature 588 offset = AdjustAlignment(offset, 4); 589 offset += resultIntegrity.sizeMasterHash; 590 591 // Final management region size 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 // The filter file does not use the option region. 626 inputParamDuplex.sizeOptionalInfo = 0; 627 628 // Get the size of the duplex file management region with 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 // Duplex management region A 641 offset = AdjustAlignment(offset, 8/*sizeof(s64)*/); 642 offset += resultDupInt.sizeControlArea; 643 644 // Duplex management region 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 continuing to insert padding, place the data portion after the duplex file management region with the verification feature. 656 // 657 offset = AdjustAlignment(offset, maxBlockSize); 658 offset += resultDupInt.sizeTotalBody;; 659 660 // Return 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 very small, the packet number returns a fixed size. 747 return 3; 748 } 749 if (countEntries <= 19) 750 { 751 // When the number of entries is less than 20, an odd number is returned. 752 return countEntries | 1; 753 } 754 755 // When the number of entries exceeds 20, the distribution state of the packet is considered, and a branch search is performed using a small prime number. 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: Considering standardizing to WStringOnBit64PathStorageArchive.QueryOptimalBucketCount 874 if (countEntries <= 3) 875 { 876 // When the number of entries is very small, the packet number returns a fixed size. 877 return 3; 878 } 879 if (countEntries <= 19) 880 { 881 // When the number of entries is less than 20, an odd number is returned 882 return countEntries | 1; 883 } 884 885 // When the number of entries exceeds 20, the distribution state of the packet is considered, and a branch search is performed using a small prime number. 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 duplex file management region with 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 maximum block size value 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 // While continuing to reproduce the placement status, calculate the size. 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 // Place the data portion after the duplex file management region with verification feature. 1052 // Insert padding to match the maximum block size. 1053 offset = AdjustAlignment(offset, sizeBlock); 1054 offset += resultDupInt.sizeTotalBody; 1055 1056 // Return 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 // Request the actual data size. 1074 var sizeData = SaveDataArchive.QueryMinDataSize( 1075 countDirectoryEntry, 1076 countFileEntry, 1077 countDirectoryEntryBucket, 1078 countFileEntryBucket, 1079 sizeArchiveBlock, 1080 countDataBlock 1081 ); 1082 1083 // Request 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 duplex file management region with verification feature for the metadata. 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 duplex file management region with verification feature for the actual data region. 1104 // Duplicate only signature data of the actual data region. 1105 var resultDupInt2 = new DuplicatedIntegrityFile.QuerySizeResult(); 1106 // Copy the integrity verification parameter (fix the additional information size to 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 maximum block size value 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 // While continuing to reproduce the placement status, calculate the size. 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 // Place the data portion after the duplex file management region with the verification feature (actual data). 1140 // Insert padding to match the maximum block size. 1141 offset = AdjustAlignment(offset, sizeBlock); 1142 offset += resultDupInt1.sizeTotalBody; 1143 1144 // Place the actual data region after the metadata region. 1145 offset = AdjustAlignment(offset, sizeBlock); 1146 offset += resultDupInt2.sizeTotalBody; 1147 1148 // Return 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 parameter 1219 var inputParamDuplex = new HierarchicalDuplexFile.InputParam(); 1220 1221 inputParamDuplex.sizeBlockLevel[0] = 128; 1222 inputParamDuplex.sizeBlockLevel[1] = 4096; 1223 1224 // Integrity verification parameter 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 // Request the file size of the duplex + integrity verification file. 1234 var resultDupIntFilter = new DuplicatedIntegrityFilterFile.QuerySizeResult(); 1235 1236 DuplicatedIntegrityFilterFile.QuerySize( 1237 resultDupIntFilter, 1238 inputParamDuplex, 1239 inputParamIntegrity, 1240 sizeOriginalData, 1241 !isMetaFile // Duplicate all of the metafiles only 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 // Divide into two because ".", "..". 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; // Added directories for user and boss 1335 countFileEntry += 1; // Add icon file portion TODO: Remove when there is 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 that can be in one directory 1353 var countMaxEntryPerDirectory = ExtSaveDataStorageArchive.QueryMaxDirectoryEntryCount( 1354 sizeArchiveBlock, 1355 ExtSaveDataStorageArchive.ENTRY_SIZE 1356 ); 1357 1358 // Number of directories created when the maximum number of files (countFileEntry files) are created 1359 var countMaxDirEntries = Math.floor((countFileEntry + countMaxEntryPerDirectory - 1) / countMaxEntryPerDirectory); 1360 if (countMaxDirEntries == 0) 1361 { 1362 countMaxDirEntries = 1; 1363 } 1364 // Number of blocks required by root 1365 var rootEntryBlocks = Math.floor((countMaxDirEntries + countMaxEntryPerDirectory - 1) / countMaxEntryPerDirectory); 1366 1367 // Number of directories that store files, including 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 directory/file packets 1424 var countDirectoryEntryBucket = DuplicatedIntegritySaveDataArchive 1425 .QueryOptimalBucketCount(countDirectoryEntry); 1426 var countFileEntryBucket = DuplicatedIntegritySaveDataArchive 1427 .QueryOptimalBucketCount(countFileEntry); 1428 1429 // Duplex parameter 1430 var inputParamDuplex = new HierarchicalDuplexFile.InputParam(); 1431 1432 inputParamDuplex.sizeBlockLevel[0] = 128; 1433 inputParamDuplex.sizeBlockLevel[1] = 512 * 8; 1434 1435 // Integrity verification parameter 1436 var inputParamIntegrity = new HierarchicalIntegrityVerificationFile.InputParam(); 1437 1438 // Change according to 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 // Determine whether to exit midway (no changes beyond this even if continued) 1516 if ((countDataBlockMax - countDataBlockMin) <= 1 1517 && (countDataBlock == countDataBlockMin)) 1518 { 1519 break; 1520 } 1521 } 1522 1523 // Calculated block count 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 1550var capacityUnit; 1551var type2BlockSize; 1552 1553function calcFsSpace() 1554{ 1555 // Clear debug output 1556 ClearDebugPrint(); 1557 1558 if (!document.FsSpace) return; 1559 1560 var FsSpace = document.FsSpace; 1561 1562 if (FsSpace.fsblocksize[0].checked) 1563 { 1564 if (FsSpace.capacitytype[2].checked) 1565 { 1566 FsSpace.capacitytype[0].checked = true; 1567 } 1568 1569 FsSpace.capacitytype[0].disabled = false; 1570 FsSpace.capacitytype[0].readonly = true; 1571 1572 FsSpace.capacitytype[1].disabled = false; 1573 FsSpace.capacitytype[1].readonly = true; 1574 1575 FsSpace.capacitytype[2].disabled = true; 1576 FsSpace.capacitytype[2].readonly = false; 1577 } 1578 else 1579 { 1580 FsSpace.capacitytype[2].checked = true; 1581 1582 FsSpace.capacitytype[0].disabled = true; 1583 FsSpace.capacitytype[0].readonly = false; 1584 1585 FsSpace.capacitytype[1].disabled = true; 1586 FsSpace.capacitytype[1].readonly = false; 1587 1588 FsSpace.capacitytype[2].disabled = false; 1589 FsSpace.capacitytype[2].readonly = true; 1590 } 1591 1592 if (FsSpace.capacitytype[2].checked) 1593 { 1594 FsSpace.capacitytypeuser.disabled = false; 1595 FsSpace.capacitytypeuser.readonly = true; 1596 } 1597 else 1598 { 1599 FsSpace.capacitytypeuser.readonly = false; 1600 FsSpace.capacitytypeuser.disabled = true; 1601 } 1602 1603 // Full duplex or half duplex 1604 var option = 0; 1605 if (FsSpace.fstype[0].checked) 1606 { 1607 option |= DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; 1608 } 1609 else if (FsSpace.fstype[1].checked) 1610 { 1611 option |= DuplicatedIntegritySaveDataArchive.DUPLICATE_FULL; 1612 } 1613 1614 // Block size 1615 var sizeArchiveBlock = 512; 1616 if (FsSpace.fsblocksize[1].checked) 1617 { 1618 sizeArchiveBlock = type2BlockSize; 1619 } 1620 1621 // Maximum number of directories/files 1622 var countDirectoryEntry = parseInt(FsSpace.CountDirectoryEntry.value); 1623 var countFileEntry = parseInt(FsSpace.CountFileEntry.value); 1624 1625 // Input value compensation 1626 if (isNaN(countDirectoryEntry) || countDirectoryEntry < 0) 1627 { 1628 countDirectoryEntry = 0; 1629 } 1630 if (isNaN(countFileEntry) || countFileEntry < 1) 1631 { 1632 countFileEntry = 1; 1633 } 1634 1635 // Rewrite compensated result 1636 FsSpace.CountDirectoryEntry.value = countDirectoryEntry; 1637 FsSpace.CountFileEntry.value = countFileEntry; 1638 1639 // Overall capacity 1640 var sizeCapacity = parseInt(FsSpace.capacitytypeuser.value) * capacityUnit; 1641 1642 // Input value compensation 1643 if (isNaN(sizeCapacity) || sizeCapacity < 1 * capacityUnit) 1644 { 1645 sizeCapacity = 1 * capacityUnit; 1646 } else if (sizeCapacity > 2047 * capacityUnit && capacityUnit == 1024 * 1024) 1647 { 1648 // Upper limit corrected only when card2. 1649 sizeCapacity = 2047 * capacityUnit; 1650 } 1651 1652 // Rewrite compensated result 1653 FsSpace.capacitytypeuser.value = Math.floor(sizeCapacity / capacityUnit); 1654 1655 if (FsSpace.capacitytype[0].checked) 1656 { 1657 sizeCapacity = 120 * 1024; 1658 } 1659 else if (FsSpace.capacitytype[1].checked) 1660 { 1661 sizeCapacity = 504 * 1024; 1662 } 1663 1664 // Calculate save data size based on obtained parameters. 1665 var result = new CalcFsSpaceResult(); 1666 1667 calcFsSpaceInternal( 1668 result, 1669 countDirectoryEntry, 1670 countFileEntry, 1671 sizeArchiveBlock, 1672 sizeCapacity, 1673 option 1674 ) 1675 1676 var sizeTotal = result.sizeTotal; 1677 var countDataBlock = result.countDataBlock; 1678 1679 FsSpace.SaveDataBlockSize.value = sizeArchiveBlock; 1680 FsSpace.SaveDataCapacities.value = countDataBlock * sizeArchiveBlock; 1681 FsSpace.SaveDataBlocks.value = countDataBlock; 1682 FsSpace.SaveDataCapacitiesKilloByte.value = Math.floor(countDataBlock * sizeArchiveBlock / 1024); 1683}; 1684 1685/*---------------------------------------------------------------------------*/ 1686 1687function calcFsSpaceExtMeta() 1688{ 1689 // Clear debug output 1690 ClearDebugPrint(); 1691 1692 if (!document.FsSpaceExtEntry) return; 1693 1694 var FsSpace = document.FsSpaceExtEntry; 1695 1696 // Full duplex or half duplex 1697 var option = DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; 1698 1699 // Block size 1700 var sizeArchiveBlock = 4096; 1701 1702 // Icon size 1703 var sizeIcon = parseInt(FsSpace.IconSize.value); 1704 1705 // Input value compensation 1706 if (isNaN(sizeIcon) || sizeIcon <= 0) 1707 { 1708 sizeIcon = 1; 1709 } 1710 1711 // Rewrite compensated result 1712 FsSpace.IconSize.value = sizeIcon; 1713 1714 // Maximum number of directories/files 1715 var countDirectoryEntry = parseInt(FsSpace.CountDirectoryEntry.value); 1716 var countFileEntry = parseInt(FsSpace.CountFileEntry.value); 1717 1718 // Input value compensation 1719 if (isNaN(countDirectoryEntry) || countDirectoryEntry < 0) 1720 { 1721 countDirectoryEntry = 0; 1722 } 1723 if (isNaN(countFileEntry) || countFileEntry < 1) 1724 { 1725 countFileEntry = 1; 1726 } 1727 1728 // Rewrite compensated result 1729 FsSpace.CountDirectoryEntry.value = countDirectoryEntry; 1730 FsSpace.CountFileEntry.value = countFileEntry; 1731 1732 // Blank the file list 1733 var arrayFileSize = []; 1734 1735 // Calculate save data size based on obtained parameters. 1736 var sizeTotal = ExtSaveDataManager.QueryTotalQuotaSize( 1737 sizeArchiveBlock, 1738 countDirectoryEntry, 1739 countFileEntry, 1740 sizeIcon, 1741 arrayFileSize, 1742 0); 1743 var countDataBlock = Math.floor((sizeTotal + sizeArchiveBlock - 1) / sizeArchiveBlock); 1744 1745 FsSpace.ExtSaveDataBlocks.value = countDataBlock; 1746 FsSpace.ExtSaveDataCapacities.value = sizeTotal; 1747 FsSpace.ExtSaveDataCapacitiesKilloByte.value = Math.floor(sizeTotal / 1024); 1748}; 1749 1750/*---------------------------------------------------------------------------*/ 1751 1752function calcFsSpaceExtFile() 1753{ 1754 // Clear debug output 1755 ClearDebugPrint(); 1756 1757 if (!document.FsSpaceExtFile) return; 1758 1759 var FsSpace = document.FsSpaceExtFile; 1760 1761 // Full duplex or half duplex 1762 var option = DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; 1763 1764 // Block size 1765 var sizeArchiveBlock = 4096; 1766 1767 // Overall capacity 1768 var sizeCapacity = parseInt(FsSpace.capacitytypeuser.value) * 1024; 1769 1770 // Input value compensation 1771 if (isNaN(sizeCapacity) || sizeCapacity < 0) 1772 { 1773 sizeCapacity = 0; 1774 } 1775 1776 // Rewrite compensated result 1777 FsSpace.capacitytypeuser.value = Math.floor(sizeCapacity / 1024); 1778 1779 // Calculate save data size based on obtained parameters. 1780 var sizeTotal = ExtSaveDataFilterArchive.QueryFilteredFileSize(sizeCapacity); 1781 var countDataBlock = Math.floor((sizeTotal + sizeArchiveBlock - 1) / sizeArchiveBlock); 1782 1783 // Each 124 + 126 * n times, a directory is created, so the maximum value that can be consumed is displayed 1784 countDataBlock += 1; 1785 sizeTotal = countDataBlock * sizeArchiveBlock; 1786 1787 FsSpace.ExtSaveDataBlocks.value = countDataBlock; 1788 FsSpace.ExtSaveDataCapacities.value = sizeTotal; 1789 FsSpace.ExtSaveDataCapacitiesKilloByte.value = Math.floor(sizeTotal / 1024); 1790}; 1791