/*---------------------------------------------------------------------------* Project: Horizon File: savedata_calc.js Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev:$ *---------------------------------------------------------------------------*/ /*===========================================================================*/ /*! @brief アラインメント調整用関数 */ function AdjustAlignment(val, alignment) { return ((val + (alignment - 1)) & ~(alignment - 1)); }; /*===========================================================================*/ /*! @brief ビット列の左側からの連続する 0 のビットの数を数えます。 */ function CntLz(val) { var x = 0; var n = 32; var c = 16; do { x = val >> c; if (x != 0) { n -= c; val = x; } c >>= 1; } while(c != 0); return (n - val); }; /*---------------------------------------------------------------------------*/ /*! @brief 値が 2 の整数乗かどうかを判定します。 */ function IsPwr2(val) { return (0 == (val & (val - 1))); }; /*---------------------------------------------------------------------------*/ /*! @brief 整数の 2 を底とする対数を計算し、結果を整数で返します。 */ function ILog2(val) { return 31 - CntLz(val); }; /*---------------------------------------------------------------------------*/ /*! @brief 例外定義 */ function ResultInvalidArgument() { }; /*===========================================================================*/ /*! @brief エントリマップテーブル @ref EntryMapTable */ function EntryMapTable() { }; /*---------------------------------------------------------------------------*/ EntryMapTable.STORAGE_SYSTEM_RESERVED = 1; EntryMapTable.DIRECTORY_SYSTEM_RESERVED = 1; EntryMapTable.FILE_SYSTEM_RESERVED = 0; EntryMapTable.INDEX_SIZE = 4; // sizeof(u32) EntryMapTable.STORAGE_INDEX_SIZE = 4; // sizeof(u32) EntryMapTable.DIRECTORY_NAME_SIZE = 16; EntryMapTable.FILE_NAME_SIZE = 16; EntryMapTable.DIRECTORY_INFO_SIZE = 4; // sizeof(bit8[4]) EntryMapTable.FILE_SYSTEM_INFO_SIZE = 4 + // sizeof(u32) 8; // sizeof(S64) EntryMapTable.FILE_OPTIONAL_INFO_SIZE = 4; // sizeof(bit8[4]) EntryMapTable.FILE_INFO_SIZE = EntryMapTable.FILE_NAME_SIZE; EntryMapTable.DIRECTORY_KEY_SIZE = EntryMapTable.STORAGE_INDEX_SIZE + EntryMapTable.DIRECTORY_NAME_SIZE; EntryMapTable.DIRECTORY_VALUE_SIZE = EntryMapTable.STORAGE_INDEX_SIZE + EntryMapTable.STORAGE_INDEX_SIZE + EntryMapTable.STORAGE_INDEX_SIZE + EntryMapTable.DIRECTORY_INFO_SIZE; EntryMapTable.FILE_KEY_SIZE = EntryMapTable.STORAGE_INDEX_SIZE + EntryMapTable.DIRECTORY_NAME_SIZE; EntryMapTable.FILE_VALUE_SIZE = EntryMapTable.STORAGE_INDEX_SIZE + 4 + // PADDING4 EntryMapTable.FILE_INFO_SIZE; EntryMapTable.DIRECTORY_STORAGE_ELEMENT_SIZE = EntryMapTable.DIRECTORY_KEY_SIZE + EntryMapTable.DIRECTORY_VALUE_SIZE + EntryMapTable.INDEX_SIZE; EntryMapTable.FILE_STORAGE_ELEMENT_SIZE = EntryMapTable.FILE_KEY_SIZE + EntryMapTable.FILE_VALUE_SIZE + EntryMapTable.INDEX_SIZE; /*---------------------------------------------------------------------------*/ EntryMapTable.QueryDirectoryEntryStorageSize = function(countDirectoryEntry) { return ((countDirectoryEntry + EntryMapTable.DIRECTORY_SYSTEM_RESERVED) + EntryMapTable.STORAGE_SYSTEM_RESERVED) * EntryMapTable.DIRECTORY_STORAGE_ELEMENT_SIZE; }; /*---------------------------------------------------------------------------*/ EntryMapTable.QueryFileEntryStorageSize = function(countFileEntry) { return ((countFileEntry + EntryMapTable.FILE_SYSTEM_RESERVED) + EntryMapTable.STORAGE_SYSTEM_RESERVED) * EntryMapTable.FILE_STORAGE_ELEMENT_SIZE; }; /*---------------------------------------------------------------------------*/ EntryMapTable.QueryDirectoryEntryBucketStorageSize = function(countDirectoryBucket) { return countDirectoryBucket * EntryMapTable.INDEX_SIZE; }; /*---------------------------------------------------------------------------*/ EntryMapTable.QueryFileEntryBucketStorageSize = function(countFileBucket) { return countFileBucket * EntryMapTable.INDEX_SIZE; }; /*===========================================================================*/ /*! @brief アロケーションテーブル @ref AllocationTableTemplate */ function AllocationTable() { }; /*---------------------------------------------------------------------------*/ AllocationTable.SECTOR_RESERVED_COUNT = 1; AllocationTable.TABLE_ELEMENT_SIZE = 4 // sizeof(u32) + 4;// sizeof(u32) /*---------------------------------------------------------------------------*/ AllocationTable.QuerySize = function(blockCount) { return (blockCount + AllocationTable.SECTOR_RESERVED_COUNT) * AllocationTable.TABLE_ELEMENT_SIZE; }; /*===========================================================================*/ /*! @brief ファイルシステム管理情報 @ref HierarchicalDuplexFile */ function FileSystemControlArea() { }; /*---------------------------------------------------------------------------*/ FileSystemControlArea.STORAGE_INFO_SIZE = 8 // sizeof(s64) + 4 // sizeof(u32) + 4;// PADDING4 FileSystemControlArea.ALLOCATION_INFO_SIZE = 4 // sizeof(u32) + 4 // sizeof(size_t) + 4 // sizeof(u32) + 4;// PADDING4 /*---------------------------------------------------------------------------*/ FileSystemControlArea.QuerySize = function() { var STORAGE_OR_ALLOCATION_INFO_SIZE = FileSystemControlArea.STORAGE_INFO_SIZE; if (FileSystemControlArea.STORAGE_INFO_SIZE < FileSystemControlArea.ALLOCATION_INFO_SIZE) { STORAGE_OR_ALLOCATION_INFO_SIZE = FileSystemControlArea.ALLOCATION_INFO_SIZE; } return (4 + 4 + FileSystemControlArea.STORAGE_INFO_SIZE + FileSystemControlArea.STORAGE_INFO_SIZE + FileSystemControlArea.STORAGE_INFO_SIZE + FileSystemControlArea.STORAGE_INFO_SIZE + STORAGE_OR_ALLOCATION_INFO_SIZE + STORAGE_OR_ALLOCATION_INFO_SIZE); }; /*===========================================================================*/ /*! @brief 階層化二重化ファイル @ref HierarchicalDuplexFile */ function HierarchicalDuplexFile() { }; /*---------------------------------------------------------------------------*/ HierarchicalDuplexFile.DPFS_BITMAP_ALIGN = 4; HierarchicalDuplexFile.MAX_LAYERS = 3; // Master, L1, BODY HierarchicalDuplexFile.LEVEL_INFO_SIZE = 8 // sizeof(Int64) + 8 // sizeof(Int64) + 4 // sizeof(s32) + 4;// PADDING4 HierarchicalDuplexFile.INFOMATION_SIZE = HierarchicalDuplexFile.LEVEL_INFO_SIZE * HierarchicalDuplexFile.MAX_LAYERS; HierarchicalDuplexFile.META_INFO_SIZE = 4 // sizeof(u32) + 4 // sizeof(u32) + HierarchicalDuplexFile.INFOMATION_SIZE /*---------------------------------------------------------------------------*/ HierarchicalDuplexFile.InputParam = function() { this.sizeBlockLevel = new Array(2); }; /*---------------------------------------------------------------------------*/ HierarchicalDuplexFile.LevelInfomation = function() { this.offset = 0; this.size = 0; this.orderBlock = 0; }; /*---------------------------------------------------------------------------*/ HierarchicalDuplexFile.QuerySizeResult = function() { this.sizeControlArea = 0; this.sizeBody = 0; }; /*---------------------------------------------------------------------------*/ HierarchicalDuplexFile.QuerySize = function( outResult, inputParam, sizeData ) { if (inputParam.sizeBlockLevel[0] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[0]) || inputParam.sizeBlockLevel[1] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[1])) { throw new ResultInvalidArgument(); } if (0 != (sizeData % inputParam.sizeBlockLevel[1])) { throw new ResultInvalidArgument(); } if (inputParam.sizeBlockLevel[0] < HierarchicalDuplexFile.DPFS_BITMAP_ALIGN || inputParam.sizeBlockLevel[1] < HierarchicalDuplexFile.DPFS_BITMAP_ALIGN) { throw new ResultInvalidArgument(); } // 管理領域サイズが確定 outResult.sizeControlArea = HierarchicalDuplexFile.META_INFO_SIZE; var MAX_LEVEL = HierarchicalDuplexFile.MAX_LAYERS; var sizeLevel = new Array(MAX_LEVEL); // Body sizeLevel[2] = sizeData; // bit単位のデータサイズ sizeLevel[1] = Math.floor(((sizeLevel[2] + inputParam.sizeBlockLevel[1] - 1) / inputParam.sizeBlockLevel[1])); // bit -> byteに変換します sizeLevel[1] = Math.floor((sizeLevel[1] + 7) / 8); // サイズをL1ブロック境界に整合します sizeLevel[1] = AdjustAlignment(sizeLevel[1], inputParam.sizeBlockLevel[0]); // bit sizeLevel[0] = Math.floor(((sizeLevel[1] + inputParam.sizeBlockLevel[0] - 1) / inputParam.sizeBlockLevel[0])); // bit -> byte sizeLevel[0] = Math.floor((sizeLevel[0] + 7) / 8); // サイズを DPFS_BITMAP_ALIGN バイト境界に整合します sizeLevel[0] = AdjustAlignment(sizeLevel[0], HierarchicalDuplexFile.DPFS_BITMAP_ALIGN); var orderBlock = new Array(MAX_LEVEL); orderBlock[0] = 0; orderBlock[1] = ILog2(inputParam.sizeBlockLevel[0]); orderBlock[2] = ILog2(inputParam.sizeBlockLevel[1]); // Master, L1 は少なくとも DPFS_BITMAP_ALIGN に整合しています。 var offset = 0; var levelInfo = new Array(MAX_LEVEL); var level; for (level = 0; level < MAX_LEVEL; level++) { levelInfo[level] = new HierarchicalDuplexFile.LevelInfomation(); // 実データはL2ブロックサイズに整合しておきます。 if (level == MAX_LEVEL - 1) { offset = AdjustAlignment(offset, inputParam.sizeBlockLevel[1]); } levelInfo[level].offset = offset; levelInfo[level].size = sizeLevel[level]; levelInfo[level].orderBlock = orderBlock[level]; offset += sizeLevel[level] * 2; } // 実データのサイズが確定 outResult.sizeBody = offset; }; /*===========================================================================*/ /*! @brief 階層化完全性検証ファイル @ref HierarchicalDuplexFile */ function HierarchicalIntegrityVerificationFile() { }; /*---------------------------------------------------------------------------*/ HierarchicalIntegrityVerificationFile.HASH_SIZE = Math.floor(256 / 8); HierarchicalIntegrityVerificationFile.MAX_LAYERS = 5; // Master, L1, L2, L3, BODY HierarchicalIntegrityVerificationFile.LEVEL_INFO_SIZE = 8 // sizeof(Int64) + 8 // sizeof(Int64) + 4 // sizeof(s32) + 4;// PADDING4 HierarchicalIntegrityVerificationFile.INFOMATION_SIZE = 4 // sizeof(u32) + HierarchicalIntegrityVerificationFile.LEVEL_INFO_SIZE * (HierarchicalIntegrityVerificationFile.MAX_LAYERS - 1); HierarchicalIntegrityVerificationFile.META_INFO_SIZE = 4 // sizeof(u32) + 4 // sizeof(u32) + 4 // sizeof(u32) + HierarchicalIntegrityVerificationFile.INFOMATION_SIZE + 4 // sizeof(u32) + 4; // sizeof(u32) /*---------------------------------------------------------------------------*/ HierarchicalIntegrityVerificationFile.InputParam = function() { this.sizeOptionalInfo = 0; this.sizeBlockLevel = new Array(HierarchicalIntegrityVerificationFile.MAX_LAYERS - 1); }; /*---------------------------------------------------------------------------*/ HierarchicalIntegrityVerificationFile.LevelInfomation = function() { this.offset = 0; this.size = 0; this.orderBlock = 0; }; /*---------------------------------------------------------------------------*/ HierarchicalIntegrityVerificationFile.QuerySizeResult = function() { this.sizeControlArea = 0; this.sizeMasterHash = 0; this.sizeLayerdHash = 0; this.sizeBody = 0; this.sizeTotal = 0; }; /*---------------------------------------------------------------------------*/ HierarchicalIntegrityVerificationFile.QuerySize = function( outResult, inputParam, sizeData ) { if (inputParam.sizeBlockLevel[0] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[0]) || inputParam.sizeBlockLevel[1] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[1]) || inputParam.sizeBlockLevel[2] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[2]) || inputParam.sizeBlockLevel[3] <= 0 || !IsPwr2(inputParam.sizeBlockLevel[3])) { throw new ResultInvalidArgument(); } var offset = 0; offset += HierarchicalIntegrityVerificationFile.META_INFO_SIZE; offset = AdjustAlignment(offset, 4); offset += inputParam.sizeOptionalInfo; // 管理領域サイズが確定 outResult.sizeControlArea = offset; var MAX_LEVEL = HierarchicalIntegrityVerificationFile.MAX_LAYERS; var HASH_SIZE = HierarchicalIntegrityVerificationFile.HASH_SIZE; var sizeLevel = new Array(MAX_LEVEL); // Body sizeLevel[4] = sizeData; // L3 sizeLevel[3] = Math.floor(((sizeLevel[4] + inputParam.sizeBlockLevel[3] - 1) / inputParam.sizeBlockLevel[3])) * HASH_SIZE; // L2 sizeLevel[2] = Math.floor(((sizeLevel[3] + inputParam.sizeBlockLevel[2] - 1) / inputParam.sizeBlockLevel[2])) * HASH_SIZE; // L1 sizeLevel[1] = Math.floor(((sizeLevel[2] + inputParam.sizeBlockLevel[1] - 1) / inputParam.sizeBlockLevel[1])) * HASH_SIZE; // Master sizeLevel[0] = Math.floor(((sizeLevel[1] + inputParam.sizeBlockLevel[0] - 1) / inputParam.sizeBlockLevel[0])) * HASH_SIZE; var orderBlock = new Array(MAX_LEVEL); orderBlock[1] = ILog2(inputParam.sizeBlockLevel[0]); orderBlock[2] = ILog2(inputParam.sizeBlockLevel[1]); orderBlock[3] = ILog2(inputParam.sizeBlockLevel[2]); orderBlock[4] = ILog2(inputParam.sizeBlockLevel[3]); // マスターハッシュサイズが確定 outResult.sizeMasterHash = sizeLevel[0]; // レベル情報を構築 var levelInfo = new Array(MAX_LEVEL); var level; offset = 0; for (level = 1; level < MAX_LEVEL; level++) { levelInfo[level - 1] = new HierarchicalIntegrityVerificationFile.LevelInfomation(); if (sizeLevel[level] >= (4 << orderBlock[level])) { offset = AdjustAlignment(offset, 1 << orderBlock[level]); } else { offset = AdjustAlignment(offset, 8/*sizeof(s64)*/); } levelInfo[level - 1].offset = offset; levelInfo[level - 1].size = sizeLevel[level]; levelInfo[level - 1].orderBlock = orderBlock[level]; offset += sizeLevel[level]; } // レイヤーハッシュサイズが確定 outResult.sizeLayeredHash = levelInfo[MAX_LEVEL - 3].offset + levelInfo[MAX_LEVEL - 3].size - levelInfo[0].offset; // 実データのサイズが確定 outResult.sizeBody = levelInfo[MAX_LEVEL - 2].size; // トータルサイズが確定 outResult.sizeTotal = levelInfo[MAX_LEVEL - 2].offset + levelInfo[MAX_LEVEL - 2].size - levelInfo[0].offset; }; /*===========================================================================*/ /*! @brief 二重化+完全性検証ファイル @ref DuplicatedIntegrityFile */ function DuplicatedIntegrityFile() { }; /*---------------------------------------------------------------------------*/ DuplicatedIntegrityFile.META_INFO_SIZE = 4 // sizeof(u32) + 4 // sizeof(u32) + 8 // sizeof(Int64) + 8 // sizeof(Int64) + 8 // sizeof(Int64) + 8 // sizeof(Int64) + 8 // sizeof(Int64) + 8 // sizeof(Int64) + 1 // sizeof(bool) + 1 // sizeof(bool) + 2 // PADDING2 + 8;// sizeof(Int64) /*---------------------------------------------------------------------------*/ DuplicatedIntegrityFile.QuerySizeResult = function() { this.sizeControlArea = 0; this.sizeTotalBody = 0; }; /*---------------------------------------------------------------------------*/ DuplicatedIntegrityFile.QuerySize = function( outResult, inputParamDuplex, inputParamIntegrity, sizeOriginalData, isDuplicateOnlyHash ) { // 階層化完全性検証ファイルのサイズを計算します。 var resultIntegrity = new HierarchicalIntegrityVerificationFile.QuerySizeResult(); HierarchicalIntegrityVerificationFile.QuerySize( resultIntegrity, inputParamIntegrity, sizeOriginalData ); var sizeDuplicateOriginal = 0; if (!isDuplicateOnlyHash) { sizeDuplicateOriginal = AdjustAlignment(resultIntegrity.sizeTotal, inputParamDuplex.sizeBlockLevel[1]); } else { sizeDuplicateOriginal = AdjustAlignment(resultIntegrity.sizeLayeredHash, inputParamDuplex.sizeBlockLevel[1]); } // 階層化二重化ファイルのサイズを計算します。 var resultDuplex = new HierarchicalDuplexFile.QuerySizeResult(); HierarchicalDuplexFile.QuerySize( resultDuplex, inputParamDuplex, sizeDuplicateOriginal ); // 二重化+完全性検証ファイルのサイズを計算します。 var offsetOriginalData; if (!isDuplicateOnlyHash) { offsetOriginalData = 0; outResult.sizeTotalBody = resultDuplex.sizeBody; } else { // 二重化した署名データの後ろに実データを配置 offsetOriginalData = AdjustAlignment(resultDuplex.sizeBody, inputParamIntegrity.sizeBlockLevel[3]); outResult.sizeTotalBody = offsetOriginalData + sizeOriginalData; } // メタ情報 var offset = DuplicatedIntegrityFile.META_INFO_SIZE; // 完全性検証レイヤー管理領域 offset = AdjustAlignment(offset, 4); offset += resultIntegrity.sizeControlArea; // 二重化レイヤー管理領域 offset = AdjustAlignment(offset, 4); offset += resultDuplex.sizeControlArea; // マスター署名 offset = AdjustAlignment(offset, 4); offset += resultIntegrity.sizeMasterHash; // 最終的な管理領域のサイズ outResult.sizeControlArea = offset; }; /*===========================================================================*/ /*! @brief 二重化+完全性検証フィルタファイル @ref DuplicatedIntegrityFile */ function DuplicatedIntegrityFilterFile() { }; /*---------------------------------------------------------------------------*/ DuplicatedIntegrityFilterFile.ATOMIC_HEADER_SIZE = 512; /*---------------------------------------------------------------------------*/ DuplicatedIntegrityFilterFile.QuerySizeResult = function() { this.sizeTotalBody = 0; }; /*---------------------------------------------------------------------------*/ DuplicatedIntegrityFilterFile.QuerySize = function( outResult, inputParamDuplex, inputParamIntegrity, sizeOriginalData, isDuplicateOnlyHash ) { // フィルタファイルではオプション領域は使用しません。 inputParamDuplex.sizeOptionalInfo = 0; // 検証機能つき二重化ファイル管理領域のサイズを取得します。 var resultDupInt = new DuplicatedIntegrityFile.QuerySizeResult(); DuplicatedIntegrityFile.QuerySize( resultDupInt, inputParamDuplex, inputParamIntegrity, sizeOriginalData, isDuplicateOnlyHash ); var offset = DuplicatedIntegrityFilterFile.ATOMIC_HEADER_SIZE; // 二重化された管理領域A offset = AdjustAlignment(offset, 8/*sizeof(s64)*/); offset += resultDupInt.sizeControlArea; // 二重化された管理領域B offset = AdjustAlignment(offset, 8/*sizeof(s64)*/); offset += resultDupInt.sizeControlArea; var maxBlockSize = ((inputParamDuplex.sizeBlockLevel[0] - 1) | (inputParamDuplex.sizeBlockLevel[1] - 1) | (inputParamIntegrity.sizeBlockLevel[0] - 1) | (inputParamIntegrity.sizeBlockLevel[1] - 1) | (inputParamIntegrity.sizeBlockLevel[2] - 1) | (inputParamIntegrity.sizeBlockLevel[3] - 1)) + 1; // パディングを挿入しつつ、検証機能つき二重化ファイルの管理領域の後に // データ部を配置します。 offset = AdjustAlignment(offset, maxBlockSize); offset += resultDupInt.sizeTotalBody;; // 最終的なサイズを返します。 outResult.sizeTotalBody = offset; }; /*===========================================================================*/ /*! @brief ファイル ID をパスとするアーカイブを文字列パスを用いて透過的に扱うためのアーカイブクラス @ref WStringOnBit64PathStorageArchive */ function WStringOnBit64PathStorageArchive() { }; /*---------------------------------------------------------------------------*/ WStringOnBit64PathStorageArchive.MAX_PATH_LENGTH = 256; WStringOnBit64PathStorageArchive.ARCHIVE_HEADER_SIZE = 4 // sizeof(u32) + 4 // sizeof(u32) + 8 // sizeof(s64) + 8 // sizeof(s64) + 4 // sizeof(u32) + 4 // PADDING4 + 8 + ( 4 // sizeof(bit32) + 8 // sizeof(FileId) -> sizeof(bit64) + WStringOnBit64PathStorageArchive.MAX_PATH_LENGTH ) // sizeof(transaction) ; /*---------------------------------------------------------------------------*/ WStringOnBit64PathStorageArchive.QueryHeaderSize = function() { return WStringOnBit64PathStorageArchive.ARCHIVE_HEADER_SIZE; }; /*---------------------------------------------------------------------------*/ WStringOnBit64PathStorageArchive.QueryFileSystemControlAreaSize = function() { return FileSystemControlArea.QuerySize(); }; /*---------------------------------------------------------------------------*/ WStringOnBit64PathStorageArchive.QueryDirectoryEntryStorageSize = function(countDirectoryEntry) { return EntryMapTable.QueryDirectoryEntryStorageSize(countDirectoryEntry); }; /*---------------------------------------------------------------------------*/ WStringOnBit64PathStorageArchive.QueryDirectoryEntryBucketStorageSize = function(countDirectoryBucket) { return EntryMapTable.QueryDirectoryEntryBucketStorageSize(countDirectoryBucket); }; /*---------------------------------------------------------------------------*/ WStringOnBit64PathStorageArchive.QueryFileEntryStorageSize = function(countFileEntry) { return EntryMapTable.QueryFileEntryStorageSize(countFileEntry); }; /*---------------------------------------------------------------------------*/ WStringOnBit64PathStorageArchive.QueryFileEntryBucketStorageSize = function(countFileBucket) { return EntryMapTable.QueryFileEntryBucketStorageSize(countFileBucket); }; /*---------------------------------------------------------------------------*/ WStringOnBit64PathStorageArchive.QueryAllocationTableStorageSize = function(countDataBlock) { return AllocationTable.QuerySize(countDataBlock); }; /*---------------------------------------------------------------------------*/ WStringOnBit64PathStorageArchive.QueryOptimalBucketCount = function(countEntries) { if (countEntries <= 3) { // エントリー数が極めて少ない場合、バケット数は固定サイズを返します。 return 3; } if (countEntries <= 19) { // エントリー数が 20 個未満の場合、奇数にして返します。 return countEntries | 1; } // エントリー数が20個を超える場合、バケットの分散具合を考慮し、 // 小さな値の素数で枝狩りを行います。 var i; for (i = 0;i < 100;i++) { var candidate = (countEntries + i); if ( (candidate % 2) != 0 && (candidate % 3) != 0 && (candidate % 5) != 0 && (candidate % 7) != 0 && (candidate % 11) != 0 && (candidate % 13) != 0 && (candidate % 17) != 0 ) { return candidate; } } return countEntries | 1; }; /*---------------------------------------------------------------------------*/ WStringOnBit64PathStorageArchive.QueryTotalSize = function( countDirectoryEntry, countDirectoryEntryBucket, countFileEntry, countFileEntryBucket, sizeBlock ) { var sizeDirectoryEntry = WStringOnBit64PathStorageArchive.QueryDirectoryEntryStorageSize(countDirectoryEntry); var blockCountDirectoryEntry = Math.floor((sizeDirectoryEntry + sizeBlock - 1) / sizeBlock); var sizeFileEntry = WStringOnBit64PathStorageArchive.QueryFileEntryStorageSize(countFileEntry); var blockCountFileEntry = Math.floor((sizeFileEntry + sizeBlock - 1) / sizeBlock); var sizeFixed = WStringOnBit64PathStorageArchive.QueryHeaderSize() + WStringOnBit64PathStorageArchive.QueryFileSystemControlAreaSize() + WStringOnBit64PathStorageArchive.QueryDirectoryEntryBucketStorageSize(countDirectoryEntryBucket) + WStringOnBit64PathStorageArchive.QueryFileEntryBucketStorageSize(countFileEntryBucket) + WStringOnBit64PathStorageArchive.QueryAllocationTableStorageSize(blockCountDirectoryEntry + blockCountFileEntry) ; sizeFixed = AdjustAlignment(sizeFixed, sizeBlock); return sizeFixed + sizeBlock * (blockCountDirectoryEntry + blockCountFileEntry); } /*===========================================================================*/ /*! @brief セーブデータアーカイブクラス @ref SaveDataArchiveTemplate */ function SaveDataArchive() { }; /*---------------------------------------------------------------------------*/ SaveDataArchive.ARCHIVE_HEADER_SIZE = 4 // sizeof(u32) + 4 // sizeof(u32) + 8 // sizeof(s64) + 8 // sizeof(s64) + 4 // sizeof(u32) + 4;// PADDING4 /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryHeaderSize = function() { return SaveDataArchive.ARCHIVE_HEADER_SIZE; }; /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryFileSystemControlAreaSize = function() { return FileSystemControlArea.QuerySize(); }; /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryDirectoryEntryStorageSize = function(countDirectoryEntry) { return EntryMapTable.QueryDirectoryEntryStorageSize(countDirectoryEntry); }; /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryDirectoryEntryBucketStorageSize = function(countDirectoryBucket) { return EntryMapTable.QueryDirectoryEntryBucketStorageSize(countDirectoryBucket); }; /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryFileEntryStorageSize = function(countFileEntry) { return EntryMapTable.QueryFileEntryStorageSize(countFileEntry); }; /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryFileEntryBucketStorageSize = function(countFileBucket) { return EntryMapTable.QueryFileEntryBucketStorageSize(countFileBucket); }; /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryAllocationTableStorageSize = function(countDataBlock) { return AllocationTable.QuerySize(countDataBlock); }; /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryOptimalBucketCount = function(countEntries) { // TODO: WStringOnBit64PathStorageArchive.QueryOptimalBucketCount に統一することを検討 if (countEntries <= 3) { // エントリー数が極めて少ない場合、バケット数は固定サイズを返します。 return 3; } if (countEntries <= 19) { // エントリー数が 20 個未満の場合、奇数にして返します return countEntries | 1; } // エントリー数が20個を超える場合、バケットの分散具合を考慮し、 // 小さな値の素数で枝狩りを行います。 var i; for (i = 0; i < 100; i++) { var candidate = (countEntries + i); if ( (candidate % 2) != 0 && (candidate % 3) != 0 && (candidate % 5) != 0 && (candidate % 7) != 0 && (candidate % 11) != 0 && (candidate % 13) != 0 && (candidate % 17) != 0 ) { return candidate; } } return countEntries | 1; }; /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryMinDataSize = function( countDirectoryEntry, countFileEntry, countDirectoryBucket, countFileBucket, sizeBlock, countDataBlock ) { if (countDirectoryBucket <= 0 || countFileBucket <= 0) { throw new ResultInvalidArgument(); } /* var sizeDirectoryEntry = SaveDataArchive.QueryDirectoryEntryStorageSize(countDirectoryEntry); var blockCountDirectoryEntry = Math.floor((sizeDirectoryEntry + sizeBlock - 1) / sizeBlock); var sizeFileEntry = SaveDataArchive.QueryFileEntryStorageSize(countFileEntry); var blockCountFileEntry = Math.floor((sizeFileEntry + sizeBlock - 1) / sizeBlock); return sizeBlock * (blockCountDirectoryEntry + blockCountFileEntry + countDataBlock); */ return sizeBlock * countDataBlock; }; /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryMetaSize = function( countDirectoryEntry, countFileEntry, countDirectoryBucket, countFileBucket, sizeBlock, countDataBlock ) { var sizeFixed = SaveDataArchive.QueryHeaderSize() + SaveDataArchive.QueryFileSystemControlAreaSize() + SaveDataArchive.QueryDirectoryEntryBucketStorageSize(countDirectoryBucket) + SaveDataArchive.QueryFileEntryBucketStorageSize(countFileBucket) + SaveDataArchive.QueryAllocationTableStorageSize(countDataBlock) + SaveDataArchive.QueryDirectoryEntryStorageSize(countDirectoryEntry) + SaveDataArchive.QueryFileEntryStorageSize(countFileEntry); return AdjustAlignment(sizeFixed, sizeBlock); }; /*---------------------------------------------------------------------------*/ SaveDataArchive.QueryTotalSize = function( countDirectoryEntry, countFileEntry, countDirectoryBucket, countFileBucket, sizeBlock, countDataBlock ) { var sizeDirectoryEntry = SaveDataArchive.QueryDirectoryEntryStorageSize(countDirectoryEntry); var blockCountDirectoryEntry = Math.floor((sizeDirectoryEntry + sizeBlock - 1) / sizeBlock); var sizeFileEntry = SaveDataArchive.QueryFileEntryStorageSize(countFileEntry); var blockCountFileEntry = Math.floor((sizeFileEntry + sizeBlock - 1) / sizeBlock); var sizeFixed = SaveDataArchive.QueryHeaderSize() + SaveDataArchive.QueryFileSystemControlAreaSize() + SaveDataArchive.QueryDirectoryEntryBucketStorageSize(countDirectoryBucket) + SaveDataArchive.QueryFileEntryBucketStorageSize(countFileBucket) + SaveDataArchive.QueryAllocationTableStorageSize(blockCountDirectoryEntry + blockCountFileEntry + countDataBlock); sizeFixed = AdjustAlignment(sizeFixed, sizeBlock); return sizeFixed + sizeBlock * (blockCountDirectoryEntry + blockCountFileEntry + countDataBlock); }; /*===========================================================================*/ /*! @brief 二重化+完全性検証セーブデータアーカイブクラス @ref DuplicatedIntegritySaveDataArchive */ function DuplicatedIntegritySaveDataArchive() { }; /*---------------------------------------------------------------------------*/ DuplicatedIntegritySaveDataArchive.DUPLICATE_FULL = 0x0001; //!< 全二重化 DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META = 0x0002; //!< 半二重化 DuplicatedIntegritySaveDataArchive.ATOMIC_HEADER_SIZE = 512; /*---------------------------------------------------------------------------*/ DuplicatedIntegritySaveDataArchive.QueryOptimalBucketCount = function(countEntries) { return SaveDataArchive.QueryOptimalBucketCount(countEntries); }; /*---------------------------------------------------------------------------*/ DuplicatedIntegritySaveDataArchive.QuerySizeAsFullDuplication = function( inputParamDuplex, inputParamIntegrity, sizeArchiveBlock, countDirectoryEntry, countFileEntry, countDirectoryEntryBucket, countFileEntryBucket, countDataBlock ) { var sizeArchive = SaveDataArchive.QueryTotalSize( countDirectoryEntry, countFileEntry, countDirectoryEntryBucket, countFileEntryBucket, sizeArchiveBlock, countDataBlock ); // 検証機能つき二重化ファイル管理領域のサイズを取得します。 var resultDupInt = new DuplicatedIntegrityFile.QuerySizeResult(); DuplicatedIntegrityFile.QuerySize( resultDupInt, inputParamDuplex, inputParamIntegrity, sizeArchive, false ); // ブロックサイズの最大値を計算 var sizeBlock =((inputParamDuplex.sizeBlockLevel[0] - 1)| (inputParamDuplex.sizeBlockLevel[1] - 1)| (inputParamIntegrity.sizeBlockLevel[0] - 1)| (inputParamIntegrity.sizeBlockLevel[1] - 1)| (inputParamIntegrity.sizeBlockLevel[2] - 1)| (inputParamIntegrity.sizeBlockLevel[3] - 1)) + 1; // 配置状態を再現しつつサイズを計算します。 var offsetControlAreaA = DuplicatedIntegritySaveDataArchive.ATOMIC_HEADER_SIZE; var sizeControlAreaAB = resultDupInt.sizeControlArea; var offset = offsetControlAreaA; offset += sizeControlAreaAB; offset = AdjustAlignment(offset, 8/*sizeof(s64)*/); offset += sizeControlAreaAB; // 検証機能つき二重化ファイルの管理領域の後にデータ部分を配置します。 // 最大のブロックサイズに合わせるためパディングを挿入します。 offset = AdjustAlignment(offset, sizeBlock); offset += resultDupInt.sizeTotalBody; // 総データサイズを返します。 return offset; }; /*---------------------------------------------------------------------------*/ DuplicatedIntegritySaveDataArchive.QuerySizeAsMetaDuplication = function( inputParamDuplex, inputParamIntegrity, sizeArchiveBlock, countDirectoryEntry, countFileEntry, countDirectoryEntryBucket, countFileEntryBucket, countDataBlock ) { // 実データのサイズを求めます。 var sizeData = SaveDataArchive.QueryMinDataSize( countDirectoryEntry, countFileEntry, countDirectoryEntryBucket, countFileEntryBucket, sizeArchiveBlock, countDataBlock ); // メタデータのサイズを求めます。 var sizeMeta = SaveDataArchive.QueryMetaSize( countDirectoryEntry, countFileEntry, countDirectoryEntryBucket, countFileEntryBucket, sizeArchiveBlock, Math.floor(sizeData / sizeArchiveBlock) ); // メタデータに対する検証機能つき二重化ファイル管理領域のサイズを取得します。 var resultDupInt1 = new DuplicatedIntegrityFile.QuerySizeResult(); DuplicatedIntegrityFile.QuerySize( resultDupInt1, inputParamDuplex, inputParamIntegrity, sizeMeta, false ); // 実データ領域に対する検証機能つき二重化ファイル管理領域のサイズを取得します。 // 実データ領域の署名データのみ二重化します。 var resultDupInt2 = new DuplicatedIntegrityFile.QuerySizeResult(); // 完全性検証パラメータを複製(付加情報サイズを 0 に固定) var inputParamIntegrity2 = new HierarchicalIntegrityVerificationFile.InputParam(); inputParamIntegrity2 = inputParamIntegrity; inputParamIntegrity2.sizeOptionalInfo = 0; DuplicatedIntegrityFile.QuerySize( resultDupInt2, inputParamDuplex, inputParamIntegrity2, sizeData, true ); // ブロックサイズの最大値を計算 var sizeBlock =((inputParamDuplex.sizeBlockLevel[0] - 1)| (inputParamDuplex.sizeBlockLevel[1] - 1)| (inputParamIntegrity.sizeBlockLevel[0] - 1)| (inputParamIntegrity.sizeBlockLevel[1] - 1)| (inputParamIntegrity.sizeBlockLevel[2] - 1)| (inputParamIntegrity.sizeBlockLevel[3] - 1)) + 1; // 配置状態を再現しつつサイズを計算します。 var offsetDuplicatedIntegrityControlArea1 = DuplicatedIntegritySaveDataArchive.ATOMIC_HEADER_SIZE; var offsetDuplicatedIntegrityControlArea2 = AdjustAlignment(resultDupInt1.sizeControlArea, 8/*sizeof(s64)*/); var sizeControlAreaAB = offsetDuplicatedIntegrityControlArea2 + AdjustAlignment(resultDupInt2.sizeControlArea, 8/*sizeof(s64)*/); var offset = offsetDuplicatedIntegrityControlArea1; offset += sizeControlAreaAB; offset += sizeControlAreaAB; // 検証機能つき二重化ファイルの管理領域(実データ)の後にメタデータ領域を配置します。 // 最大のブロックサイズに合わせるためパディングを挿入します。 offset = AdjustAlignment(offset, sizeBlock); offset += resultDupInt1.sizeTotalBody; // メタデータ領域の後に実データ領域を配置します。 offset = AdjustAlignment(offset, sizeBlock); offset += resultDupInt2.sizeTotalBody; // 総データサイズを返します。 return offset; }; /*---------------------------------------------------------------------------*/ DuplicatedIntegritySaveDataArchive.QuerySize = function( inputParamDuplex, inputParamIntegrity, sizeArchiveBlock, countDirectoryEntry, countFileEntry, countDirectoryEntryBucket, countFileEntryBucket, countDataBlock, option ) { var sizeTotal = 0; if (option & DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META) { sizeTotal = DuplicatedIntegritySaveDataArchive.QuerySizeAsMetaDuplication( inputParamDuplex, inputParamIntegrity, sizeArchiveBlock, countDirectoryEntry, countFileEntry, countDirectoryEntryBucket, countFileEntryBucket, countDataBlock ); } else if (option & DuplicatedIntegritySaveDataArchive.DUPLICATE_FULL) { sizeTotal = DuplicatedIntegritySaveDataArchive.QuerySizeAsFullDuplication( inputParamDuplex, inputParamIntegrity, sizeArchiveBlock, countDirectoryEntry, countFileEntry, countDirectoryEntryBucket, countFileEntryBucket, countDataBlock ); } else { throw new ResultInvalidArgument(); } return sizeTotal; }; /*===========================================================================*/ /*! @brief 拡張セーブデータフィルタアーカイブクラス @ref ExtSaveDataFilterArchive */ function ExtSaveDataFilterArchive() { }; /*---------------------------------------------------------------------------*/ ExtSaveDataFilterArchive.QueryFilteredFileSizeInternal = function( sizeOriginalData, isMetaFile ) { // 二重化パラメータ var inputParamDuplex = new HierarchicalDuplexFile.InputParam(); inputParamDuplex.sizeBlockLevel[0] = 128; inputParamDuplex.sizeBlockLevel[1] = 4096; // 完全性検証パラメータ var inputParamIntegrity = new HierarchicalIntegrityVerificationFile.InputParam(); inputParamIntegrity.sizeBlockLevel[0] = 512; inputParamIntegrity.sizeBlockLevel[1] = 512; inputParamIntegrity.sizeBlockLevel[2] = 4096; inputParamIntegrity.sizeBlockLevel[3] = 4096; inputParamIntegrity.sizeOptionalInfo = 0; // 二重化+完全性検証フィルタファイルのサイズを求めます。 var resultDupIntFilter = new DuplicatedIntegrityFilterFile.QuerySizeResult(); DuplicatedIntegrityFilterFile.QuerySize( resultDupIntFilter, inputParamDuplex, inputParamIntegrity, sizeOriginalData, !isMetaFile // メタファイルのみ全二重化 ); return resultDupIntFilter.sizeTotalBody; }; /*---------------------------------------------------------------------------*/ ExtSaveDataFilterArchive.QueryFilteredMetaFileSize = function( sizeMetaData ) { return ExtSaveDataFilterArchive.QueryFilteredFileSizeInternal( sizeMetaData, true ); }; /*---------------------------------------------------------------------------*/ ExtSaveDataFilterArchive.QueryFilteredFileSize = function( sizeOriginalData ) { return ExtSaveDataFilterArchive.QueryFilteredFileSizeInternal( sizeOriginalData, false ); }; /*===========================================================================*/ /*! @brief 拡張セーブデータストレージアーカイブクラス @ref ExtSaveDataStorageArchive */ function ExtSaveDataStorageArchive() { }; /*---------------------------------------------------------------------------*/ ExtSaveDataStorageArchive.ENTRY_SIZE = 32; /*---------------------------------------------------------------------------*/ ExtSaveDataStorageArchive.QueryMaxDirectoryEntryCount = function( sizeArchiveBlock, sizeEntry ) { // "."、".."のために 2 つ分除きます。 return Math.floor(sizeArchiveBlock / sizeEntry) - 2; } /*===========================================================================*/ /*! @brief 拡張セーブデータ管理クラス @ref ExtSaveDataManager */ function ExtSaveDataManager() { }; /*---------------------------------------------------------------------------*/ ExtSaveDataManager.QueryMetaDataSize = function( sizeArchiveBlock, countDirectoryEntry, countFileEntry ) { var countDirectoryBucket = WStringOnBit64PathStorageArchive.QueryOptimalBucketCount(countDirectoryEntry); var countFileBucket = WStringOnBit64PathStorageArchive.QueryOptimalBucketCount(countFileEntry); return WStringOnBit64PathStorageArchive.QueryTotalSize( countDirectoryEntry, countDirectoryBucket, countFileEntry, countFileBucket, sizeArchiveBlock ); }; /*---------------------------------------------------------------------------*/ ExtSaveDataManager.QueryTotalQuotaSize = function( sizeArchiveBlock, countDirectoryEntry, countFileEntry, sizeIcon, fileSizeArray, fileSizeArrayLength ) { countDirectoryEntry += 2; // user, boss ディレクトリの分を追加 countFileEntry += 1; // icon ファイルの分を追加 TODO: 共有拡張セーブデータの場合ははずす? var sizeMetaData = ExtSaveDataManager.QueryMetaDataSize( sizeArchiveBlock, countDirectoryEntry, countFileEntry ); var resultDupIntFilter = new DuplicatedIntegrityFilterFile.QuerySizeResult(); var sizeFilteredMetaData = ExtSaveDataFilterArchive.QueryFilteredMetaFileSize(sizeMetaData); var filteredMetaDataBlocks = Math.floor((sizeFilteredMetaData + sizeArchiveBlock - 1) / sizeArchiveBlock); var fileBlocks = 0; for (var i = 0; i < fileSizeArrayLength; i++) { var sizeFilteredFile = ExtSaveDataFilterArchive.QueryFilteredFileSize(fileSizeArray[i]); fileBlocks += Math.floor((sizeFilteredFile + sizeArchiveBlock - 1) / sizeArchiveBlock); } // ディレクトリひとつ当たりに入るファイル数 var countMaxEntryPerDirectory = ExtSaveDataStorageArchive.QueryMaxDirectoryEntryCount( sizeArchiveBlock, ExtSaveDataStorageArchive.ENTRY_SIZE ); // ファイル数を最大まで(countFileEntry個)作成したときに作られるディレクトリの数 var countMaxDirEntries = Math.floor((countFileEntry + countMaxEntryPerDirectory - 1) / countMaxEntryPerDirectory); if (countMaxDirEntries == 0) { countMaxDirEntries = 1; } // ルートが必要とするブロック数 var rootEntryBlocks = Math.floor((countMaxDirEntries + countMaxEntryPerDirectory - 1) / countMaxEntryPerDirectory); // メタファイルやアイコンファイルを含むファイルが格納されるディレクトリの数 var countDirEntries = Math.floor(((fileSizeArrayLength + 2) + countMaxEntryPerDirectory - 1) / countMaxEntryPerDirectory); var iconBlocks = 0; { var sizeFilterdIcon = ExtSaveDataFilterArchive.QueryFilteredFileSize(sizeIcon); iconBlocks = Math.floor((sizeFilterdIcon + sizeArchiveBlock - 1) / sizeArchiveBlock); } return (filteredMetaDataBlocks + fileBlocks + countDirEntries + rootEntryBlocks + iconBlocks) * sizeArchiveBlock; }; /*===========================================================================*/ function ClearDebugPrint() { if (!document.FsDebug) return; var out = document.FsDebug.output; if (!out) return; out.value = ""; }; /*---------------------------------------------------------------------------*/ function DebugPrint(str) { if (!document.FsDebug) return; var out = document.FsDebug.output; if (!out) return; out.value += str + "\n"; }; /*===========================================================================*/ CalcFsSpaceResult = function() { this.sizeTotal = 0; this.countDataBlock = 0; }; /*---------------------------------------------------------------------------*/ function calcFsSpaceInternal( outResult, countDirectoryEntry, countFileEntry, sizeArchiveBlock, sizeCapacity, option ) { // ディレクトリ/ファイルバケット数 var countDirectoryEntryBucket = DuplicatedIntegritySaveDataArchive .QueryOptimalBucketCount(countDirectoryEntry); var countFileEntryBucket = DuplicatedIntegritySaveDataArchive .QueryOptimalBucketCount(countFileEntry); // 二重化パラメータ var inputParamDuplex = new HierarchicalDuplexFile.InputParam(); inputParamDuplex.sizeBlockLevel[0] = 128; inputParamDuplex.sizeBlockLevel[1] = 512 * 8; // 完全性検証パラメータ var inputParamIntegrity = new HierarchicalIntegrityVerificationFile.InputParam(); // 二重化タイプとブロックサイズに応じて変更 switch (sizeArchiveBlock) { case 512: if (option & DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META) { inputParamIntegrity.sizeBlockLevel[0] = 512; inputParamIntegrity.sizeBlockLevel[1] = 512; inputParamIntegrity.sizeBlockLevel[2] = 512 * 8; inputParamIntegrity.sizeBlockLevel[3] = 512; inputParamIntegrity.sizeOptionalInfo = 0; } else if (option & DuplicatedIntegritySaveDataArchive.DUPLICATE_FULL) { inputParamIntegrity.sizeBlockLevel[0] = 512; inputParamIntegrity.sizeBlockLevel[1] = 512; inputParamIntegrity.sizeBlockLevel[2] = 512 * 8; inputParamIntegrity.sizeBlockLevel[3] = 512 * 8; inputParamIntegrity.sizeOptionalInfo = 0; } else { throw new ResultInvalidArgument(); } break; case 4096: { inputParamIntegrity.sizeBlockLevel[0] = 512; inputParamIntegrity.sizeBlockLevel[1] = 512; inputParamIntegrity.sizeBlockLevel[2] = 512 * 8; inputParamIntegrity.sizeBlockLevel[3] = 512 * 8; inputParamIntegrity.sizeOptionalInfo = 0; } break; default: throw new ResultInvalidArgument(); break; } // トータルサイズ var sizeTotal = 0; // キャパシティに合うように総ブロック数を調整します。 var countDataBlockMin = 0; var countDataBlockMax = Math.floor(sizeCapacity / sizeArchiveBlock); var retryCount = 32; while (1 <= (countDataBlockMax - countDataBlockMin) && (0 < retryCount--)) { var countDataBlock = Math.floor((countDataBlockMin + countDataBlockMax) / 2); sizeTotal = DuplicatedIntegritySaveDataArchive.QuerySize( inputParamDuplex, inputParamIntegrity, sizeArchiveBlock, countDirectoryEntry, countFileEntry, countDirectoryEntryBucket, countFileEntryBucket, countDataBlock, option ); DebugPrint("sizeCapacity = " + sizeCapacity + ", sizeTotal = " + sizeTotal + ", countDataBlockMax = " + countDataBlockMax + ", countDataBlockMin = " + countDataBlockMin); if (sizeTotal > sizeCapacity) { countDataBlockMax = countDataBlock; } else { countDataBlockMin = countDataBlock; } // 途中抜け判定(これ以上継続しても変化なし) if ((countDataBlockMax - countDataBlockMin) <= 1 && (countDataBlock == countDataBlockMin)) { break; } } // 計算されたブロック数 outResult.countDataBlock = countDataBlockMin; // 最終的なサイズを計算します。 sizeTotal = DuplicatedIntegritySaveDataArchive.QuerySize( inputParamDuplex, inputParamIntegrity, sizeArchiveBlock, countDirectoryEntry, countFileEntry, countDirectoryEntryBucket, countFileEntryBucket, countDataBlock, option ); if (sizeTotal <= sizeCapacity) { outResult.sizeTotal = sizeTotal; } else { outResult.sizeTotal = sizeTotal; } }; /*---------------------------------------------------------------------------*/ function calcFsSpace() { // デバッグ出力クリア ClearDebugPrint(); if (!document.FsSpace) return; var FsSpace = document.FsSpace; if (FsSpace.fsblocksize[0].checked) { if (FsSpace.capacitytype[2].checked) { FsSpace.capacitytype[0].checked = true; } FsSpace.capacitytype[0].disabled = false; FsSpace.capacitytype[0].readonly = true; FsSpace.capacitytype[1].disabled = false; FsSpace.capacitytype[1].readonly = true; FsSpace.capacitytype[2].disabled = true; FsSpace.capacitytype[2].readonly = false; } else { FsSpace.capacitytype[2].checked = true; FsSpace.capacitytype[0].disabled = true; FsSpace.capacitytype[0].readonly = false; FsSpace.capacitytype[1].disabled = true; FsSpace.capacitytype[1].readonly = false; FsSpace.capacitytype[2].disabled = false; FsSpace.capacitytype[2].readonly = true; } if (FsSpace.capacitytype[2].checked) { FsSpace.capacitytypeuser.disabled = false; FsSpace.capacitytypeuser.readonly = true; } else { FsSpace.capacitytypeuser.readonly = false; FsSpace.capacitytypeuser.disabled = true; } // 全二重 or 半二重 var option = 0; if (FsSpace.fstype[0].checked) { option |= DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; } else if (FsSpace.fstype[1].checked) { option |= DuplicatedIntegritySaveDataArchive.DUPLICATE_FULL; } // ブロックサイズ var sizeArchiveBlock = 512; if (FsSpace.fsblocksize[1].checked) { sizeArchiveBlock = 4096; } // 最大ディレクトリ/ファイル数 var countDirectoryEntry = parseInt(FsSpace.CountDirectoryEntry.value); var countFileEntry = parseInt(FsSpace.CountFileEntry.value); // 入力値の補正 if (isNaN(countDirectoryEntry) || countDirectoryEntry < 0) { countDirectoryEntry = 0; } if (isNaN(countFileEntry) || countFileEntry < 1) { countFileEntry = 1; } // 補正結果を書き戻す FsSpace.CountDirectoryEntry.value = countDirectoryEntry; FsSpace.CountFileEntry.value = countFileEntry; // 全体容量 var sizeCapacity = parseInt(FsSpace.capacitytypeuser.value) * 1024; // 入力値の補正 if (isNaN(sizeCapacity) || sizeCapacity < 0) { sizeCapacity = 0; } // 補正結果を書き戻す FsSpace.capacitytypeuser.value = Math.floor(sizeCapacity / 1024); if (FsSpace.capacitytype[0].checked) { sizeCapacity = 120 * 1024; } else if (FsSpace.capacitytype[1].checked) { sizeCapacity = 504 * 1024; } // 得られたパラメータを元にセーブデータサイズを計算します。 var result = new CalcFsSpaceResult(); calcFsSpaceInternal( result, countDirectoryEntry, countFileEntry, sizeArchiveBlock, sizeCapacity, option ) var sizeTotal = result.sizeTotal; var countDataBlock = result.countDataBlock; FsSpace.SaveDataBlockSize.value = sizeArchiveBlock; FsSpace.SaveDataCapacities.value = countDataBlock * sizeArchiveBlock; FsSpace.SaveDataBlocks.value = countDataBlock; FsSpace.SaveDataCapacitiesKilloByte.value = Math.floor(countDataBlock * sizeArchiveBlock / 1024); }; /*---------------------------------------------------------------------------*/ function calcFsSpaceExtMeta() { // デバッグ出力クリア ClearDebugPrint(); if (!document.FsSpaceExtEntry) return; var FsSpace = document.FsSpaceExtEntry; // 全二重 or 半二重 var option = DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; // ブロックサイズ var sizeArchiveBlock = 4096; // アイコンサイズ var sizeIcon = parseInt(FsSpace.IconSize.value); // 入力値の補正 if (isNaN(sizeIcon) || sizeIcon <= 0) { sizeIcon = 1; } // 補正結果を書き戻す FsSpace.IconSize.value = sizeIcon; // 最大ディレクトリ/ファイル数 var countDirectoryEntry = parseInt(FsSpace.CountDirectoryEntry.value); var countFileEntry = parseInt(FsSpace.CountFileEntry.value); // 入力値の補正 if (isNaN(countDirectoryEntry) || countDirectoryEntry < 0) { countDirectoryEntry = 0; } if (isNaN(countFileEntry) || countFileEntry < 1) { countFileEntry = 1; } // 補正結果を書き戻す FsSpace.CountDirectoryEntry.value = countDirectoryEntry; FsSpace.CountFileEntry.value = countFileEntry; // ファイル一覧は空とします var arrayFileSize = []; // 得られたパラメータを元にセーブデータサイズを計算します。 var sizeTotal = ExtSaveDataManager.QueryTotalQuotaSize( sizeArchiveBlock, countDirectoryEntry, countFileEntry, sizeIcon, arrayFileSize, 0); var countDataBlock = Math.floor((sizeTotal + sizeArchiveBlock - 1) / sizeArchiveBlock); FsSpace.ExtSaveDataBlocks.value = countDataBlock; FsSpace.ExtSaveDataCapacities.value = sizeTotal; FsSpace.ExtSaveDataCapacitiesKilloByte.value = Math.floor(sizeTotal / 1024); }; /*---------------------------------------------------------------------------*/ function calcFsSpaceExtFile() { // デバッグ出力クリア ClearDebugPrint(); if (!document.FsSpaceExtFile) return; var FsSpace = document.FsSpaceExtFile; // 全二重 or 半二重 var option = DuplicatedIntegritySaveDataArchive.DUPLICATE_ONLY_META; // ブロックサイズ var sizeArchiveBlock = 4096; // 全体容量 var sizeCapacity = parseInt(FsSpace.capacitytypeuser.value) * 1024; // 入力値の補正 if (isNaN(sizeCapacity) || sizeCapacity < 0) { sizeCapacity = 0; } // 補正結果を書き戻す FsSpace.capacitytypeuser.value = Math.floor(sizeCapacity / 1024); // 得られたパラメータを元にセーブデータサイズを計算します。 var sizeTotal = ExtSaveDataFilterArchive.QueryFilteredFileSize(sizeCapacity); var countDataBlock = Math.floor((sizeTotal + sizeArchiveBlock - 1) / sizeArchiveBlock); // 124 + 126 * n個のたびにディレクトリが1つ作られるので、消費される可能性のある最大値を表示しておく countDataBlock += 1; sizeTotal = countDataBlock * sizeArchiveBlock; FsSpace.ExtSaveDataBlocks.value = countDataBlock; FsSpace.ExtSaveDataCapacities.value = sizeTotal; FsSpace.ExtSaveDataCapacitiesKilloByte.value = Math.floor(sizeTotal / 1024); };