From e47e37a8d285776a804116b45cfb4fd51a74ae25 Mon Sep 17 00:00:00 2001 From: lioncash Date: Mon, 31 Mar 2014 08:56:24 -0400 Subject: [PATCH 1/3] Fix some memory leaks in unedat.cpp. --- rpcs3/Crypto/unedat.cpp | 435 +++++++++++++++++++++------------------- 1 file changed, 228 insertions(+), 207 deletions(-) diff --git a/rpcs3/Crypto/unedat.cpp b/rpcs3/Crypto/unedat.cpp index 65641919cb..dd632bbb9a 100644 --- a/rpcs3/Crypto/unedat.cpp +++ b/rpcs3/Crypto/unedat.cpp @@ -1,135 +1,135 @@ #include "stdafx.h" #include "unedat.h" -void generate_key(int crypto_mode, int version, unsigned char *key_final, unsigned char *iv_final, unsigned char *key, unsigned char *iv) -{ - int mode = (int) (crypto_mode & 0xF0000000); - switch (mode) { - case 0x10000000: - // Encrypted ERK. - // Decrypt the key with EDAT_KEY + EDAT_IV and copy the original IV. - aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, key, key_final, 0x10); - memcpy(iv_final, iv, 0x10); - break; - case 0x20000000: - // Default ERK. - // Use EDAT_KEY and EDAT_IV. - memcpy(key_final, version ? EDAT_KEY_1 : EDAT_KEY_0, 0x10); - memcpy(iv_final, EDAT_IV, 0x10); - break; - case 0x00000000: - // Unencrypted ERK. - // Use the original key and iv. - memcpy(key_final, key, 0x10); - memcpy(iv_final, iv, 0x10); - break; - }; -} - -void generate_hash(int hash_mode, int version, unsigned char *hash_final, unsigned char *hash) -{ - int mode = (int) (hash_mode & 0xF0000000); - switch (mode) { - case 0x10000000: - // Encrypted HASH. - // Decrypt the hash with EDAT_KEY + EDAT_IV. - aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, hash, hash_final, 0x10); - break; - case 0x20000000: - // Default HASH. - // Use EDAT_HASH. - memcpy(hash_final, version ? EDAT_HASH_1 : EDAT_HASH_0, 0x10); - break; - case 0x00000000: - // Unencrypted ERK. - // Use the original hash. - memcpy(hash_final, hash, 0x10); - break; - }; -} +void generate_key(int crypto_mode, int version, unsigned char *key_final, unsigned char *iv_final, unsigned char *key, unsigned char *iv) +{ + int mode = (int) (crypto_mode & 0xF0000000); + switch (mode) { + case 0x10000000: + // Encrypted ERK. + // Decrypt the key with EDAT_KEY + EDAT_IV and copy the original IV. + aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, key, key_final, 0x10); + memcpy(iv_final, iv, 0x10); + break; + case 0x20000000: + // Default ERK. + // Use EDAT_KEY and EDAT_IV. + memcpy(key_final, version ? EDAT_KEY_1 : EDAT_KEY_0, 0x10); + memcpy(iv_final, EDAT_IV, 0x10); + break; + case 0x00000000: + // Unencrypted ERK. + // Use the original key and iv. + memcpy(key_final, key, 0x10); + memcpy(iv_final, iv, 0x10); + break; + }; +} -bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsigned char *out, int lenght, unsigned char *key, unsigned char *iv, unsigned char *hash, unsigned char *test_hash) -{ - // Setup buffers for key, iv and hash. - unsigned char key_final[0x10] = {}; - unsigned char iv_final[0x10] = {}; - unsigned char hash_final_10[0x10] = {}; - unsigned char hash_final_14[0x14] = {}; - - // Generate crypto key and hash. - generate_key(crypto_mode, version, key_final, iv_final, key, iv); - if ((hash_mode & 0xFF) == 0x01) - generate_hash(hash_mode, version, hash_final_14, hash); - else - generate_hash(hash_mode, version, hash_final_10, hash); - - if ((crypto_mode & 0xFF) == 0x01) // No algorithm. - { - memcpy(out, in, lenght); - } - else if ((crypto_mode & 0xFF) == 0x02) // AES128-CBC - { - aescbc128_decrypt(key_final, iv_final, in, out, lenght); - } - else - { - ConLog.Error("EDAT: Unknown crypto algorithm!\n"); - return false; - } - - if ((hash_mode & 0xFF) == 0x01) // 0x14 SHA1-HMAC - { - return hmac_hash_compare(hash_final_14, 0x14, in, lenght, test_hash); - } - else if ((hash_mode & 0xFF) == 0x02) // 0x10 AES-CMAC - { - return cmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); - } - else if ((hash_mode & 0xFF) == 0x04) //0x10 SHA1-HMAC - { - return hmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); - } - else - { - ConLog.Error("EDAT: Unknown hashing algorithm!\n"); - return false; - } -} - -unsigned char* dec_section(unsigned char* metadata) -{ - unsigned char *dec = new unsigned char[0x10]; - dec[0x00] = (metadata[0xC] ^ metadata[0x8] ^ metadata[0x10]); - dec[0x01] = (metadata[0xD] ^ metadata[0x9] ^ metadata[0x11]); - dec[0x02] = (metadata[0xE] ^ metadata[0xA] ^ metadata[0x12]); - dec[0x03] = (metadata[0xF] ^ metadata[0xB] ^ metadata[0x13]); - dec[0x04] = (metadata[0x4] ^ metadata[0x8] ^ metadata[0x14]); - dec[0x05] = (metadata[0x5] ^ metadata[0x9] ^ metadata[0x15]); - dec[0x06] = (metadata[0x6] ^ metadata[0xA] ^ metadata[0x16]); - dec[0x07] = (metadata[0x7] ^ metadata[0xB] ^ metadata[0x17]); - dec[0x08] = (metadata[0xC] ^ metadata[0x0] ^ metadata[0x18]); - dec[0x09] = (metadata[0xD] ^ metadata[0x1] ^ metadata[0x19]); - dec[0x0A] = (metadata[0xE] ^ metadata[0x2] ^ metadata[0x1A]); - dec[0x0B] = (metadata[0xF] ^ metadata[0x3] ^ metadata[0x1B]); - dec[0x0C] = (metadata[0x4] ^ metadata[0x0] ^ metadata[0x1C]); - dec[0x0D] = (metadata[0x5] ^ metadata[0x1] ^ metadata[0x1D]); - dec[0x0E] = (metadata[0x6] ^ metadata[0x2] ^ metadata[0x1E]); - dec[0x0F] = (metadata[0x7] ^ metadata[0x3] ^ metadata[0x1F]); +void generate_hash(int hash_mode, int version, unsigned char *hash_final, unsigned char *hash) +{ + int mode = (int) (hash_mode & 0xF0000000); + switch (mode) { + case 0x10000000: + // Encrypted HASH. + // Decrypt the hash with EDAT_KEY + EDAT_IV. + aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, hash, hash_final, 0x10); + break; + case 0x20000000: + // Default HASH. + // Use EDAT_HASH. + memcpy(hash_final, version ? EDAT_HASH_1 : EDAT_HASH_0, 0x10); + break; + case 0x00000000: + // Unencrypted ERK. + // Use the original hash. + memcpy(hash_final, hash, 0x10); + break; + }; +} + +bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsigned char *out, int lenght, unsigned char *key, unsigned char *iv, unsigned char *hash, unsigned char *test_hash) +{ + // Setup buffers for key, iv and hash. + unsigned char key_final[0x10] = {}; + unsigned char iv_final[0x10] = {}; + unsigned char hash_final_10[0x10] = {}; + unsigned char hash_final_14[0x14] = {}; + + // Generate crypto key and hash. + generate_key(crypto_mode, version, key_final, iv_final, key, iv); + if ((hash_mode & 0xFF) == 0x01) + generate_hash(hash_mode, version, hash_final_14, hash); + else + generate_hash(hash_mode, version, hash_final_10, hash); + + if ((crypto_mode & 0xFF) == 0x01) // No algorithm. + { + memcpy(out, in, lenght); + } + else if ((crypto_mode & 0xFF) == 0x02) // AES128-CBC + { + aescbc128_decrypt(key_final, iv_final, in, out, lenght); + } + else + { + ConLog.Error("EDAT: Unknown crypto algorithm!\n"); + return false; + } + + if ((hash_mode & 0xFF) == 0x01) // 0x14 SHA1-HMAC + { + return hmac_hash_compare(hash_final_14, 0x14, in, lenght, test_hash); + } + else if ((hash_mode & 0xFF) == 0x02) // 0x10 AES-CMAC + { + return cmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); + } + else if ((hash_mode & 0xFF) == 0x04) //0x10 SHA1-HMAC + { + return hmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); + } + else + { + ConLog.Error("EDAT: Unknown hashing algorithm!\n"); + return false; + } +} + +unsigned char* dec_section(unsigned char* metadata) +{ + unsigned char *dec = new unsigned char[0x10]; + dec[0x00] = (metadata[0xC] ^ metadata[0x8] ^ metadata[0x10]); + dec[0x01] = (metadata[0xD] ^ metadata[0x9] ^ metadata[0x11]); + dec[0x02] = (metadata[0xE] ^ metadata[0xA] ^ metadata[0x12]); + dec[0x03] = (metadata[0xF] ^ metadata[0xB] ^ metadata[0x13]); + dec[0x04] = (metadata[0x4] ^ metadata[0x8] ^ metadata[0x14]); + dec[0x05] = (metadata[0x5] ^ metadata[0x9] ^ metadata[0x15]); + dec[0x06] = (metadata[0x6] ^ metadata[0xA] ^ metadata[0x16]); + dec[0x07] = (metadata[0x7] ^ metadata[0xB] ^ metadata[0x17]); + dec[0x08] = (metadata[0xC] ^ metadata[0x0] ^ metadata[0x18]); + dec[0x09] = (metadata[0xD] ^ metadata[0x1] ^ metadata[0x19]); + dec[0x0A] = (metadata[0xE] ^ metadata[0x2] ^ metadata[0x1A]); + dec[0x0B] = (metadata[0xF] ^ metadata[0x3] ^ metadata[0x1B]); + dec[0x0C] = (metadata[0x4] ^ metadata[0x0] ^ metadata[0x1C]); + dec[0x0D] = (metadata[0x5] ^ metadata[0x1] ^ metadata[0x1D]); + dec[0x0E] = (metadata[0x6] ^ metadata[0x2] ^ metadata[0x1E]); + dec[0x0F] = (metadata[0x7] ^ metadata[0x3] ^ metadata[0x1F]); return dec; } -unsigned char* get_block_key(int block, NPD_HEADER *npd) -{ - unsigned char empty_key[0x10] = {}; - unsigned char *src_key = (npd->version <= 1) ? empty_key : npd->dev_hash; - unsigned char *dest_key = new unsigned char[0x10]; - memcpy(dest_key, src_key, 0xC); - dest_key[0xC] = (block >> 24 & 0xFF); - dest_key[0xD] = (block >> 16 & 0xFF); - dest_key[0xE] = (block >> 8 & 0xFF); - dest_key[0xF] = (block & 0xFF); +unsigned char* get_block_key(int block, NPD_HEADER *npd) +{ + unsigned char empty_key[0x10] = {}; + unsigned char *src_key = (npd->version <= 1) ? empty_key : npd->dev_hash; + unsigned char *dest_key = new unsigned char[0x10]; + memcpy(dest_key, src_key, 0xC); + dest_key[0xC] = (block >> 24 & 0xFF); + dest_key[0xD] = (block >> 16 & 0xFF); + dest_key[0xE] = (block >> 8 & 0xFF); + dest_key[0xF] = (block & 0xFF); return dest_key; -} +} // EDAT/SDAT functions. int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, unsigned char* crypt_key, bool verbose) @@ -301,20 +301,17 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np return 0; } -int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFile *f, bool verbose) +static bool check_flags(EDAT_SDAT_HEADER *edat, NPD_HEADER *npd) { - f->Seek(0); - unsigned char *header = new unsigned char[0xA0]; - unsigned char *tmp = new unsigned char[0xA0]; - unsigned char *hash_result = new unsigned char[0x10]; + if (edat == nullptr || npd == nullptr) + return false; - // Check NPD version and EDAT flags. - if ((npd->version == 0) || (npd->version == 1)) + if (npd->version == 0 || npd->version == 1) { if (edat->flags & 0x7EFFFFFE) { ConLog.Error("EDAT: Bad header flags!\n"); - return 1; + return false; } } else if (npd->version == 2) @@ -322,93 +319,113 @@ int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFi if (edat->flags & 0x7EFFFFE0) { ConLog.Error("EDAT: Bad header flags!\n"); - return 1; + return false; } } - else if ((npd->version == 3) || (npd->version == 4)) + else if (npd->version == 3 || npd->version == 4) { if (edat->flags & 0x7EFFFFC0) { ConLog.Error("EDAT: Bad header flags!\n"); - return 1; + return false; } } - else + else if (npd->version > 4) { - ConLog.Error("EDAT: Unknown version!\n"); + ConLog.Error("EDAT: Unknown version - %d\n", npd->version); + return false; + } + + return true; +} + +int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFile *f, bool verbose) +{ + f->Seek(0); + unsigned char *header = new unsigned char[0xA0]; + unsigned char *tmp = new unsigned char[0xA0]; + unsigned char *hash_result = new unsigned char[0x10]; + + // Check NPD version and EDAT flags. + if (!check_flags(edat, npd)) + { + delete[] header; + delete[] tmp; + delete[] hash_result; + return 1; - } - - // Read in the file header. - f->Read(header, 0xA0); - f->Read(hash_result, 0x10); - - // Setup the hashing mode and the crypto mode used in the file. - int crypto_mode = 0x1; - int hash_mode = ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002; - if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0) - { - ConLog.Warning("EDAT: DEBUG data detected!\n"); - hash_mode |= 0x01000000; - } - - // Setup header key and iv buffers. - unsigned char header_key[0x10] = {}; - unsigned char header_iv[0x10] = {}; - - // Test the header hash (located at offset 0xA0). - if (!crypto(hash_mode, crypto_mode, (npd->version == 4), header, tmp, 0xA0, header_key, header_iv, key, hash_result)) - { - if (verbose) - ConLog.Warning("EDAT: Header hash is invalid!\n"); - } - - // Parse the metadata info. - int metadata_section_size = 0x10; - if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0)) - { - ConLog.Warning("EDAT: COMPRESSED data detected!\n"); - metadata_section_size = 0x20; - } - - int block_num = (int) ((edat->file_size + edat->block_size - 1) / edat->block_size); - int bytes_read = 0; - int metadata_offset = 0x100; - - long bytes_to_read = metadata_section_size * block_num; - while (bytes_to_read > 0) - { - // Locate the metadata blocks. - int block_size = (0x3C00 > bytes_to_read) ? (int) bytes_to_read : 0x3C00; // 0x3C00 is the maximum block size. - f->Seek(metadata_offset + bytes_read); - unsigned char *data = new unsigned char[block_size]; - - // Read in the metadata. - tmp = new unsigned char[block_size]; - f->Read(data, block_size); - - // Check the generated hash against the metadata hash located at offset 0x90 in the header. - memset(hash_result, 0, 0x10); - f->Seek(0x90); - f->Read(hash_result, 0x10); - - // Generate the hash for this block. - if (!crypto(hash_mode, crypto_mode, (npd->version == 4), data, tmp, block_size, header_key, header_iv, key, hash_result)) - { - if (verbose) - ConLog.Warning("EDAT: Metadata hash from block 0x%08x is invalid!\n", metadata_offset + bytes_read); - } - - // Adjust sizes. - bytes_read += block_size; - bytes_to_read -= block_size; - - delete[] data; + } + + // Read in the file header. + f->Read(header, 0xA0); + f->Read(hash_result, 0x10); + + // Setup the hashing mode and the crypto mode used in the file. + int crypto_mode = 0x1; + int hash_mode = ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002; + if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0) + { + ConLog.Warning("EDAT: DEBUG data detected!\n"); + hash_mode |= 0x01000000; + } + + // Setup header key and iv buffers. + unsigned char header_key[0x10] = {}; + unsigned char header_iv[0x10] = {}; + + // Test the header hash (located at offset 0xA0). + if (!crypto(hash_mode, crypto_mode, (npd->version == 4), header, tmp, 0xA0, header_key, header_iv, key, hash_result)) + { + if (verbose) + ConLog.Warning("EDAT: Header hash is invalid!\n"); + } + + // Parse the metadata info. + int metadata_section_size = 0x10; + if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0)) + { + ConLog.Warning("EDAT: COMPRESSED data detected!\n"); + metadata_section_size = 0x20; + } + + int block_num = (int) ((edat->file_size + edat->block_size - 1) / edat->block_size); + int bytes_read = 0; + int metadata_offset = 0x100; + + long bytes_to_read = metadata_section_size * block_num; + while (bytes_to_read > 0) + { + // Locate the metadata blocks. + int block_size = (0x3C00 > bytes_to_read) ? (int) bytes_to_read : 0x3C00; // 0x3C00 is the maximum block size. + f->Seek(metadata_offset + bytes_read); + unsigned char *data = new unsigned char[block_size]; + + // Read in the metadata. + tmp = new unsigned char[block_size]; + f->Read(data, block_size); + + // Check the generated hash against the metadata hash located at offset 0x90 in the header. + memset(hash_result, 0, 0x10); + f->Seek(0x90); + f->Read(hash_result, 0x10); + + // Generate the hash for this block. + if (!crypto(hash_mode, crypto_mode, (npd->version == 4), data, tmp, block_size, header_key, header_iv, key, hash_result)) + { + if (verbose) + ConLog.Warning("EDAT: Metadata hash from block 0x%08x is invalid!\n", metadata_offset + bytes_read); + } + + // Adjust sizes. + bytes_read += block_size; + bytes_to_read -= block_size; + + delete[] data; } // Cleanup. - delete[] header; - delete[] tmp; + delete[] header; + delete[] tmp; delete[] hash_result; return 0; @@ -501,6 +518,8 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un if(memcmp(NPD->magic, npd_magic, 4)) { ConLog.Error("EDAT: File has invalid NPD header."); + delete NPD; + delete EDAT; return 1; } @@ -556,6 +575,8 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un if (!test) { ConLog.Error("EDAT: A valid RAP file is needed!"); + delete NPD; + delete EDAT; return 1; } } @@ -670,4 +691,4 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi input.Close(); output.Close(); return 0; -} +} From c4b64c8d9f93c76844c4cd0f652406245e353f79 Mon Sep 17 00:00:00 2001 From: lioncash Date: Mon, 31 Mar 2014 08:59:52 -0400 Subject: [PATCH 2/3] Fix variable typos in unedat.cpp Also fixed possible uninitialized variable usage. Initializes length to zero. --- rpcs3/Crypto/unedat.cpp | 50 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/rpcs3/Crypto/unedat.cpp b/rpcs3/Crypto/unedat.cpp index dd632bbb9a..f7f44cf16f 100644 --- a/rpcs3/Crypto/unedat.cpp +++ b/rpcs3/Crypto/unedat.cpp @@ -48,7 +48,7 @@ void generate_hash(int hash_mode, int version, unsigned char *hash_final, unsign }; } -bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsigned char *out, int lenght, unsigned char *key, unsigned char *iv, unsigned char *hash, unsigned char *test_hash) +bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsigned char *out, int length, unsigned char *key, unsigned char *iv, unsigned char *hash, unsigned char *test_hash) { // Setup buffers for key, iv and hash. unsigned char key_final[0x10] = {}; @@ -65,11 +65,11 @@ bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsi if ((crypto_mode & 0xFF) == 0x01) // No algorithm. { - memcpy(out, in, lenght); + memcpy(out, in, length); } else if ((crypto_mode & 0xFF) == 0x02) // AES128-CBC { - aescbc128_decrypt(key_final, iv_final, in, out, lenght); + aescbc128_decrypt(key_final, iv_final, in, out, length); } else { @@ -79,15 +79,15 @@ bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsi if ((hash_mode & 0xFF) == 0x01) // 0x14 SHA1-HMAC { - return hmac_hash_compare(hash_final_14, 0x14, in, lenght, test_hash); + return hmac_hash_compare(hash_final_14, 0x14, in, length, test_hash); } else if ((hash_mode & 0xFF) == 0x02) // 0x10 AES-CMAC { - return cmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); + return cmac_hash_compare(hash_final_10, 0x10, in, length, test_hash); } else if ((hash_mode & 0xFF) == 0x04) //0x10 SHA1-HMAC { - return hmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); + return hmac_hash_compare(hash_final_10, 0x10, in, length, test_hash); } else { @@ -147,13 +147,12 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np unsigned char empty_iv[0x10] = {}; // Decrypt the metadata. - int i; - for (i = 0; i < block_num; i++) + for (int i = 0; i < block_num; i++) { in->Seek(metadata_offset + i * metadata_section_size); unsigned char hash_result[0x10]; long offset; - int lenght; + int length = 0; int compression_end = 0; if ((edat->flags & EDAT_COMPRESSED_FLAG) != 0) @@ -164,7 +163,7 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np // If the data is compressed, decrypt the metadata. unsigned char *result = dec_section(metadata); offset = ((swap32(*(int*)&result[0]) << 4) | (swap32(*(int*)&result[4]))); - lenght = swap32(*(int*)&result[8]); + length = swap32(*(int*)&result[8]); compression_end = swap32(*(int*)&result[12]); delete[] result; @@ -173,44 +172,43 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np else if ((edat->flags & EDAT_FLAG_0x20) != 0) { // If FLAG 0x20, the metadata precedes each data block. - in->Seek(metadata_offset + i * metadata_section_size + lenght); + in->Seek(metadata_offset + i * metadata_section_size + length); unsigned char metadata[0x20]; in->Read(metadata, 0x20); // If FLAG 0x20 is set, apply custom xor. - int j; - for (j = 0; j < 0x10; j++) { + for (int j = 0; j < 0x10; j++) { hash_result[j] = (unsigned char)(metadata[j] ^ metadata[j+0x10]); } offset = metadata_offset + i * edat->block_size + (i + 1) * metadata_section_size; - lenght = edat->block_size; + length = edat->block_size; if ((i == (block_num - 1)) && (edat->file_size % edat->block_size)) - lenght = (int) (edat->file_size % edat->block_size); + length = (int) (edat->file_size % edat->block_size); } else { in->Read(hash_result, 0x10); offset = metadata_offset + i * edat->block_size + block_num * metadata_section_size; - lenght = edat->block_size; + length = edat->block_size; if ((i == (block_num - 1)) && (edat->file_size % edat->block_size)) - lenght = (int) (edat->file_size % edat->block_size); + length = (int) (edat->file_size % edat->block_size); } // Locate the real data. - int pad_lenght = lenght; - lenght = (int) ((pad_lenght + 0xF) & 0xFFFFFFF0); + int pad_length = length; + length = (int) ((pad_length + 0xF) & 0xFFFFFFF0); in->Seek(offset); // Setup buffers for decryption and read the data. - enc_data = new unsigned char[lenght]; - dec_data = new unsigned char[lenght]; + enc_data = new unsigned char[length]; + dec_data = new unsigned char[length]; unsigned char key_result[0x10]; unsigned char hash[0x10]; - in->Read(enc_data, lenght); + in->Read(enc_data, length); // Generate a key for the current block. b_key = get_block_key(i, npd); @@ -245,14 +243,14 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np crypto_mode |= 0x01000000; hash_mode |= 0x01000000; // Simply copy the data without the header or the footer. - memcpy(dec_data, enc_data, lenght); + memcpy(dec_data, enc_data, length); } else { // IV is null if NPD version is 1 or 0. iv = (npd->version <= 1) ? empty_iv : npd->digest; // Call main crypto routine on this data block. - crypto(hash_mode, crypto_mode, (npd->version == 4), enc_data, dec_data, lenght, key_result, iv, hash, hash_result); + crypto(hash_mode, crypto_mode, (npd->version == 4), enc_data, dec_data, length, key_result, iv, hash, hash_result); } // Apply additional compression if needed and write the decrypted data. @@ -270,7 +268,7 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np if (verbose) { - ConLog.Write("EDAT: Compressed block size: %d\n", pad_lenght); + ConLog.Write("EDAT: Compressed block size: %d\n", pad_length); ConLog.Write("EDAT: Decompressed block size: %d\n", res); } @@ -291,7 +289,7 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np } else { - out->Write(dec_data, pad_lenght); + out->Write(dec_data, pad_length); } delete[] enc_data; From a09ad031ec9210156cab5dc74826d4cbd4c1db4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandro=20S=C3=A1nchez=20Bach?= Date: Mon, 31 Mar 2014 20:30:07 +0200 Subject: [PATCH 3/3] cellSaveData* (cellSysutil) improvements * cellSaveData improvements: cellSaveDataListLoad2 should work perfectly (ignoring the fact that there is no dialog, and the first entry is chosen automatically). cellSaveDataListSave2 has improved too. Some code refactoring is required though. * Reverted (deleted) Emu/SysCalls/Dialogs/ folder which I accidentally included while merging Nekotekina's branch (including minor SaveData changes). * Modified some small things in cellGcmSys. --- rpcs3/Emu/SysCalls/Dialogs/Dialog.cpp | 2 - rpcs3/Emu/SysCalls/Dialogs/Dialog.h | 8 - rpcs3/Emu/SysCalls/Dialogs/MessageDialog.cpp | 7 - rpcs3/Emu/SysCalls/Dialogs/MessageDialog.h | 15 -- rpcs3/Emu/SysCalls/Dialogs/SaveDataList.cpp | 37 ---- rpcs3/Emu/SysCalls/Dialogs/SaveDataList.h | 9 - rpcs3/Emu/SysCalls/Dialogs/UserList.cpp | 2 - rpcs3/Emu/SysCalls/Dialogs/UserList.h | 0 rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp | 110 ++++------- .../SysCalls/Modules/cellSysutil_SaveData.cpp | 184 +++++++++++++++--- .../SysCalls/Modules/cellSysutil_SaveData.h | 16 +- 11 files changed, 215 insertions(+), 175 deletions(-) delete mode 100644 rpcs3/Emu/SysCalls/Dialogs/Dialog.cpp delete mode 100644 rpcs3/Emu/SysCalls/Dialogs/Dialog.h delete mode 100644 rpcs3/Emu/SysCalls/Dialogs/MessageDialog.cpp delete mode 100644 rpcs3/Emu/SysCalls/Dialogs/MessageDialog.h delete mode 100644 rpcs3/Emu/SysCalls/Dialogs/SaveDataList.cpp delete mode 100644 rpcs3/Emu/SysCalls/Dialogs/SaveDataList.h delete mode 100644 rpcs3/Emu/SysCalls/Dialogs/UserList.cpp delete mode 100644 rpcs3/Emu/SysCalls/Dialogs/UserList.h diff --git a/rpcs3/Emu/SysCalls/Dialogs/Dialog.cpp b/rpcs3/Emu/SysCalls/Dialogs/Dialog.cpp deleted file mode 100644 index 80e37ceb0c..0000000000 --- a/rpcs3/Emu/SysCalls/Dialogs/Dialog.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "stdafx.h" -#include "Dialog.h" \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Dialogs/Dialog.h b/rpcs3/Emu/SysCalls/Dialogs/Dialog.h deleted file mode 100644 index 0a4e38e58e..0000000000 --- a/rpcs3/Emu/SysCalls/Dialogs/Dialog.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -class Dialog -{ -public: - void Show(); - void Close(); -}; diff --git a/rpcs3/Emu/SysCalls/Dialogs/MessageDialog.cpp b/rpcs3/Emu/SysCalls/Dialogs/MessageDialog.cpp deleted file mode 100644 index 2390ca5601..0000000000 --- a/rpcs3/Emu/SysCalls/Dialogs/MessageDialog.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "stdafx.h" -#include "MessageDialog.h" - -MessageDialog::MessageDialog(std::string message, std::string title, int flags, char* icon) -{ - // TODO: Use RSX post-drawing instead of wxWidgets -} \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Dialogs/MessageDialog.h b/rpcs3/Emu/SysCalls/Dialogs/MessageDialog.h deleted file mode 100644 index 9201122fa1..0000000000 --- a/rpcs3/Emu/SysCalls/Dialogs/MessageDialog.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "Dialog.h" - -enum MessageDialogFlags -{ - MessageDialog_Button_Enter = 0x1, - MessageDialog_Button_Back = 0x2, - - MessageDialog_Controls_YesNo = 0x4, -}; - -class MessageDialog : public Dialog -{ - MessageDialog(std::string message, std::string title, int flags, char* icon); -}; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Dialogs/SaveDataList.cpp b/rpcs3/Emu/SysCalls/Dialogs/SaveDataList.cpp deleted file mode 100644 index b8ffafdda7..0000000000 --- a/rpcs3/Emu/SysCalls/Dialogs/SaveDataList.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "stdafx.h" -#include "SaveDataList.h" - -void SaveDataList::Load(const std::vector& entries) -{ - wxDialog dialog(NULL, wxID_ANY, "test", wxDefaultPosition, wxSize(450, 680)); - - wxPanel *panel = new wxPanel(&dialog, -1); - wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); - wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL); - wxListCtrl* list = new wxListCtrl(&dialog, wxID_ANY, wxPoint(10,10), wxSize(400,600)); - - list->InsertColumn(0, "Icon"); - list->InsertColumn(1, "Information"); - wxImageList* pImageList = new wxImageList(320,176); - - for (int i=0; iInsertItem (i, i); - list->SetItemColumnImage (i, 0, i); - list->SetItem (i, 1, wxString::Format("%d",i+1)); - - wxImage img(320, 176, entries[i].iconBuffer); - pImageList->Add(img); - } - list->SetImageList(pImageList, wxIMAGE_LIST_SMALL); - - panel->AddChild(list); - - vbox->Add(panel, 1); - vbox->Add(hbox, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, 10); - - dialog.SetSizer(vbox); - dialog.Centre(); - dialog.ShowModal(); - dialog.Destroy(); -} diff --git a/rpcs3/Emu/SysCalls/Dialogs/SaveDataList.h b/rpcs3/Emu/SysCalls/Dialogs/SaveDataList.h deleted file mode 100644 index 0a9e5db1ef..0000000000 --- a/rpcs3/Emu/SysCalls/Dialogs/SaveDataList.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "Dialog.h" -#include "Emu/SysCalls/Modules/cellSysutil_SaveData.h" - -class SaveDataList : public Dialog -{ -public: - void Load(const std::vector& entries); -}; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Dialogs/UserList.cpp b/rpcs3/Emu/SysCalls/Dialogs/UserList.cpp deleted file mode 100644 index 4f2fcb076d..0000000000 --- a/rpcs3/Emu/SysCalls/Dialogs/UserList.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "stdafx.h" -#include "UserList.h" diff --git a/rpcs3/Emu/SysCalls/Dialogs/UserList.h b/rpcs3/Emu/SysCalls/Dialogs/UserList.h deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp index 16db0c32d7..ea68e5b871 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp @@ -4,9 +4,9 @@ #include "Emu/GS/GCM.h" void cellGcmSys_init(); -void cellGcmSys_Load(); -void cellGcmSys_Unload(); -Module cellGcmSys(0x0010, cellGcmSys_init, cellGcmSys_Load, cellGcmSys_Unload); +void cellGcmSys_load(); +void cellGcmSys_unload(); +Module cellGcmSys(0x0010, cellGcmSys_init, cellGcmSys_load, cellGcmSys_unload); u32 local_size = 0; u32 local_addr = NULL; @@ -24,9 +24,9 @@ enum // Function declaration int cellGcmSetPrepareFlip(mem_ptr_t ctxt, u32 id); -/*------------------------------------------------------------ - Memory Mapping -------------------------------------------------------------*/ +//---------------------------------------------------------------------------- +// Memory Mapping +//---------------------------------------------------------------------------- struct gcm_offset { @@ -853,88 +853,64 @@ int cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co void cellGcmSys_init() { - //------------------------------------------------------------------------ - // Generating Render Commands - //------------------------------------------------------------------------ - - // TODO - - //------------------------------------------------------------------------ // Data Retrieval - //------------------------------------------------------------------------ - // cellGcmGetCurrentField + //cellGcmSys.AddFunc(0xc8f3bd09, cellGcmGetCurrentField); cellGcmSys.AddFunc(0xf80196c1, cellGcmGetLabelAddress); - // cellGcmGetNotifyDataAddress - // cellGcmGetReport - // cellGcmGetReportDataAddress + //cellGcmSys.AddFunc(0x21cee035, cellGcmGetNotifyDataAddress); + //cellGcmSys.AddFunc(0x99d397ac, cellGcmGetReport); + //cellGcmSys.AddFunc(0x9a0159af, cellGcmGetReportDataAddress); cellGcmSys.AddFunc(0x8572bce2, cellGcmGetReportDataAddressLocation); - // cellGcmGetReportDataLocation + //cellGcmSys.AddFunc(0xa6b180ac, cellGcmGetReportDataLocation); cellGcmSys.AddFunc(0x5a41c10f, cellGcmGetTimeStamp); - // cellGcmGetTimeStampLocation + //cellGcmSys.AddFunc(0x2ad4951b, cellGcmGetTimeStampLocation); - //------------------------------------------------------------------------ - // Data Transfer and Format Conversion - //------------------------------------------------------------------------ - - // TODO - - //------------------------------------------------------------------------ // Command Buffer Control - //------------------------------------------------------------------------ - // cellGcmCallbackForSnc - // cellGcmFinish - // cellGcmFlush + //cellGcmSys.AddFunc(, cellGcmCallbackForSnc); + //cellGcmSys.AddFunc(, cellGcmFinish); + //cellGcmSys.AddFunc(, cellGcmFlush); cellGcmSys.AddFunc(0xa547adde, cellGcmGetControlRegister); cellGcmSys.AddFunc(0x5e2ee0f0, cellGcmGetDefaultCommandWordSize); cellGcmSys.AddFunc(0x8cdf8c70, cellGcmGetDefaultSegmentWordSize); cellGcmSys.AddFunc(0xcaabd992, cellGcmInitDefaultFifoMode); - // cellGcmReserveMethodSize - // cellGcmResetDefaultCommandBuffer - // cellGcmSetCallCommand + //cellGcmSys.AddFunc(, cellGcmReserveMethodSize); + //cellGcmSys.AddFunc(, cellGcmResetDefaultCommandBuffer); cellGcmSys.AddFunc(0x9ba451e4, cellGcmSetDefaultFifoSize); - // cellGcmSetJumpCommand - // cellGcmSetNopCommand - // cellGcmSetReturnCommand - // cellGcmSetSkipNop - // cellGcmSetupContextData - // cellGcmSetUserCommand + //cellGcmSys.AddFunc(, cellGcmSetupContextData); - //------------------------------------------------------------------------ // Hardware Resource Management - //------------------------------------------------------------------------ cellGcmSys.AddFunc(0x4524cccd, cellGcmBindTile); cellGcmSys.AddFunc(0x9dc04436, cellGcmBindZcull); - // cellGcmDumpGraphicsError + //cellGcmSys.AddFunc(0x1f61b3ff, cellGcmDumpGraphicsError); cellGcmSys.AddFunc(0xe315a0b2, cellGcmGetConfiguration); - // cellGcmGetDisplayBufferByFlipIndex + //cellGcmSys.AddFunc(0x371674cf, cellGcmGetDisplayBufferByFlipIndex); cellGcmSys.AddFunc(0x72a577ce, cellGcmGetFlipStatus); - // cellGcmgetLastFlipTime - // cellGcmGetLastSecondVTime + //cellGcmSys.AddFunc(0x63387071, cellGcmgetLastFlipTime); + //cellGcmSys.AddFunc(0x23ae55a3, cellGcmGetLastSecondVTime); cellGcmSys.AddFunc(0x055bd74d, cellGcmGetTiledPitchSize); - // cellGcmGetVBlankCount + //cellGcmSys.AddFunc(0x723bbc7e, cellGcmGetVBlankCount); cellGcmSys.AddFunc(0x15bae46b, cellGcmInit); - // cellGcmInitSystemMode + //cellGcmSys.AddFunc(0xfce9e764, cellGcmInitSystemMode); cellGcmSys.AddFunc(0xb2e761d4, cellGcmResetFlipStatus); cellGcmSys.AddFunc(0x51c9d62b, cellGcmSetDebugOutputLevel); cellGcmSys.AddFunc(0xa53d12ae, cellGcmSetDisplayBuffer); cellGcmSys.AddFunc(0xdc09357e, cellGcmSetFlip); cellGcmSys.AddFunc(0xa41ef7e8, cellGcmSetFlipHandler); - // cellGcmSetFlipImmediate + //cellGcmSys.AddFunc(0xacee8542, cellGcmSetFlipImmediate); cellGcmSys.AddFunc(0x4ae8d215, cellGcmSetFlipMode); cellGcmSys.AddFunc(0xa47c09ff, cellGcmSetFlipStatus); - // cellGcmSetFlipWithWaitLabel - // cellGcmSetGraphicsHandler + //cellGcmSys.AddFunc(, cellGcmSetFlipWithWaitLabel); + //cellGcmSys.AddFunc(0xd01b570d, cellGcmSetGraphicsHandler); cellGcmSys.AddFunc(0x0b4b62d5, cellGcmSetPrepareFlip); - //cellGcmSetQueueHandler + //cellGcmSys.AddFunc(0x0a862772, cellGcmSetQueueHandler); cellGcmSys.AddFunc(0x4d7ce993, cellGcmSetSecondVFrequency); - // cellGcmSetSecondVHandler + //cellGcmSys.AddFunc(0xdc494430, cellGcmSetSecondVHandler); cellGcmSys.AddFunc(0xbd100dbc, cellGcmSetTileInfo); cellGcmSys.AddFunc(0x06edea9e, cellGcmSetUserHandler); - // cellGcmSetVBlankFrequency + //cellGcmSys.AddFunc(0xffe0160e, cellGcmSetVBlankFrequency); cellGcmSys.AddFunc(0xa91b0402, cellGcmSetVBlankHandler); cellGcmSys.AddFunc(0x983fb9aa, cellGcmSetWaitFlip); cellGcmSys.AddFunc(0xd34a420d, cellGcmSetZcull); - // cellGcmSortRemapEaIoAddress + //cellGcmSys.AddFunc(0x25b40ab4, cellGcmSortRemapEaIoAddress); cellGcmSys.AddFunc(0xd9b7653e, cellGcmUnbindTile); cellGcmSys.AddFunc(0xa75640e8, cellGcmUnbindZcull); cellGcmSys.AddFunc(0x657571f7, cellGcmGetTileInfo); @@ -942,9 +918,7 @@ void cellGcmSys_init() cellGcmSys.AddFunc(0x0e6b0dae, cellGcmGetDisplayInfo); cellGcmSys.AddFunc(0x93806525, cellGcmGetCurrentDisplayBufferId); - //------------------------------------------------------------------------ - //Memory Mapping - //------------------------------------------------------------------------ + // Memory Mapping cellGcmSys.AddFunc(0x21ac3697, cellGcmAddressToOffset); cellGcmSys.AddFunc(0xfb81c03e, cellGcmGetMaxIoMapSize); cellGcmSys.AddFunc(0x2922aed0, cellGcmGetOffsetTable); @@ -958,9 +932,7 @@ void cellGcmSys_init() cellGcmSys.AddFunc(0xdb23e867, cellGcmUnmapIoAddress); cellGcmSys.AddFunc(0x3b9bd5bd, cellGcmUnreserveIoMapSize); - //------------------------------------------------------------------------ // Cursor - //------------------------------------------------------------------------ cellGcmSys.AddFunc(0x107bf3a1, cellGcmInitCursor); cellGcmSys.AddFunc(0xc47d0812, cellGcmSetCursorEnable); cellGcmSys.AddFunc(0x69c6cc82, cellGcmSetCursorDisable); @@ -968,25 +940,21 @@ void cellGcmSys_init() cellGcmSys.AddFunc(0x1a0de550, cellGcmSetCursorPosition); cellGcmSys.AddFunc(0xbd2fa0a7, cellGcmUpdateCursor); - //------------------------------------------------------------------------ // Functions for Maintaining Compatibility - //------------------------------------------------------------------------ - // cellGcmGetCurrentBuffer - // cellGcmSetCurrentBuffer + //cellGcmSys.AddFunc(, cellGcmGetCurrentBuffer); + //cellGcmSys.AddFunc(, cellGcmSetCurrentBuffer); cellGcmSys.AddFunc(0xbc982946, cellGcmSetDefaultCommandBuffer); - // cellGcmSetDefaultCommandBufferAndSegmentWordSize - // cellGcmSetUserCallback + //cellGcmSys.AddFunc(, cellGcmSetDefaultCommandBufferAndSegmentWordSize); + //cellGcmSys.AddFunc(, cellGcmSetUserCallback); - //------------------------------------------------------------------------ // Other - //------------------------------------------------------------------------ cellGcmSys.AddFunc(0x21397818, cellGcmSetFlipCommand); cellGcmSys.AddFunc(0x3a33c1fd, cellGcmFunc15); cellGcmSys.AddFunc(0xd8f88e1a, cellGcmSetFlipCommandWithWaitLabel); cellGcmSys.AddFunc(0xd0b1d189, cellGcmSetTile); } -void cellGcmSys_Load() +void cellGcmSys_load() { current_config.ioAddress = NULL; current_config.localAddress = NULL; @@ -994,6 +962,6 @@ void cellGcmSys_Load() local_addr = NULL; } -void cellGcmSys_Unload() +void cellGcmSys_unload() { -} \ No newline at end of file +} diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil_SaveData.cpp b/rpcs3/Emu/SysCalls/Modules/cellSysutil_SaveData.cpp index 8f4ab520cd..6fe5e52b86 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil_SaveData.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSysutil_SaveData.cpp @@ -7,8 +7,6 @@ #include "Loader/PSF.h" #include "stblib/stb_image.h" -//#include "Emu/SysCalls/Dialogs/SaveDataList.h" - extern Module cellSysutil; // Auxiliary Classes @@ -75,7 +73,7 @@ void addSaveDataEntry(std::vector& saveEntries, const std::st saveEntry.title = psf.GetString("TITLE"); saveEntry.subtitle = psf.GetString("SUB_TITLE"); saveEntry.details = psf.GetString("DETAIL"); - saveEntry.sizeKb = getSaveDataSize(saveDir)/1024; + saveEntry.sizeKB = getSaveDataSize(saveDir)/1024; saveEntry.st_atime_ = 0; // TODO saveEntry.st_mtime_ = 0; // TODO saveEntry.st_ctime_ = 0; // TODO @@ -102,6 +100,7 @@ void addNewSaveDataEntry(std::vector& saveEntries, mem_ptr_t< u32 focusSaveDataEntry(const std::vector& saveEntries, u32 focusPosition) { + // TODO: Get the correct index. Right now, this returns the first element of the list. return 0; } @@ -126,14 +125,97 @@ void setSaveDataEntries(std::vector& saveEntries, mem_ptr_t statGet) +{ + if (entry.isNew) + statGet->isNewData = CELL_SAVEDATA_ISNEWDATA_YES; + else + statGet->isNewData = CELL_SAVEDATA_ISNEWDATA_NO; + + statGet->bind = 0; // TODO ? + statGet->sizeKB = entry.sizeKB; + statGet->hddFreeSizeKB = 40000000; // 40 GB. TODO ? + statGet->sysSizeKB = 0; // TODO: This is the size of PARAM.SFO + PARAM.PDF + statGet->dir.st_atime_ = 0; // TODO ? + statGet->dir.st_mtime_ = 0; // TODO ? + statGet->dir.st_ctime_ = 0; // TODO ? + memcpy(statGet->dir.dirName, entry.dirName.c_str(), CELL_SAVEDATA_DIRNAME_SIZE); + + statGet->getParam.attribute = 0; // TODO ? + memcpy(statGet->getParam.title, entry.title.c_str(), CELL_SAVEDATA_SYSP_TITLE_SIZE); + memcpy(statGet->getParam.subTitle, entry.subtitle.c_str(), CELL_SAVEDATA_SYSP_SUBTITLE_SIZE); + memcpy(statGet->getParam.detail, entry.details.c_str(), CELL_SAVEDATA_SYSP_DETAIL_SIZE); + memcpy(statGet->getParam.listParam, entry.listParam.c_str(), CELL_SAVEDATA_SYSP_LPARAM_SIZE); + + statGet->fileNum = 0; + statGet->fileList.SetAddr(0); + statGet->fileListNum = 0; + std::string saveDir = "/dev_hdd0/home/00000001/savedata/" + entry.dirName; // TODO: Get the path of the current user + vfsDir dir(saveDir); + if (!dir.IsOpened()) + return; + + std::vector fileEntries; + for(const DirEntryInfo* dirEntry = dir.Read(); dirEntry; dirEntry = dir.Read()) { + if (dirEntry->flags & DirEntry_TypeFile) { + if (dirEntry->name == "PARAM.SFO" || dirEntry->name == "PARAM.PFD") + continue; + + statGet->fileNum++; + statGet->fileListNum++; + CellSaveDataFileStat fileEntry; + vfsFile file(saveDir + "/" + dirEntry->name); + + if (dirEntry->name == "ICON0.PNG") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0; + if (dirEntry->name == "ICON1.PAM") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1; + if (dirEntry->name == "PIC1.PNG") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1; + if (dirEntry->name == "SND0.AT3") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0; + fileEntry.st_size = file.GetSize(); + fileEntry.st_atime_ = 0; // TODO ? + fileEntry.st_mtime_ = 0; // TODO ? + fileEntry.st_ctime_ = 0; // TODO ? + memcpy(fileEntry.fileName, (const char*)dirEntry->name.mb_str(), CELL_SAVEDATA_FILENAME_SIZE); + + fileEntries.push_back(fileEntry); + } + } + + statGet->fileList.SetAddr(Memory.Alloc(sizeof(CellSaveDataFileStat) * fileEntries.size(), sizeof(CellSaveDataFileStat))); + for (u32 i=0; ifileList[i], &fileEntries[i], sizeof(CellSaveDataFileStat)); +} + +s32 readSaveDataFile(mem_ptr_t fileSet, const std::string& saveDir) +{ + void* dest = NULL; + std::string filepath = saveDir + '/' + (char*)Memory.VirtualToRealAddr(fileSet->fileName_addr); + vfsFile file(filepath); + + switch (fileSet->fileType) + { + case CELL_SAVEDATA_FILETYPE_SECUREFILE: + case CELL_SAVEDATA_FILETYPE_NORMALFILE: + case CELL_SAVEDATA_FILETYPE_CONTENT_ICON0: + case CELL_SAVEDATA_FILETYPE_CONTENT_ICON1: + case CELL_SAVEDATA_FILETYPE_CONTENT_PIC1: + case CELL_SAVEDATA_FILETYPE_CONTENT_SND0: + dest = Memory.VirtualToRealAddr(fileSet->fileBuf_addr); + return file.Read(dest, min(fileSet->fileSize, fileSet->fileBufSize)); // TODO: This may fail for big files because of the dest pointer. + + default: + ConLog.Error("readSaveDataFile: Unknown type! Aborting..."); + return -1; + } +} + // Functions int cellSaveDataListSave2(u32 version, mem_ptr_t setList, mem_ptr_t setBuf, mem_func_ptr_t funcList, mem_func_ptr_t funcStat, mem_func_ptr_t funcFile, - u32 container, u32 userdata) + u32 container, u32 userdata_addr) { cellSysutil.Warning("cellSaveDataListSave2(version=%d, setList_addr=0x%x, setBuf=0x%x, funcList=0x%x, funcStat=0x%x, funcFile=0x%x, container=%d, userdata_addr=0x%x)", - version, setList.GetAddr(), setBuf.GetAddr(), funcList.GetAddr(), funcStat.GetAddr(), funcFile.GetAddr(), container, userdata); + version, setList.GetAddr(), setBuf.GetAddr(), funcList.GetAddr(), funcStat.GetAddr(), funcFile.GetAddr(), container, userdata_addr); if (!setList.IsGood() || !setBuf.IsGood() || !funcList.IsGood() || !funcStat.IsGood() || !funcFile.IsGood()) return CELL_SAVEDATA_ERROR_PARAM; @@ -174,15 +256,41 @@ int cellSaveDataListSave2(u32 version, mem_ptr_t setList, m } funcList(result.GetAddr(), listGet.GetAddr(), listSet.GetAddr()); + if (result->result < 0) { + ConLog.Error("cellSaveDataListSave2: CellSaveDataListCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. + return CELL_SAVEDATA_ERROR_CBRESULT; + } + if (!listSet->fixedList.IsGood()) + return CELL_SAVEDATA_ERROR_PARAM; + + setSaveDataEntries(saveEntries, (u32)listSet->fixedList.GetAddr(), listSet->fixedListNum); + if (listSet->newData.IsGood()) + addNewSaveDataEntry(saveEntries, (u32)listSet->newData.GetAddr()); + if (saveEntries.size() == 0) { + ConLog.Warning("cellSaveDataListSave2: No save entries found!"); // TODO: Find a better way to handle this error + return CELL_SAVEDATA_RET_OK; + } MemoryAllocator statGet; MemoryAllocator statSet; + u32 focusIndex = focusSaveDataEntry(saveEntries, listSet->focusPosition); + // TODO: Display the dialog here + u32 selectedIndex = focusIndex; // TODO: Until the dialog is implemented, select always the focused entry + getSaveDataStat(saveEntries[selectedIndex], statGet.GetAddr()); + result->userdata_addr = userdata_addr; + funcStat(result.GetAddr(), statGet.GetAddr(), statSet.GetAddr()); + Memory.Free(statGet->fileList.GetAddr()); + if (result->result < 0) { + ConLog.Error("cellSaveDataListLoad2: CellSaveDataStatCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. + return CELL_SAVEDATA_ERROR_CBRESULT; + } MemoryAllocator fileGet; MemoryAllocator fileSet; funcFile(result.GetAddr(), fileGet.GetAddr(), fileSet.GetAddr()); + // TODO: There are other returns in this function that doesn't free the memory. Fix it (without using goto's, please). for (auto& entry : saveEntries) { delete[] entry.iconBuf; entry.iconBuf = nullptr; @@ -193,10 +301,10 @@ int cellSaveDataListSave2(u32 version, mem_ptr_t setList, m int cellSaveDataListLoad2(u32 version, mem_ptr_t setList, mem_ptr_t setBuf, mem_func_ptr_t funcList, mem_func_ptr_t funcStat, mem_func_ptr_t funcFile, - u32 container, u32 userdata) + u32 container, u32 userdata_addr) { cellSysutil.Warning("cellSaveDataListLoad2(version=%d, setList_addr=0x%x, setBuf=0x%x, funcList=0x%x, funcStat=0x%x, funcFile=0x%x, container=%d, userdata_addr=0x%x)", - version, setList.GetAddr(), setBuf.GetAddr(), funcList.GetAddr(), funcStat.GetAddr(), funcFile.GetAddr(), container, userdata); + version, setList.GetAddr(), setBuf.GetAddr(), funcList.GetAddr(), funcStat.GetAddr(), funcFile.GetAddr(), container, userdata_addr); if (!setList.IsGood() || !setBuf.IsGood() || !funcList.IsGood() || !funcStat.IsGood() || !funcFile.IsGood()) return CELL_SAVEDATA_ERROR_PARAM; @@ -204,6 +312,10 @@ int cellSaveDataListLoad2(u32 version, mem_ptr_t setList, m MemoryAllocator result; MemoryAllocator listGet; MemoryAllocator listSet; + MemoryAllocator statGet; + MemoryAllocator statSet; + MemoryAllocator fileGet; + MemoryAllocator fileSet; std::string saveBaseDir = "/dev_hdd0/home/00000001/savedata/"; // TODO: Get the path of the current user vfsDir dir(saveBaseDir); @@ -237,34 +349,60 @@ int cellSaveDataListLoad2(u32 version, mem_ptr_t setList, m } funcList(result.GetAddr(), listGet.GetAddr(), listSet.GetAddr()); - if (result->result < 0) { ConLog.Error("cellSaveDataListLoad2: CellSaveDataListCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. return CELL_SAVEDATA_ERROR_CBRESULT; } - if (!listSet->fixedList.IsGood()) { + if (!listSet->fixedList.IsGood()) return CELL_SAVEDATA_ERROR_PARAM; - } + setSaveDataEntries(saveEntries, (u32)listSet->fixedList.GetAddr(), listSet->fixedListNum); + if (listSet->newData.IsGood()) + addNewSaveDataEntry(saveEntries, (u32)listSet->newData.GetAddr()); + if (saveEntries.size() == 0) { + ConLog.Warning("cellSaveDataListLoad2: No save entries found!"); // TODO: Find a better way to handle this error + return CELL_SAVEDATA_RET_OK; + } + u32 focusIndex = focusSaveDataEntry(saveEntries, listSet->focusPosition); - - MemoryAllocator statGet; - MemoryAllocator statSet; - // TODO: Display the dialog here - ConLog.Warning("cellSaveDataListLoad2:"); + u32 selectedIndex = focusIndex; // TODO: Until the dialog is implemented, select always the focused entry + getSaveDataStat(saveEntries[selectedIndex], statGet.GetAddr()); + result->userdata_addr = userdata_addr; - statGet->isNewData = CELL_SAVEDATA_ISNEWDATA_NO; // You can *never* load new data - //statGet->dir = - - - funcStat(result.GetAddr(), statGet.GetAddr(), statSet.GetAddr()); + Memory.Free(statGet->fileList.GetAddr()); + if (result->result < 0) { + ConLog.Error("cellSaveDataListLoad2: CellSaveDataStatCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. + return CELL_SAVEDATA_ERROR_CBRESULT; + } + if (statSet->setParam.IsGood()) + addNewSaveDataEntry(saveEntries, (u32)listSet->newData.GetAddr()); - MemoryAllocator fileGet; - MemoryAllocator fileSet; - funcFile(result.GetAddr(), fileGet.GetAddr(), fileSet.GetAddr()); + fileGet->excSize = 0; + while(true) + { + funcFile(result.GetAddr(), fileGet.GetAddr(), fileSet.GetAddr()); + if (result->result < 0) { + ConLog.Error("cellSaveDataListLoad2: CellSaveDataStatCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. + return CELL_SAVEDATA_ERROR_CBRESULT; + } + if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) + break; + switch (fileSet->fileOperation) + { + case CELL_SAVEDATA_FILEOP_READ: + fileGet->excSize = readSaveDataFile(fileSet.GetAddr(), saveBaseDir + (char*)statGet->dir.dirName); + break; + case CELL_SAVEDATA_FILEOP_WRITE: + case CELL_SAVEDATA_FILEOP_DELETE: + case CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC: + ConLog.Warning("cellSaveDataListLoad2: TODO: fileSet->fileOperation not yet implemented"); + break; + } + } + // TODO: There are other returns in this function that doesn't free the memory. Fix it (without using goto's, please). for (auto& entry : saveEntries) { delete[] entry.iconBuf; entry.iconBuf = nullptr; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil_SaveData.h b/rpcs3/Emu/SysCalls/Modules/cellSysutil_SaveData.h index 0ebcc172f9..8a7d127f97 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil_SaveData.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSysutil_SaveData.h @@ -71,6 +71,20 @@ enum CELL_SAVEDATA_FOCUSPOS_LATEST = 3, CELL_SAVEDATA_FOCUSPOS_OLDEST = 4, CELL_SAVEDATA_FOCUSPOS_NEWDATA = 5, + + // CellSaveDataFileOperation + CELL_SAVEDATA_FILEOP_READ = 0, + CELL_SAVEDATA_FILEOP_WRITE = 1, + CELL_SAVEDATA_FILEOP_DELETE = 2, + CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC = 3, + + // CellSaveDataFileType + CELL_SAVEDATA_FILETYPE_SECUREFILE = 0, + CELL_SAVEDATA_FILETYPE_NORMALFILE = 1, + CELL_SAVEDATA_FILETYPE_CONTENT_ICON0 = 2, + CELL_SAVEDATA_FILETYPE_CONTENT_ICON1 = 3, + CELL_SAVEDATA_FILETYPE_CONTENT_PIC1 = 4, + CELL_SAVEDATA_FILETYPE_CONTENT_SND0 = 5, }; @@ -248,7 +262,7 @@ struct SaveDataListEntry std::string title; std::string subtitle; std::string details; - u32 sizeKb; + u32 sizeKB; s64 st_atime_; s64 st_mtime_; s64 st_ctime_;