diff --git a/.gitignore b/.gitignore index a07ef6a..f3ac88e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,16 @@ */obj/* */bin/* +Thumbs.Db + CHOVY-GEN/Debug/* CHOVY-GEN/Release/* +LiLib/bin/* +LiLib/obj/* + +Vita/bin/* +Vita/lib/* + CHOVY-TRANSFER/obj/* CHOVY-TRANSFER/bin/* \ No newline at end of file diff --git a/CHOVY-GEN/CHOVY-GEN.vcxproj b/CHOVY-GEN/CHOVY-GEN.vcxproj deleted file mode 100644 index 6da94f8..0000000 --- a/CHOVY-GEN/CHOVY-GEN.vcxproj +++ /dev/null @@ -1,163 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - - - - - - - 15.0 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB} - Win32Proj - CHOVYGEN - 10.0 - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration) - CHOVY - - - true - - - false - - CHOVY - $(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration) - - - false - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions) - C:\openssl\include;%(AdditionalIncludeDirectories) - MultiThreaded - - - Windows - C:\openssl\lib;%(AdditionalLibraryDirectories) - ws2_32.lib;libsslMT.lib;Crypt32.lib;libcryptoMT.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - _DEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions) - - - Windows - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions) - MultiThreaded - C:\openssl\include;%(AdditionalIncludeDirectories) - - - Windows - true - true - C:\openssl\lib;%(AdditionalLibraryDirectories) - ws2_32.lib;libsslMT.lib;Crypt32.lib;libcryptoMT.lib;%(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - NDEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - - - - - - \ No newline at end of file diff --git a/CHOVY-GEN/CHOVY-GEN.vcxproj.filters b/CHOVY-GEN/CHOVY-GEN.vcxproj.filters deleted file mode 100644 index dc521e5..0000000 --- a/CHOVY-GEN/CHOVY-GEN.vcxproj.filters +++ /dev/null @@ -1,27 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - - - Source Files - - - \ No newline at end of file diff --git a/CHOVY-GEN/CHOVY-GEN.vcxproj.user b/CHOVY-GEN/CHOVY-GEN.vcxproj.user deleted file mode 100644 index d9462ff..0000000 --- a/CHOVY-GEN/CHOVY-GEN.vcxproj.user +++ /dev/null @@ -1,13 +0,0 @@ - - - - $(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration)\CHOVY-TRANSFER.EXE - WindowsLocalDebugger - Mixed - - - $(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration)\CHOVY-TRANSFER.EXE - WindowsLocalDebugger - Mixed - - \ No newline at end of file diff --git a/CHOVY-GEN/chovy-gen.c b/CHOVY-GEN/chovy-gen.c deleted file mode 100644 index a7f6ac2..0000000 --- a/CHOVY-GEN/chovy-gen.c +++ /dev/null @@ -1,289 +0,0 @@ -//Project Chovy - __sce_ebootpbp generator by @dots_tb and motoharu -// With CBPS help especially: @SiliCart, @nyaaasen, @notzecoxao (and his friends?) - -//Check out motoharu's project: https://github.com/motoharu-gosuto/psvcmd56/blob/master/src/CMD56Reversed/F00D/GcAuthMgrService.cpp#L1102 -#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) ) - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "key_vault.h" -PACK(typedef struct -{ - uint8_t r[0x1c]; - uint8_t s[0x1c]; -} ECDSA_SIG_0x1c); - -PACK(typedef struct sce_ebootpbp { - uint64_t magic; - uint32_t key_type;// set to 1 (maybe keytype?) - uint32_t type;// 03 - ps1, 02 - psp - uint8_t np_title[0x30]; - uint64_t aid; - uint64_t secure_tick; - uint64_t filesz; - uint64_t sw_ver; - uint8_t padding[0xf8]; - ECDSA_SIG_0x1c ebootpbp_hdr_sig; - ECDSA_SIG_0x1c NPUMDIMG_sig; - ECDSA_SIG_0x1c sceebootpbp_sig; -} sce_ebootpbp); - - -typedef struct pbp_hdr { - uint32_t magic; - uint32_t unk; - uint32_t sfo_offset; - uint32_t icon0_offset; - uint32_t icon1_offset; - uint32_t pic0_offset; - uint32_t pic1_offset; - uint32_t snd0_offset; - uint32_t data_psp_offset; - uint32_t data_psar_offset; -} pbp_hdr; - - -#define PSAR_SZ 0x1C0000 -#define WORK_BUF_SZ 0x7c0 - - -//based motoharu -__declspec(dllexport) int can_be_reversed_80C17A(const uint8_t* src, int some_size, uint8_t* iv, uint8_t* src_xored_digest) -{ - unsigned char src_xored[0x20]; - memcpy(src_xored, iv, 0x20); - - if (some_size > 0x20) - return 0x12; - - for(int i = 0; i < some_size; i++) - src_xored[i] = src[i] ^ iv[i]; - - int r0; - - SHA256_CTX sha256_ctx; - SHA256_Init(&sha256_ctx); - SHA256_Update(&sha256_ctx, src_xored, 0x20); - r0 = SHA256_Final(src_xored_digest, &sha256_ctx); - if(r0 != 1) - return 0x11; - - for(int i = 0; i < 0x20; i++) - iv[i] = src_xored_digest[i] ^ iv[i]; - - for(int i = 0; i < 0x20; i++) - { - if(iv[i] != 0xFF) - { - iv[i] = iv[i] + 1; - break; - } - - iv[i] = 0; - } - - return 0; -} - - -__declspec(dllexport) int f00d_KIRK0x22(const uint8_t *hash, ECDSA_SIG_0x1c *signature, int key_sel) { - - - uint8_t hmac_in[0x38]; - uint8_t hmac_hash_iv[0x38]; - memcpy(&hmac_in, hash, 0x1c); - memcpy(&hmac_in[0x1c], &keyvault_ec_privkey[key_sel], 0x1c); - - HMAC_CTX *hmac_ctx = HMAC_CTX_new(); - HMAC_Init_ex(hmac_ctx, &hmac_key_0x22, 0x40, EVP_sha256(), NULL); - HMAC_Update(hmac_ctx, &hmac_in, 0x1c << 1); - unsigned int len; - HMAC_Final(hmac_ctx, &hmac_hash_iv, &len); - HMAC_CTX_free(hmac_ctx); - - uint8_t sha256_out[0x40]; - int ret = 0; - do { - ret = can_be_reversed_80C17A(hash, 0x1c, hmac_hash_iv, &sha256_out[0]); - if(ret != 0 || (ret = can_be_reversed_80C17A(hash, 0x1c, hmac_hash_iv, &sha256_out[0x20])) != 0) - return 0; - - } while(ret != 0); - - //ECDSA - - BIGNUM *a = BN_bin2bn(keyvault_ec_a, 0x1c, NULL), - *b = BN_bin2bn(keyvault_ec_b, 0x1c, NULL), - *p = BN_bin2bn(keyvault_ec_p, 0x1c, NULL), - *order = BN_bin2bn(keyvault_ec_N, 0x1c, NULL), - *x = BN_bin2bn(keyvault_ec_Gx, 0x1c, NULL), - *y = BN_bin2bn(keyvault_ec_Gy, 0x1c, NULL), - *priv_key = BN_bin2bn(keyvault_ec_privkey[key_sel], 0x1c, NULL), - *m = BN_bin2bn(sha256_out, 0x3c, NULL); - - BN_CTX *bn_ctx = BN_CTX_new(); - BN_MONT_CTX *bn_mon_ctx = BN_MONT_CTX_new(); - BN_MONT_CTX_set(bn_mon_ctx, order, bn_ctx); - - EC_GROUP *curve = EC_GROUP_new_curve_GFp(p, a, b, bn_ctx); - EC_POINT *generator = EC_POINT_new(curve); - EC_POINT_set_affine_coordinates_GFp(curve, generator, x, y, bn_ctx); - EC_GROUP_set_generator(curve, generator, order, NULL); - - EC_KEY *eckey=EC_KEY_new(); - EC_KEY_set_group(eckey,curve); - EC_KEY_set_private_key(eckey, priv_key); - - - m = BN_bin2bn(sha256_out, 0x3c, NULL); - BN_mod(m, m, order, bn_ctx); - - - - //Generate R in order to get custom "random number" - BIGNUM *sig_r = BN_new(); - EC_POINT_mul(curve, generator, m, NULL, NULL, bn_ctx); - EC_POINT_get_affine_coordinates_GFp(curve, generator, sig_r, NULL, bn_ctx); - BN_nnmod(sig_r, sig_r, order, bn_ctx); - - //Generate M^-1 - BIGNUM *exp = BN_new(); - BIGNUM *minv = BN_new(); - - BN_set_word(exp, (BN_ULONG)2); - BN_sub(exp, order, exp); - BN_mod_exp_mont(minv, m, exp, order, bn_ctx, bn_mon_ctx); - - - ECDSA_SIG *sig = ECDSA_do_sign_ex(hash, 0x1c, minv, sig_r, eckey); - - - if(!sig) { - ret = 0; - goto error; - - } - BIGNUM *sig_s; - ECDSA_SIG_get0(sig, NULL, &sig_s); - BN_bn2bin(sig_r, &signature->r); - BN_bn2bin(sig_s, &signature->s); - ECDSA_SIG_free(sig); - //BN_free(sig_s); - ret = 1; - -error: - BN_free(sig_r); - - EC_POINT_free(generator); - BN_free(y); - BN_free(x); - BN_free(order); - BN_free(p); - BN_free(b); - BN_free(a); - BN_free(minv); - BN_free(exp); - BN_free(priv_key); - BN_CTX_free(bn_ctx); - BN_MONT_CTX_free(bn_mon_ctx); - return ret; - -} - - -__declspec(dllexport) int chovy_gen(char *ebootpbp, uint64_t signaid, char *outscefile) -{ - - int ret = 1; - FILE *fin = 0, *fout = 0; - - uint8_t *work_buf = (unsigned char*) calloc (1, WORK_BUF_SZ); - sce_ebootpbp *sceebootpbp_file = (unsigned char*) calloc (1, sizeof(sce_ebootpbp)); - - - fin = fopen(ebootpbp, "rb"); - if (!fin) { - - goto error; - } - memcpy(&sceebootpbp_file->magic, "NPUMDSIG", 0x8); - sceebootpbp_file->type = 2; - sceebootpbp_file->key_type = 1; - sceebootpbp_file->aid = signaid; - - - fseek(fin, 0, SEEK_END); - sceebootpbp_file->filesz = ftell(fin); - - pbp_hdr hdr; - fseek(fin, 0, SEEK_SET); - fread(&hdr, sizeof(pbp_hdr),1,fin); - - - fseek(fin, 0, SEEK_SET); - fread(work_buf, hdr.icon0_offset, 1,fin); - - uint8_t work_hash[0x1c]; - SHA256_CTX sha256_ctx; - SHA224_Init(&sha256_ctx); - SHA224_Update(&sha256_ctx, work_buf, hdr.icon0_offset); - SHA224_Final(work_hash, &sha256_ctx); - f00d_KIRK0x22(work_hash, &sceebootpbp_file->ebootpbp_hdr_sig, sceebootpbp_file->key_type); - - SHA224_Init(&sha256_ctx); - fseek(fin, hdr.data_psar_offset, SEEK_SET); - - size_t size = PSAR_SZ; - int to_read = size > WORK_BUF_SZ ? WORK_BUF_SZ : size; - - - fread(work_buf, to_read, 1,fin); - if(memcmp(work_buf, "NPUMDIMG", 0x8) == 0) - memcpy(&sceebootpbp_file->np_title, work_buf + 0x10, sizeof(sceebootpbp_file->np_title)); - else { - memcpy(&sceebootpbp_file->magic, "NPPS1SIG", sizeof(sceebootpbp_file->magic)); - sceebootpbp_file->type = 3; - } - - do { - size -= to_read; - SHA224_Update(&sha256_ctx, work_buf, to_read); - to_read = size > WORK_BUF_SZ ? WORK_BUF_SZ : size; - fread(work_buf, to_read, 1,fin); - } while(size > 0); - - SHA224_Final(work_hash, &sha256_ctx); - - f00d_KIRK0x22(work_hash, &sceebootpbp_file->NPUMDIMG_sig, sceebootpbp_file->key_type); - - SHA224_Init(&sha256_ctx); - SHA224_Update(&sha256_ctx, sceebootpbp_file, 0x1C8); - SHA224_Final(work_hash, &sha256_ctx); - - f00d_KIRK0x22(work_hash, &sceebootpbp_file->sceebootpbp_sig, sceebootpbp_file->key_type); - - fout = fopen(outscefile, "wb"); - if (!fout) { - goto error; - } - fwrite(sceebootpbp_file, 1, sizeof(sce_ebootpbp), fout); - - ret = 0; -error: - if (fin) - fclose(fin); - if (fout) - fclose(fout); - free(work_buf); - free(sceebootpbp_file); - return ret; -} diff --git a/CHOVY-GEN/key_vault.h b/CHOVY-GEN/key_vault.h deleted file mode 100644 index 2488e5e..0000000 --- a/CHOVY-GEN/key_vault.h +++ /dev/null @@ -1,17 +0,0 @@ -uint8_t keyvault_ec_p[0x1c] = {0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x53, 0x73, 0xD3, 0x79, 0xF6, 0x9D, 0xA2, 0x8D, 0x09, 0x99, 0x9F, 0xED, 0x57, 0xA9, 0x0F}; -uint8_t keyvault_ec_a[0x1c] = {0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x53, 0x73, 0xD3, 0x79, 0xF6, 0x9D, 0xA2, 0x8D, 0x09, 0x99, 0x9F, 0xED, 0x57, 0xA9, 0x0C}; -uint8_t keyvault_ec_b[0x1c] = {0x90, 0x65, 0x94, 0x1D, 0x29, 0x37, 0x4A, 0x8F, 0x11, 0xDD, 0x1E, 0x54, 0x01, 0x89, 0x43, 0x4E, 0x4A, 0x6E, 0xBF, 0xAF, 0x54, 0x77, 0xF6, 0xC1, 0x72, 0xF6, 0x85, 0x5E}; -uint8_t keyvault_ec_N[0x1c] = { 0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x52, 0x26, 0x98, 0xDE, 0xEF, 0x58, 0xDB, 0x1A, 0xD9, 0xAB, 0x7F, 0x04, 0xE3, 0xAE, 0x7F}; -uint8_t keyvault_ec_Gx[0x1c] = {0x7E, 0x06, 0x09, 0x82, 0x47, 0xE6, 0xB5, 0x9F, 0x31, 0x10, 0xBC, 0xBB, 0x3A, 0xB6, 0xC2, 0x50, 0xBC, 0x5A, 0xB0, 0x6C, 0x03, 0x2D, 0xAD, 0x43, 0x68, 0x4C, 0x24, 0x8F}; -uint8_t keyvault_ec_Gy[0x1c] = {0x0B, 0xD9, 0x41, 0x8D, 0xE8, 0xE3, 0xE4, 0x5D, 0x2D, 0x70, 0x1E, 0x02, 0x37, 0xFD, 0x7F, 0x2A, 0xDE, 0x0D, 0x48, 0xB7, 0x4C, 0xEE, 0xF2, 0xF1, 0xC8, 0xAC, 0x48, 0x4E}; -uint8_t keyvault_ec_pubkey[2][0x38] = { - {0x5F, 0x9D, 0x17, 0x1A, 0x2B, 0xDD, 0xA8, 0xD4, 0x08, 0x78, 0xBF, 0x98, 0x5A, 0xC3, 0x26, 0xED, 0x5E, 0xFF, 0x43, 0xC9, 0x37, 0x6C, 0x77, 0xEC, 0x0A, 0x00, 0xC7, 0xBB, 0xA3, 0x44, 0xE4, 0x4E, 0x6E, 0xAC, 0x25, 0x52, 0x35, 0xF9, 0x54, 0xF5, 0xB6, 0x17, 0xC7, 0xBD, 0x49, 0xF1, 0x80, 0x26, 0x24, 0x54, 0xAA, 0xE1, 0xB6, 0x2A, 0x9F, 0x2C}, - {0x67, 0x00, 0x2D, 0x9B, 0xB8, 0xE4, 0x2D, 0x2B, 0xF9, 0x61, 0x0B, 0x27, 0xFE, 0xAB, 0x9B, 0x34, 0x56, 0x15, 0x50, 0x92, 0x13, 0x12, 0xDF, 0xEE, 0x7A, 0x3A, 0x86, 0xEC, 0x6C, 0xA7, 0x14, 0x42, 0x6F, 0x6D, 0x4E, 0x96, 0x09, 0xA6, 0x38, 0xBF, 0x4A, 0xFB, 0x18, 0x2B, 0xFA, 0x50, 0xC8, 0x2F, 0xF2, 0xB4, 0xC5, 0xEC, 0x6C, 0xCD, 0x97, 0x65} - }; - -uint8_t keyvault_ec_privkey[2][0x1c] = { - {0x76, 0x74, 0x36, 0xA6, 0x99, 0x9D, 0x88, 0x48, 0x0E, 0xC8, 0x56, 0xF5, 0x5C, 0xEA, 0xBB, 0x43, 0x96, 0x85, 0x9E, 0x37, 0x45, 0x99, 0x40, 0x39, 0x21, 0xF5, 0x55, 0x98}, - {0x60, 0x7A, 0x2E, 0x55, 0x68, 0xB4, 0xB9, 0xA0, 0x32, 0xF4, 0x52, 0x53, 0xCF, 0xED, 0x20, 0xDB, 0x2E, 0x6E, 0x44, 0x6C, 0x37, 0x82, 0xE8, 0x2A, 0x1A, 0xB9, 0xC9, 0x23} - }; - -uint8_t hmac_key_0x22[0x40] = {0x54, 0x88, 0xA9, 0x81, 0x1C, 0x9A, 0x2C, 0xBC, 0xCC, 0x59, 0x6B, 0x1F, 0xAD, 0x1A, 0x7E, 0x29, 0xE0, 0x75, 0x84, 0x0F, 0x47, 0x43, 0x1F, 0x37, 0xAC, 0x06, 0x02, 0x46, 0x4A, 0x27, 0x9E, 0x02, 0xDF, 0x2E, 0x71, 0x65, 0xF1, 0x13, 0x7B, 0xF6, 0x9A, 0xE6, 0xDC, 0xB9, 0xDC, 0x38, 0x8C, 0x9D, 0xCC, 0xB3, 0x64, 0xC4, 0xCA, 0x26, 0xCB, 0x8F, 0x1A, 0xF0, 0x63, 0x8A, 0x6E, 0xAD, 0xB5, 0x4D}; diff --git a/CHOVY-TRANSFER.sln b/CHOVY-TRANSFER.sln index 61b3e78..149950f 100644 --- a/CHOVY-TRANSFER.sln +++ b/CHOVY-TRANSFER.sln @@ -1,11 +1,12 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.76 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33205.214 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CHOVY-TRANSFER", "CHOVY-TRANSFER\CHOVY-TRANSFER.csproj", "{B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CHOVY-TRANSFER", "CHOVY-TRANSFER\CHOVY-TRANSFER.csproj", "{B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CHOVY-GEN", "CHOVY-GEN\CHOVY-GEN.vcxproj", "{DCDBF747-DFB6-450E-A403-1C592D20EAEB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PspCrypto", "PspCrypto\PspCrypto.csproj", "{C93D6CE7-989F-4C89-A29B-9684C9297184}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vita", "Vita\Vita.csproj", "{8463BD1A-EC79-4469-A383-26020298F512}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -29,20 +30,35 @@ Global {B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}.Release|x64.Build.0 = Release|Any CPU {B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}.Release|x86.ActiveCfg = Release|Any CPU {B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}.Release|x86.Build.0 = Release|Any CPU - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|Any CPU.Build.0 = Debug|Win32 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|x64.ActiveCfg = Debug|x64 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|x64.Build.0 = Debug|x64 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|x86.ActiveCfg = Debug|Win32 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|x86.Build.0 = Debug|Win32 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|Any CPU.ActiveCfg = Release|Win32 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|Any CPU.Build.0 = Release|Win32 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|x64.ActiveCfg = Release|x64 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|x64.Build.0 = Release|x64 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|x86.ActiveCfg = Release|Win32 - {DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|x86.Build.0 = Release|Win32 + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|x64.ActiveCfg = Debug|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|x64.Build.0 = Debug|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|x86.ActiveCfg = Debug|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|x86.Build.0 = Debug|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|Any CPU.Build.0 = Release|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|x64.ActiveCfg = Release|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|x64.Build.0 = Release|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|x86.ActiveCfg = Release|Any CPU + {C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|x86.Build.0 = Release|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Debug|x64.ActiveCfg = Debug|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Debug|x64.Build.0 = Debug|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Debug|x86.ActiveCfg = Debug|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Debug|x86.Build.0 = Debug|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Release|Any CPU.Build.0 = Release|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Release|x64.ActiveCfg = Release|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Release|x64.Build.0 = Release|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Release|x86.ActiveCfg = Release|Any CPU + {8463BD1A-EC79-4469-A383-26020298F512}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D2939D13-1FC7-4C9B-95D9-BA3B53E08138} + EndGlobalSection EndGlobal diff --git a/CHOVY-TRANSFER/App.config b/CHOVY-TRANSFER/App.config index a3f4642..f5d114b 100644 --- a/CHOVY-TRANSFER/App.config +++ b/CHOVY-TRANSFER/App.config @@ -2,5 +2,5 @@ - + diff --git a/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj b/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj index c981102..36d7475 100644 --- a/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj +++ b/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj @@ -1,107 +1,32 @@ - - - + - Debug - AnyCPU - {B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C} + net6.0-windows WinExe CHOVY_TRANSFER CHOVY-TRANS - v4.5.2 - 512 - true - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - false + false + true + true chovy-trans.ico + CHOVY-TRANSFER + CHOVY-TRANSFER + Copyright © 2019 + 1.0.0.0 + 1.0.0.0 - - - ..\packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll - - - ..\packages\DotNetZip.1.13.4\lib\net40\DotNetZip.dll - - - - - - - - - - - - - - - - Form - - - CHOVYTRANSFER.cs - - - - - - - - - - CHOVYTRANSFER.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj.user b/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj.user new file mode 100644 index 0000000..5d596ed --- /dev/null +++ b/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj.user @@ -0,0 +1,11 @@ + + + + <_LastSelectedProfileId>C:\Users\Li\Documents\git\chovy-trans\CHOVY-TRANSFER\Properties\PublishProfiles\FolderProfile.pubxml + + + + Form + + + \ No newline at end of file diff --git a/CHOVY-TRANSFER/CHOVYTRANSFER.Designer.cs b/CHOVY-TRANSFER/CHOVYTRANSFER.Designer.cs index 9d7ad8f..15ef931 100644 --- a/CHOVY-TRANSFER/CHOVYTRANSFER.Designer.cs +++ b/CHOVY-TRANSFER/CHOVYTRANSFER.Designer.cs @@ -84,9 +84,10 @@ "X:\\", "Y:\\", "Z:\\"}); - this.driveLetterSrc.Location = new System.Drawing.Point(74, 12); + this.driveLetterSrc.Location = new System.Drawing.Point(86, 14); + this.driveLetterSrc.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.driveLetterSrc.Name = "driveLetterSrc"; - this.driveLetterSrc.Size = new System.Drawing.Size(41, 21); + this.driveLetterSrc.Size = new System.Drawing.Size(47, 23); this.driveLetterSrc.TabIndex = 1; this.driveLetterSrc.SelectedIndexChanged += new System.EventHandler(this.driveLetterSrc_SelectedIndexChanged); // @@ -95,15 +96,18 @@ this.pspFolder.BackColor = System.Drawing.Color.DimGray; this.pspFolder.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.pspFolder.ForeColor = System.Drawing.Color.Lime; - this.pspFolder.Location = new System.Drawing.Point(121, 13); + this.pspFolder.Location = new System.Drawing.Point(141, 15); + this.pspFolder.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.pspFolder.Name = "pspFolder"; - this.pspFolder.Size = new System.Drawing.Size(194, 20); + this.pspFolder.Size = new System.Drawing.Size(226, 23); this.pspFolder.TabIndex = 2; this.pspFolder.Text = "PSP"; this.pspFolder.TextChanged += new System.EventHandler(this.pspFolder_TextChanged); // // groupBox1 // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.groupBox1.BackColor = System.Drawing.Color.Black; this.groupBox1.Controls.Add(this.cmaDir); this.groupBox1.Controls.Add(this.driveLetterDst); @@ -112,21 +116,26 @@ this.groupBox1.Controls.Add(this.driveLetterSrc); this.groupBox1.Controls.Add(this.pspFolder); this.groupBox1.ForeColor = System.Drawing.Color.Lime; - this.groupBox1.Location = new System.Drawing.Point(162, 12); + this.groupBox1.Location = new System.Drawing.Point(189, 14); + this.groupBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(622, 41); + this.groupBox1.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.groupBox1.Size = new System.Drawing.Size(726, 47); this.groupBox1.TabIndex = 3; this.groupBox1.TabStop = false; this.groupBox1.Text = "Directories"; // // cmaDir // + this.cmaDir.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.cmaDir.BackColor = System.Drawing.Color.DimGray; this.cmaDir.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.cmaDir.ForeColor = System.Drawing.Color.Lime; - this.cmaDir.Location = new System.Drawing.Point(439, 14); + this.cmaDir.Location = new System.Drawing.Point(512, 14); + this.cmaDir.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.cmaDir.Name = "cmaDir"; - this.cmaDir.Size = new System.Drawing.Size(177, 20); + this.cmaDir.Size = new System.Drawing.Size(206, 23); this.cmaDir.TabIndex = 6; this.cmaDir.Text = "Users\\XXX\\Documents\\PS Vita"; this.cmaDir.TextChanged += new System.EventHandler(this.cmaDir_TextChanged); @@ -166,59 +175,70 @@ "X:\\", "Y:\\", "Z:\\"}); - this.driveLetterDst.Location = new System.Drawing.Point(392, 12); + this.driveLetterDst.Location = new System.Drawing.Point(457, 13); + this.driveLetterDst.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.driveLetterDst.Name = "driveLetterDst"; - this.driveLetterDst.Size = new System.Drawing.Size(41, 21); + this.driveLetterDst.Size = new System.Drawing.Size(47, 23); this.driveLetterDst.TabIndex = 5; this.driveLetterDst.SelectedIndexChanged += new System.EventHandler(this.driveLetterDst_SelectedIndexChanged); // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(321, 16); + this.label2.Location = new System.Drawing.Point(376, 17); + this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(65, 13); + this.label2.Size = new System.Drawing.Size(73, 15); this.label2.TabIndex = 4; this.label2.Text = "CMA Folder:"; // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(11, 16); + this.label1.Location = new System.Drawing.Point(13, 18); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(63, 13); + this.label1.Size = new System.Drawing.Size(66, 15); this.label1.TabIndex = 3; this.label1.Text = "PSP Folder:"; // // pspGames // + this.pspGames.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.pspGames.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); this.pspGames.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.pspGames.ForeColor = System.Drawing.Color.Lime; this.pspGames.FormattingEnabled = true; - this.pspGames.Location = new System.Drawing.Point(162, 73); + this.pspGames.ItemHeight = 15; + this.pspGames.Location = new System.Drawing.Point(189, 84); + this.pspGames.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.pspGames.Name = "pspGames"; - this.pspGames.Size = new System.Drawing.Size(622, 223); + this.pspGames.Size = new System.Drawing.Size(725, 257); this.pspGames.TabIndex = 4; // // label3 // this.label3.AutoSize = true; this.label3.ForeColor = System.Drawing.Color.Lime; - this.label3.Location = new System.Drawing.Point(159, 56); + this.label3.Location = new System.Drawing.Point(186, 65); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(82, 13); + this.label3.Size = new System.Drawing.Size(86, 15); this.label3.TabIndex = 5; this.label3.Text = "Games on PSP:"; // // transVita // + this.transVita.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.transVita.BackColor = System.Drawing.Color.Black; this.transVita.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.transVita.ForeColor = System.Drawing.Color.Red; - this.transVita.Location = new System.Drawing.Point(649, 302); + this.transVita.Location = new System.Drawing.Point(757, 348); + this.transVita.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.transVita.Name = "transVita"; - this.transVita.Size = new System.Drawing.Size(135, 23); + this.transVita.Size = new System.Drawing.Size(158, 27); this.transVita.TabIndex = 6; this.transVita.Text = "MOV 1, PSVITA"; this.transVita.UseVisualStyleBackColor = false; @@ -227,56 +247,68 @@ // // progressBar // - this.progressBar.Location = new System.Drawing.Point(202, 302); + this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar.Location = new System.Drawing.Point(236, 348); + this.progressBar.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.progressBar.Name = "progressBar"; - this.progressBar.Size = new System.Drawing.Size(441, 23); + this.progressBar.Size = new System.Drawing.Size(514, 27); this.progressBar.TabIndex = 7; // // progressStatus // - this.progressStatus.AutoSize = true; + this.progressStatus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.progressStatus.ForeColor = System.Drawing.Color.Lime; - this.progressStatus.Location = new System.Drawing.Point(159, 307); + this.progressStatus.Location = new System.Drawing.Point(186, 354); + this.progressStatus.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.progressStatus.Name = "progressStatus"; - this.progressStatus.Size = new System.Drawing.Size(21, 13); + this.progressStatus.Size = new System.Drawing.Size(42, 17); this.progressStatus.TabIndex = 8; this.progressStatus.Text = "0%"; + this.progressStatus.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // // pictureBox1 // + this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); this.pictureBox1.BackgroundImage = global::CHOVY_TRANSFER.Properties.Resources.chovytrans; this.pictureBox1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; - this.pictureBox1.Location = new System.Drawing.Point(9, 8); + this.pictureBox1.Location = new System.Drawing.Point(10, 9); + this.pictureBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.pictureBox1.Name = "pictureBox1"; - this.pictureBox1.Size = new System.Drawing.Size(144, 330); + this.pictureBox1.Size = new System.Drawing.Size(168, 381); this.pictureBox1.TabIndex = 9; this.pictureBox1.TabStop = false; // // dexToggle // - this.dexToggle.Location = new System.Drawing.Point(781, 0); + this.dexToggle.Location = new System.Drawing.Point(911, 0); + this.dexToggle.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.dexToggle.Name = "dexToggle"; - this.dexToggle.Size = new System.Drawing.Size(16, 16); + this.dexToggle.Size = new System.Drawing.Size(19, 18); this.dexToggle.TabIndex = 10; this.dexToggle.TabStop = false; this.dexToggle.Click += new System.EventHandler(this.dexToggle_Click); // // currentFile // - this.currentFile.AutoSize = true; + this.currentFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.currentFile.ForeColor = System.Drawing.Color.Lime; - this.currentFile.Location = new System.Drawing.Point(173, 328); + this.currentFile.Location = new System.Drawing.Point(186, 378); + this.currentFile.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.currentFile.Name = "currentFile"; - this.currentFile.Size = new System.Drawing.Size(55, 13); + this.currentFile.Size = new System.Drawing.Size(728, 17); this.currentFile.TabIndex = 11; this.currentFile.Text = "Waiting ..."; + this.currentFile.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // // CHOVYTRANSFER // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.Color.Black; - this.ClientSize = new System.Drawing.Size(796, 350); + this.ClientSize = new System.Drawing.Size(929, 404); this.Controls.Add(this.currentFile); this.Controls.Add(this.dexToggle); this.Controls.Add(this.pictureBox1); @@ -287,6 +319,7 @@ this.Controls.Add(this.pspGames); this.Controls.Add(this.groupBox1); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.Name = "CHOVYTRANSFER"; this.Text = "Chovy-Transfer"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.CHOVYTRANSFER_FormClosing); diff --git a/CHOVY-TRANSFER/CHOVYTRANSFER.cs b/CHOVY-TRANSFER/CHOVYTRANSFER.cs index 1c7b3d8..d47babc 100644 --- a/CHOVY-TRANSFER/CHOVYTRANSFER.cs +++ b/CHOVY-TRANSFER/CHOVYTRANSFER.cs @@ -2,22 +2,42 @@ using System; using System.IO; using System.Windows.Forms; -using Param_SFO; using System.Runtime.InteropServices; using System.Text; -using KeyDerivation; -using PSVIMGTOOLS; using System.Drawing; using System.Threading; using System.Collections.Generic; using System.Linq; +using Li.Progress; +using Param; +using PspCrypto; +using Vita.ContentManager; +using Vita.PsvImgTools; +using System.Security.Cryptography; +using System.Threading.Tasks; + namespace CHOVY_TRANSFER { public partial class CHOVYTRANSFER : Form { - [DllImport("CHOVY.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern int chovy_gen(string ebootpbp, UInt64 AID, string outscefile); + const int FW_VERSION = 0x3600000; + private byte[] chovy_gen(string ebootpbp, UInt64 AID) + { + bool ps1 = IsPs1(ebootpbp); + using (FileStream fs = File.OpenRead(ebootpbp)) + { + byte[] ebootSig = new byte[0x200]; + SceNpDrm.Aid = AID; + + if(ps1) + SceNpDrm.KsceNpDrmEbootSigGenPs1(fs, ebootSig, FW_VERSION); + else + SceNpDrm.KsceNpDrmEbootSigGenPsp(fs, ebootSig, FW_VERSION); + + return ebootSig; + } + } public bool IsDexAidSet() { @@ -31,55 +51,6 @@ namespace CHOVY_TRANSFER return true; } } - public string GetCmaDir() - { - string Dir = ""; - try - { - //try qcma - Dir = Registry.CurrentUser.OpenSubKey(@"Software\codestation\qcma").GetValue("appsPath").ToString(); - } - catch (Exception) - { - try - { - //try sony cma - Dir = Registry.CurrentUser.OpenSubKey(@"Software\Sony Corporation\Content Manager Assistant\Settings").GetValue("ApplicationHomePath").ToString(); - } - catch (Exception) - { - try - { - //try devkit cma - Dir = Registry.CurrentUser.OpenSubKey(@"Software\SCE\PSP2\Services\Content Manager Assistant for PlayStation(R)Vita DevKit\Settings").GetValue("ApplicationHomePath").ToString(); - } - catch (Exception) - { - try - { - string DefaultDir = Path.Combine(Environment.GetEnvironmentVariable("HOMEDRIVE"), Environment.GetEnvironmentVariable("HOMEPATH"), "Documents", "PS Vita"); - if (Directory.Exists(DefaultDir)) - { - Dir = DefaultDir; - } - } - catch (Exception) - { - //Do nothing - } - } - } - - } - - if (ReadSetting("CmaDir") != "") - { - Dir = ReadSetting("CmaDir"); - } - - return Dir.Replace("/","\\"); - } - public string ReadSetting(string Setting) { @@ -160,13 +131,10 @@ namespace CHOVY_TRANSFER string Title = GetTitleFromPbp(EbootPbp); string ContentId = GetContentIdFromPbp(EbootPbp); + string LicenseFile = Path.Combine(PspDir, "LICENSE", ContentId + ".RIF"); - string LicenseFile = Path.Combine(PspDir, "LICENSE", ContentId); - - if (TitleId.Length == 9 && File.Exists(LicenseFile)); - { + if (TitleId.Length == 9 && File.Exists(LicenseFile)) pspGames.Items.Add(TitleId + " - " + Title); - } } catch (Exception) { }; @@ -194,12 +162,8 @@ namespace CHOVY_TRANSFER public string GetTitleFromPbp(string pbp) { byte[] SfoData = GetSfo(pbp); - - using (MemoryStream ms = new MemoryStream(SfoData, 0x00, SfoData.Length)) - { - PARAM_SFO sfo = new PARAM_SFO(ms); - return sfo.Title; - } + Sfo sfo = Sfo.ReadSfo(SfoData); + return sfo["TITLE"] as String; } public byte[] GetSfo(string pbp) @@ -338,8 +302,14 @@ namespace CHOVY_TRANSFER pspFolder.Text = PspDir; } + string cmaDir = ReadSetting("CmaDir"); + if(cmaDir == "") + cmaDir = SettingsReader.BackupsFolder; + + SettingsReader.BackupsFolder = cmaDir; + ChangePspDir(FindPspDir()); - ChangeCmaDir(GetCmaDir()); + ChangeCmaDir(SettingsReader.BackupsFolder); PopulatePspGameList(); } @@ -356,11 +326,13 @@ namespace CHOVY_TRANSFER private void cmaDir_TextChanged(object sender, EventArgs e) { - WriteSetting("CmaDir", Path.Combine(driveLetterDst.Text, cmaDir.Text)); + string dir = Path.Combine(driveLetterDst.Text, cmaDir.Text); + WriteSetting("CmaDir", dir); + SettingsReader.BackupsFolder = dir; } private void driveLetterDst_SelectedIndexChanged(object sender, EventArgs e) { - WriteSetting("CmaDir", Path.Combine(driveLetterDst.Text, cmaDir.Text)); + cmaDir_TextChanged(sender, e); } private void transVita_EnabledChanged(object sender, EventArgs e) { @@ -376,10 +348,10 @@ namespace CHOVY_TRANSFER Environment.Exit(0); } - private void transVita_Click(object sender, EventArgs e) + private async void transVita_Click(object sender, EventArgs e) { - if(!Directory.Exists(Path.Combine(driveLetterDst.Text, cmaDir.Text))) + if(!Directory.Exists(SettingsReader.BackupsFolder)) { MessageBox.Show("CMA Folder Doesn't Exist", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -404,19 +376,23 @@ namespace CHOVY_TRANSFER cmaDir.ReadOnly = true; pspGames.Enabled = false; + bool isDlc = false; + string titleId = pspGames.SelectedItem.ToString().Substring(0, 9); - string gameFolder = Path.Combine(driveLetterSrc.Text, pspFolder.Text, "GAME", titleId); + string pspDir = Path.Combine(driveLetterSrc.Text, pspFolder.Text); + string gameFolder = Path.Combine(pspDir, "GAME", titleId); string ebootFile = Path.Combine(gameFolder, "EBOOT.PBP"); if (!File.Exists(ebootFile)) + { + isDlc = true; ebootFile = Path.Combine(gameFolder, "PARAM.PBP"); + } List licenseFiles = new List(); string cid = GetContentIdFromPbp(ebootFile); - licenseFiles.Add(Path.Combine(driveLetterSrc.Text, pspFolder.Text, "LICENSE", cid + ".RIF")); + licenseFiles.Add(Path.Combine(pspDir, "LICENSE", cid + ".RIF")); string sigFile = Path.Combine(gameFolder, "__sce_ebootpbp"); - string backupDir = Path.Combine(driveLetterDst.Text, cmaDir.Text); - - bool isDlc = Path.GetFileName(gameFolder) == "PARAM.PBP"; + bool isPs1 = IsPs1(ebootFile); if (!File.Exists(licenseFiles.First())) @@ -444,74 +420,44 @@ namespace CHOVY_TRANSFER File.Delete(sigFile); } - int ChovyGenRes = 100; - Thread ChovyGen = new Thread(() => - { - ChovyGenRes = chovy_gen(ebootFile, uAid, sigFile); - }); - - ChovyGen.Start(); - while (ChovyGen.IsAlive) - { - Application.DoEvents(); - } - - if (!File.Exists(sigFile) || ChovyGenRes != 0 && !isDlc) - { - MessageBox.Show("CHOVY-GEN Failed! Please check CHOVY.DLL exists\nand that the Microsoft Visual C++ 2015 Redistributable Update 3 RC is installed", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - transVita.Enabled = true; - driveLetterDst.Enabled = true; - driveLetterSrc.Enabled = true; - pspFolder.ReadOnly = false; - cmaDir.ReadOnly = false; - pspGames.Enabled = true; - return; - } + byte[] EbootSig = chovy_gen(ebootFile, uAid); + Account CmaAccount = new Account(uAid); + CmaAccount.Devkit = IsDexAidSet(); + /* * BUILD PSVIMG FILE(s) */ // Pacakge GAME - - byte[] CmaKey; - if(!IsDexAidSet()) - { - CmaKey = CmaKeys.GenerateKey(bAid); - } - else - { - CmaKey = CmaKeys.GenerateKey(new byte[0x8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); - } + byte[] CmaKey = CmaAccount.CmaKey; string[] entrys = Directory.GetFileSystemEntries(gameFolder, "*", SearchOption.AllDirectories); long noEntrys = entrys.LongLength; string parentPath = "ux0:pspemu/temp/game/PSP/GAME/" + titleId; int noBlocks = 0; foreach (string fileName in Directory.GetFiles(gameFolder, "*", SearchOption.AllDirectories)) - { noBlocks += Convert.ToInt32(new FileInfo(fileName).Length / PSVIMGConstants.PSVIMG_BLOCK_SIZE); - } progressBar.Maximum = noBlocks; string pgameFolder; - string pgameFolderl; + string pgameFolderLicense; string scesys; if (!isPs1) { if(!IsDexAidSet()) { - pgameFolder = Path.Combine(backupDir, "PGAME", sAid, titleId, "game"); - pgameFolderl = Path.Combine(backupDir, "PGAME", sAid, titleId, "license"); - scesys = Path.Combine(backupDir, "PGAME", sAid, titleId, "sce_sys"); + pgameFolder = Path.Combine(SettingsReader.PspFolder, sAid, titleId, "game"); + pgameFolderLicense = Path.Combine(SettingsReader.PspFolder, sAid, titleId, "license"); + scesys = Path.Combine(SettingsReader.PspFolder, sAid, titleId, "sce_sys"); } else { - pgameFolder = Path.Combine(backupDir, "PGAME", "0000000000000000", titleId, "game"); - pgameFolderl = Path.Combine(backupDir, "PGAME", "0000000000000000", titleId, "license"); - scesys = Path.Combine(backupDir, "PGAME", "0000000000000000", titleId, "sce_sys"); + pgameFolder = Path.Combine(SettingsReader.PspFolder, "0000000000000000", titleId, "game"); + pgameFolderLicense = Path.Combine(SettingsReader.PspFolder, "0000000000000000", titleId, "license"); + scesys = Path.Combine(SettingsReader.PspFolder, "0000000000000000", titleId, "sce_sys"); } } @@ -519,94 +465,95 @@ namespace CHOVY_TRANSFER { if(!IsDexAidSet()) { - pgameFolder = Path.Combine(backupDir, "PSGAME", sAid, titleId, "game"); - pgameFolderl = Path.Combine(backupDir, "PSGAME", sAid, titleId, "license"); - scesys = Path.Combine(backupDir, "PSGAME", sAid, titleId, "sce_sys"); + pgameFolder = Path.Combine(SettingsReader.Ps1Folder, sAid, titleId, "game"); + pgameFolderLicense = Path.Combine(SettingsReader.Ps1Folder, sAid, titleId, "license"); + scesys = Path.Combine(SettingsReader.Ps1Folder, sAid, titleId, "sce_sys"); } else { - pgameFolder = Path.Combine(backupDir, "PSGAME", "0000000000000000", titleId, "game"); - pgameFolderl = Path.Combine(backupDir, "PSGAME", "0000000000000000", titleId, "license"); - scesys = Path.Combine(backupDir, "PSGAME", "0000000000000000", titleId, "sce_sys"); + pgameFolder = Path.Combine(SettingsReader.Ps1Folder, "0000000000000000", titleId, "game"); + pgameFolderLicense = Path.Combine(SettingsReader.Ps1Folder, "0000000000000000", titleId, "license"); + scesys = Path.Combine(SettingsReader.Ps1Folder, "0000000000000000", titleId, "sce_sys"); } } Directory.CreateDirectory(pgameFolder); - Directory.CreateDirectory(pgameFolderl); + Directory.CreateDirectory(pgameFolderLicense); Directory.CreateDirectory(scesys); - string psvimgFilepathl = Path.Combine(pgameFolderl, "license.psvimg"); + string psvimgFilepathLicense = Path.Combine(pgameFolderLicense, "license.psvimg"); string psvimgFilepath = Path.Combine(pgameFolder, "game.psvimg"); - string psvmdFilepathl = Path.Combine(pgameFolderl, "license.psvmd"); + string psvmdFilepathLicense = Path.Combine(pgameFolderLicense, "license.psvmd"); string psvmdFilepath = Path.Combine(pgameFolder, "game.psvmd"); - FileStream gamePsvimg = File.OpenWrite(psvimgFilepath); - gamePsvimg.SetLength(0); - PSVIMGBuilder builder = new PSVIMGBuilder(gamePsvimg, CmaKey); - - foreach (string entry in entrys) + await Task.Run(() => { - string relativePath = entry.Remove(0, gameFolder.Length); - relativePath = relativePath.Replace('\\', '/'); - - if(Path.GetExtension(entry).ToUpperInvariant() == ".EDAT") + using (FileStream gamePsvimg = File.Open(psvimgFilepath, FileMode.Create, FileAccess.ReadWrite)) { - string edatContentId = GetContentIdFromPspEdat(entry); - string rifPath = Path.Combine(driveLetterSrc.Text, pspFolder.Text, "LICENSE", edatContentId + ".RIF"); - if (!licenseFiles.Contains(rifPath) && File.Exists(rifPath)) - licenseFiles.Add(rifPath); - } - - bool isDir = File.GetAttributes(entry).HasFlag(FileAttributes.Directory); - - if (isDir) - { - builder.AddDir(entry, parentPath, relativePath); - } - else - { - builder.AddFileAsync(entry, parentPath, relativePath); - while (!builder.HasFinished) + PSVIMGBuilder builder = new PSVIMGBuilder(gamePsvimg, CmaKey); + builder.RegisterCallback((ProgressInfo inf) => { - try - { + Invoke((Action)delegate { int tBlocks = builder.BlocksWritten; + if (tBlocks > noBlocks) tBlocks = noBlocks; progressBar.Value = tBlocks; decimal progress = Math.Floor(((decimal)tBlocks / (decimal)noBlocks) * 100); progressStatus.Text = progress.ToString() + "%"; - currentFile.Text = "Processing: " + Path.GetFileName(entry); + currentFile.Text = inf.CurrentProcess; + }); + }); + + foreach (string entry in entrys) + { + string relativePath = entry.Remove(0, gameFolder.Length); + relativePath = relativePath.Replace('\\', '/'); + + if (Path.GetExtension(entry).ToUpperInvariant() == ".EDAT") + { + string edatContentId = GetContentIdFromPspEdat(entry); + string rifPath = Path.Combine(pspDir, "LICENSE", edatContentId + ".RIF"); + if (!licenseFiles.Contains(rifPath) && File.Exists(rifPath)) + licenseFiles.Add(rifPath); } - catch (Exception) { } - Application.DoEvents(); + bool isDir = File.GetAttributes(entry).HasFlag(FileAttributes.Directory); + + if (isDir) + { + builder.AddDir(entry, parentPath, relativePath); + } + else + { + builder.AddFile(entry, parentPath, relativePath); + } } + + // add __sce_ebootpbp + if(!isDlc) + builder.AddFile(EbootSig, parentPath, "/__sce_ebootpbp"); + + long ContentSize = builder.Finish(); + + using (FileStream gamePsvmd = File.Open(psvmdFilepath, FileMode.Create, FileAccess.ReadWrite)) + PSVMDBuilder.CreatePsvmd(gamePsvmd, gamePsvimg, ContentSize, "game", CmaKey); } - } - - long ContentSize = builder.Finish(); - gamePsvimg = File.OpenRead(psvimgFilepath); - FileStream gamePsvmd = File.OpenWrite(psvmdFilepath); - PSVMDBuilder.CreatePsvmd(gamePsvmd, gamePsvimg, ContentSize, "game", CmaKey); - gamePsvmd.Close(); - gamePsvimg.Close(); - // Package LICENSE - FileStream licensePsvimg = File.OpenWrite(psvimgFilepathl); - licensePsvimg.SetLength(0); - builder = new PSVIMGBuilder(licensePsvimg, CmaKey); - foreach(string licenseFile in licenseFiles) - builder.AddFile(licenseFile, "ux0:pspemu/temp/game/PSP/LICENSE", "/" + Path.GetFileNameWithoutExtension(licenseFile) + ".rif"); - ContentSize = builder.Finish(); - - licensePsvimg = File.OpenRead(psvimgFilepathl); - FileStream licensePsvmd = File.OpenWrite(psvmdFilepathl); - PSVMDBuilder.CreatePsvmd(licensePsvmd, licensePsvimg, ContentSize, "license", CmaKey); - licensePsvmd.Close(); - licensePsvimg.Close(); + // Package LICENSE + using (FileStream licensePsvimg = File.Open(psvimgFilepathLicense, FileMode.Create, FileAccess.ReadWrite)) + { + PSVIMGBuilder builder = new PSVIMGBuilder(licensePsvimg, CmaKey); + foreach (string licenseFile in licenseFiles) + builder.AddFile(licenseFile, "ux0:pspemu/temp/game/PSP/LICENSE", "/" + Path.GetFileNameWithoutExtension(licenseFile) + ".rif"); + long ContentSize = builder.Finish(); + using (FileStream licensePsvmd = File.Open(psvmdFilepathLicense, FileMode.Create, FileAccess.ReadWrite)) + PSVMDBuilder.CreatePsvmd(licensePsvmd, licensePsvimg, ContentSize, "license", CmaKey); + } + }); + // Write PARAM.SFO & ICON0.PNG byte[] ParamSfo = GetSfo(ebootFile); diff --git a/CHOVY-TRANSFER/CHOVYTRANSFER.resx b/CHOVY-TRANSFER/CHOVYTRANSFER.resx index fb7c757..ff44fd5 100644 --- a/CHOVY-TRANSFER/CHOVYTRANSFER.resx +++ b/CHOVY-TRANSFER/CHOVYTRANSFER.resx @@ -1,64 +1,4 @@ - - - + diff --git a/CHOVY-TRANSFER/Properties/AssemblyInfo.cs b/CHOVY-TRANSFER/Properties/AssemblyInfo.cs index 89b2172..8cfac4e 100644 --- a/CHOVY-TRANSFER/Properties/AssemblyInfo.cs +++ b/CHOVY-TRANSFER/Properties/AssemblyInfo.cs @@ -1,16 +1,6 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("CHOVY-TRANSFER")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("CHOVY-TRANSFER")] -[assembly: AssemblyCopyright("Copyright © 2019")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -21,16 +11,3 @@ using System.Runtime.InteropServices; // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("b4cad2c0-ba54-46b6-a8d0-43a9c2390d3c")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml b/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..9c7c088 --- /dev/null +++ b/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,18 @@ + + + + + Release + Any CPU + bin\Release\net6.0-windows\publish\win-x86\ + FileSystem + <_TargetId>Folder + net6.0-windows + win-x86 + true + true + true + + \ No newline at end of file diff --git a/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml.user b/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml.user new file mode 100644 index 0000000..5b523f4 --- /dev/null +++ b/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -0,0 +1,10 @@ + + + + + True|2023-07-10T03:53:35.4493264Z;True|2023-07-10T15:48:49.3356830+12:00;True|2023-07-10T15:44:35.4847823+12:00;True|2023-07-10T15:42:39.5955955+12:00;True|2023-07-10T15:30:22.5199359+12:00;True|2023-07-10T13:56:34.8005938+12:00; + + + \ No newline at end of file diff --git a/CHOVY-TRANSFER/Properties/Resources.Designer.cs b/CHOVY-TRANSFER/Properties/Resources.Designer.cs index d2bd39e..18c5fdc 100644 --- a/CHOVY-TRANSFER/Properties/Resources.Designer.cs +++ b/CHOVY-TRANSFER/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace CHOVY_TRANSFER.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { diff --git a/CHOVY-TRANSFER/Properties/Settings.Designer.cs b/CHOVY-TRANSFER/Properties/Settings.Designer.cs index 24a2001..54c4a3c 100644 --- a/CHOVY-TRANSFER/Properties/Settings.Designer.cs +++ b/CHOVY-TRANSFER/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace CHOVY_TRANSFER.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.0.1.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/CHOVY-TRANSFER/Sfo.cs b/CHOVY-TRANSFER/Sfo.cs new file mode 100644 index 0000000..dd7ed35 --- /dev/null +++ b/CHOVY-TRANSFER/Sfo.cs @@ -0,0 +1,257 @@ +using Li.Utilities; +using System; +using System.Collections.Generic; +using System.Diagnostics.Tracing; +using System.IO; +using System.Runtime.CompilerServices; + +// A Sfo Parser Written by Li +// Because all the others are overly-complicated for no reason! +// MIT Licensed. + +namespace Param +{ + + public class Sfo + { + + private struct SfoEntry + { + internal string keyName; + internal byte type; + internal UInt32 valueSize; + internal UInt32 totalSize; + internal byte align; + internal object value; + } + + const int SFO_MAGIC = 0x46535000; + const byte PSF_TYPE_BIN = 0; + const byte PSF_TYPE_STR = 2; + const byte PSF_TYPE_VAL = 4; + + private Dictionary sfoEntries; + public Object this[string index] + { + get + { + if (sfoEntries.ContainsKey(index)) + return sfoEntries[index].value; + else + return null; + } + set + { + if (sfoEntries.ContainsKey(index)) + { + SfoEntry sfoEnt = sfoEntries[index]; + sfoEnt.value = value; + + // update sz + sfoEnt.valueSize = getObjectSz(sfoEnt.value); + + if (sfoEnt.valueSize > sfoEnt.totalSize) + sfoEnt.totalSize = Convert.ToUInt32(MathUtil.CalculatePaddingAmount(Convert.ToInt32(sfoEnt.valueSize), sfoEnt.align)); + + // update type + sfoEnt.type = getPsfType(sfoEnt.value); + + sfoEntries[index] = sfoEnt; + } + else + { + UInt32 sz = getObjectSz(value); + int alg = MathUtil.CalculatePaddingAmount(Convert.ToInt32(sz), 4); + + AddKey(index, value, Convert.ToUInt32(sz + alg), 4); + } + } + } + + public void AddKey(string keyName, object value, UInt32 totalSize, byte align = 4) + { + SfoEntry ent = new SfoEntry(); + ent.keyName = keyName; + ent.type = getPsfType(value); + ent.valueSize = getObjectSz(value); + ent.totalSize = Convert.ToUInt32(totalSize + MathUtil.CalculatePaddingAmount(Convert.ToInt32(totalSize), align)); + ent.align = align; + ent.value = value; + sfoEntries[ent.keyName] = ent; + } + + public Sfo() + { + sfoEntries = new Dictionary(); + } + + + private static UInt32 getObjectSz(Object obj) + { + if (obj is Int32) return 4; + if (obj is UInt32) return 4; + if (obj is String) return Convert.ToUInt32((obj as String).Length + 1); + if (obj is Byte[]) return Convert.ToUInt32((obj as Byte[]).Length); + throw new Exception("Object is of unsupported type: " + obj.GetType()); + } + + private static byte getPsfType(Object obj) + { + if (obj is Int32 || obj is UInt32) return PSF_TYPE_VAL; + if (obj is String) return PSF_TYPE_STR; + if (obj is Byte[]) return PSF_TYPE_BIN; + throw new Exception("Object is of unsupported type: " + obj.GetType()); + } + + public byte[] WriteSfo(UInt32 version = 0x101, Byte align = 0x4) + { + using (MemoryStream sfoStream = new MemoryStream()) + { + WriteSfo(sfoStream, version, align); + byte[] sfoBytes = sfoStream.ToArray(); + return sfoBytes; + } + } + public void WriteSfo(Stream SfoStream, UInt32 version = 0x101, Byte align = 0x4) + { + using (MemoryStream sfoStream = new MemoryStream()) + { + StreamUtil sfoUtil = new StreamUtil(sfoStream); + + sfoUtil.WriteUInt32(SFO_MAGIC); + sfoUtil.WriteUInt32(version); + + sfoUtil.WriteUInt32(0xFFFFFFFF); // key offset + sfoUtil.WriteUInt32(0xFFFFFFFF); // value offset + // (will fill these in after the file is created) + + sfoUtil.WriteInt32(sfoEntries.Count); + + using (MemoryStream keyTable = new MemoryStream()) + { + StreamUtil keyUtils = new StreamUtil(keyTable); + using (MemoryStream valueTable = new MemoryStream()) + { + StreamUtil valueUtils = new StreamUtil(valueTable); + foreach (SfoEntry entry in sfoEntries.Values) + { + // write name + sfoUtil.WriteUInt16(Convert.ToUInt16(keyTable.Position)); + keyUtils.WriteCStr(entry.keyName); + + + + // write entry + + sfoUtil.WriteByte(align); // align + sfoUtil.WriteByte(entry.type); // type + sfoUtil.WriteUInt32(entry.valueSize); // valueSize + sfoUtil.WriteUInt32(entry.totalSize); // totalSize + + // write data + sfoUtil.WriteUInt32(Convert.ToUInt32(valueTable.Position)); // dataOffset + + switch (entry.type) + { + case PSF_TYPE_VAL: + valueUtils.WriteUInt32(Convert.ToUInt32(entry.value)); + valueUtils.WritePadding(0x00, Convert.ToInt32(entry.totalSize - entry.valueSize)); + break; + case PSF_TYPE_STR: + valueUtils.WriteStrWithPadding(entry.value as String, 0x00, Convert.ToInt32(entry.totalSize)); + break; + case PSF_TYPE_BIN: + valueUtils.WriteBytesWithPadding(entry.value as Byte[], 0x00, Convert.ToInt32(entry.totalSize)); + break; + } + } + + + keyUtils.AlignTo(0x00, align); + UInt32 keyOffset = Convert.ToUInt32(sfoStream.Position); + keyTable.Seek(0x00, SeekOrigin.Begin); + keyTable.CopyTo(sfoStream); + + UInt32 valueOffset = Convert.ToUInt32(sfoStream.Position); + valueTable.Seek(0x00, SeekOrigin.Begin); + valueTable.CopyTo(sfoStream); + + sfoStream.Seek(0x8, SeekOrigin.Begin); + sfoUtil.WriteUInt32(keyOffset); // key offset + sfoUtil.WriteUInt32(valueOffset); // value offset + } + } + + sfoStream.Seek(0x0, SeekOrigin.Begin); + sfoStream.CopyTo(SfoStream); + } + + } + + public static Sfo ReadSfo(Stream SfoStream) + { + Sfo sfoFile = new Sfo(); + StreamUtil DataUtils = new StreamUtil(SfoStream); + + // Read Sfo Header + UInt32 magic = DataUtils.ReadUInt32(); + UInt32 version = DataUtils.ReadUInt32(); + UInt32 keyOffset = DataUtils.ReadUInt32(); + UInt32 valueOffset = DataUtils.ReadUInt32(); + UInt32 count = DataUtils.ReadUInt32(); + + if (magic == SFO_MAGIC) //\x00PSF + { + for (int i = 0; i < count; i++) + { + SfoEntry entry = new SfoEntry(); + + UInt16 nameOffset = DataUtils.ReadUInt16(); + entry.align = DataUtils.ReadByte(); + entry.type = DataUtils.ReadByte(); + entry.valueSize = DataUtils.ReadUInt32(); + entry.totalSize = DataUtils.ReadUInt32(); + UInt32 dataOffset = DataUtils.ReadUInt32(); + + int keyLocation = Convert.ToInt32(keyOffset + nameOffset); + entry.keyName = DataUtils.ReadStringAt(keyLocation); + int valueLocation = Convert.ToInt32(valueOffset + dataOffset); + + + switch (entry.type) + { + case PSF_TYPE_STR: + entry.value = DataUtils.ReadStringAt(valueLocation); + break; + + case PSF_TYPE_VAL: + entry.value = DataUtils.ReadUInt32At(valueLocation); + break; + + case PSF_TYPE_BIN: + entry.value = DataUtils.ReadBytesAt(valueLocation, Convert.ToInt32(entry.valueSize)); + break; + } + + + sfoFile.sfoEntries[entry.keyName] = entry; + } + + } + else + { + throw new InvalidDataException("Sfo Magic is Invalid."); + } + + return sfoFile; + } + + public static Sfo ReadSfo(byte[] Sfo) + { + using (MemoryStream SfoStream = new MemoryStream(Sfo)) + { + return ReadSfo(SfoStream); + } + } + } +} diff --git a/CHOVY-TRANSFER/packages.config b/CHOVY-TRANSFER/packages.config deleted file mode 100644 index 5e69641..0000000 --- a/CHOVY-TRANSFER/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/CHOVY-TRANSFER/param.cs b/CHOVY-TRANSFER/param.cs deleted file mode 100644 index d20730d..0000000 --- a/CHOVY-TRANSFER/param.cs +++ /dev/null @@ -1,569 +0,0 @@ -/* Copyright (c) 2015 - 2018 TheDarkporgramer -* -* This was originally done by Jappi88 (Jappi88 at Gmail dot com) https://github.com/Jappi88 -* All modifications have been TheDarkporgramer (save sfo ext ext ) https://github.com/xXxTheDarkprogramerxXx -* -* This(software Is provided) 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications*, and to alter it and redistribute it -* freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledge in the product documentation is required. -* -* 2. Altered source versions must be plainly marked as such, and must not -* be misrepresented as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -* *Contact must be made to discuses permission and terms. -*/ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Linq; - -namespace Param_SFO -{ - public class PARAM_SFO - { - #region << Enums >> - public enum DataTypes : uint - { - PSN_Game = 18248, - GameData = 0x4744, - SaveData = 0x5344, - AppPhoto = 0x4150, - AppMusic = 0x414D, - AppVideo = 0x4156, - BroadCastVideo = 0x4256, - AppleTV = 4154, - WebTV = 5754, - CellBE = 0x4342, - Home = 0x484D, - StoreFronted = 0x5346, - HDDGame = 0x4847, - DiscGame = 0x4447, - AutoInstallRoot = 0x4152, - DiscPackage = 0x4450, - ExtraRoot = 0x5852, - VideoRoot = 0x5652, - ThemeRoot = 0x5452, - DiscMovie = 0x444D, - Game_Digital_Application = 0x4081AC0,//GD - PS4_Game_Application_Patch = 28775, - Additional_Content = 25441,//PSvita PS4 - GameContent = 25447,//PSVITA - Blu_Ray_Disc = 25698,//PS4 - None - } - - public enum FMT : ushort - { - UTF_8 = 0x0004, - ASCII = 0x0402, - Utf8Null = 0x0204, - UINT32 = 0x0404, - } - - #endregion << Enums >> - - #region << Vars>> - public List Tables { get; set; } - - #endregion << Vars>> - - #region << Example Of Calling Functions >> - //ypu can use this as SFO.Atribute - public string Attribute - { - get - { - if (Tables == null) - return ""; - foreach (Table t in Tables) - { - if (t.Name == "ATTRIBUTE") - return t.Value; - } - return ""; - } - } - - public DataTypes DataType - { - get - { - if (Tables == null) - return DataTypes.None; - foreach (Table t in Tables) - if (t.Name == "CATEGORY") - return ((DataTypes)BitConverter.ToUInt16(Encoding.UTF8.GetBytes(t.Value), 0)); - return DataTypes.None; - } - } - - public string APP_VER - { - get - { - if (Tables == null) - return ""; - foreach (Table t in Tables) - { - if (t.Name == "APP_VER") - return t.Value; - } - return ""; - } - } - - public string Detail - { - get - { - if (Tables == null) - return ""; - foreach (Table t in Tables) - if (t.Name == "DETAIL") - return t.Value; - return ""; - } - } - - public string ContentID - { - get - { - if (Tables == null) - return ""; - foreach (Table t in Tables) - if (t.Name == "CONTENT_ID") - return t.Value; - return ""; - } - } - - public string GetValue(string tagName) - { - foreach (Table t in Tables) - if (t.Name == tagName) - return t.Value; - return ""; - } - public string TITLEID - { - get - { - if (Tables == null) - return ""; - foreach (Table t in Tables) - if (t.Name == "TITLE_ID") - return t.Value; - return ""; - } - } - - public string TitleID - { - get - { - string name = TITLEID; - if (name == "") - return ""; - return name.Split('-')[0]; - } - } - - public string Title - { - get - { - if (Tables == null) - return ""; - foreach (Table t in Tables) - if (t.Name == "TITLE") - return t.Value; - return ""; - } - } - - public string Category - { - get - { - if (Tables == null) - return ""; - foreach (Table t in Tables) - if (t.Name == "CATEGORY") - return t.Value; - return ""; - } - } - - public enum Playstation - { - ps3 = 0, - psvita = 1, - ps4 = 2, - psp = 3, - unknown = 4,//there will be a time i no longer support the scene this will be for ps5+ most probabbly - } - - public Playstation PlaystationVersion - { - get - { - if (Tables == null) - return Playstation.unknown; - foreach (Table t in Tables) - { - if (t.Name == "PS3_SYSTEM_VER") - return Playstation.ps3;//this is the unique offset for ps3 - if (t.Name == "PSP2_SYSTEM_VER") - { - return Playstation.psvita;//this is the only flag that tells us its a psvita - } - if (t.Name == "PSP_SYSTEM_VER") - { - return Playstation.psp;//this is how we know its a psp - } - if (t.Name == "SYSTEM_VER")//i believe this to be only ps4 - { - return Playstation.ps4; - } - } - return Playstation.unknown; - } - } - - - #endregion << Example Of Calling Functions >> - - #region Param.SFO Struct - - public struct Header - { - public static byte[] Magic = { 0, 0x50, 0x53, 0x46 }; - public static byte[] version = { 01, 01, 0, 0 }; - public static uint KeyTableStart = 0; - public static uint DataTableStart = 0; - public static uint IndexTableEntries = 0; - - private static byte[] Buffer - { - get - { - var header = new byte[20]; - Array.Copy(Magic, 0, header, 0, 4); - Array.Copy(version, 0, header, 4, 4); - Array.Copy(BitConverter.GetBytes(KeyTableStart), 0, header, 8, 4); - Array.Copy(BitConverter.GetBytes(DataTableStart), 0, header, 12, 4); - Array.Copy(BitConverter.GetBytes(IndexTableEntries), 0, header, 16, 4); - return header; - } - } - - public static void Read(BinaryReader input) - { - input.BaseStream.Seek(0, SeekOrigin.Begin); - input.Read(Magic, 0, 4); - input.Read(version, 0, 4); - KeyTableStart = input.ReadUInt32(); - DataTableStart = input.ReadUInt32(); - IndexTableEntries = input.ReadUInt32(); - } - - } - [Serializable] - public struct Table : IComparable - { - public index_table Indextable; - public string Name; - public string Value; - public int index; - - public byte[] NameBuffer - { - get - { - var buffer = new byte[Name.Length + 1]; - Array.Copy(Encoding.UTF8.GetBytes(Name), 0, buffer, 0, Encoding.UTF8.GetBytes(Name).Length); - return buffer; - } - } - - public byte[] ValueBuffer - { - get - { - byte[] buffer; - switch (Indextable.param_data_fmt) - { - case FMT.ASCII: - buffer = new byte[Indextable.param_data_max_len]; - Array.Copy(Encoding.ASCII.GetBytes(Value), 0, buffer, 0, Encoding.UTF8.GetBytes(Value).Length); - return buffer; - case FMT.UINT32: - return BitConverter.GetBytes(uint.Parse(Value)); - case FMT.UTF_8: - buffer = new byte[Indextable.param_data_max_len]; - Array.Copy(Encoding.UTF8.GetBytes(Value), 0, buffer, 0, Encoding.UTF8.GetBytes(Value).Length); - return buffer; - case FMT.Utf8Null: - buffer = new byte[Indextable.param_data_max_len]; - Array.Copy(Encoding.UTF8.GetBytes(Value), 0, buffer, 0, Encoding.UTF8.GetBytes(Value).Length);/*write the length of the array*/ - return buffer; - default: - return null; - } - } - } - - public int CompareTo(object obj) - { - throw new NotImplementedException(); - } - } - [Serializable] - public struct index_table - { - public FMT param_data_fmt; /* param_data data type */ - public uint param_data_len; /* param_data used bytes */ - public uint param_data_max_len; /* param_data total reserved bytes */ - public uint param_data_offset; /* param_data offset (relative to start offset of data_table) */ - public ushort param_key_offset; /* param_key offset (relative to start offset of key_table) */ - - - private byte[] Buffer - { - get - { - var data = new byte[16]; - Array.Copy(BitConverter.GetBytes(param_key_offset), 0, data, 0, 2); - Array.Copy(BitConverter.GetBytes(((ushort)param_data_fmt)), 0, data, 2, 2); - Array.Copy(BitConverter.GetBytes(param_data_len), 0, data, 4, 4); - Array.Copy(BitConverter.GetBytes(param_data_max_len), 0, data, 8, 4); - Array.Copy(BitConverter.GetBytes(param_data_offset), 0, data, 12, 4); - return data; - } - } - - public void Read(BinaryReader input) - { - param_key_offset = input.ReadUInt16(); - param_data_fmt = (FMT)input.ReadUInt16(); - param_data_len = input.ReadUInt32(); - param_data_max_len = input.ReadUInt32(); - param_data_offset = input.ReadUInt32(); - } - } - - [Serializable] - private enum DATA_TYPE : byte - { - BinaryData = 0, - Utf8Text = 2, - Si32Integer = 4 - } - - #endregion Param.SFO Struct - - #region << Methods >> - - - public PARAM_SFO() - { - - } - - public PARAM_SFO(string filepath) - { - Init(new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read)); - } - - public PARAM_SFO(byte[] inputdata) - { - Init(new MemoryStream(inputdata)); - } - - public PARAM_SFO(Stream input) - { - Init(input); - } - - - /// - /// This is the SaveSFO Function for PS3/PS4/PSVita/And PSP no longer needed for Sony's CMD - /// - /// SFO That has been opened - /// Save Location - public void SaveSFO(PARAM_SFO psfo, string filename) - { - //we start by opening the stream to the file - using (var stream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read)) - { - if (!stream.CanSeek) - throw new ArgumentException("Stream must be seekable");//throw this error we cant seek the stream - - var utf8 = new UTF8Encoding(false);//encoding - using (var writer = new BinaryWriter(stream, utf8))//start binary reader - { - - #region << Header Info (DevWiki) >> - /* - Header - * 0x00 0x04 magic PSF - 0x04 0x04 version 01 01 00 00 1.01 - 0x08 0x04 key_table_start 24 00 00 00 Absolute start offset of key_table = 0x24 - 0x0C 0x04 data_table_start 30 00 00 00 Absolute start offset of data_table = 0x30 - 0x10 0x04 tables_entries 01 00 00 00 Number of entries in index_table, key_table, and data_table = 1 - */ - - #endregion <
> - - //so lets start writing the info - writer.Write(Header.Magic);//write magic "\0PSF" - writer.Write(Header.version);//write version info this is mayjor and minor (01 01 00 00 1.01) - Header.KeyTableStart = 0x14 + Header.IndexTableEntries * 0x10;/*we can write all this lovely info from the tables back*/ - writer.Write(Header.KeyTableStart); - - Header.DataTableStart = Convert.ToUInt32(Header.KeyTableStart + Tables.Sum(i => i.Name.Length + 1));//needs to be Uint - if (Header.DataTableStart % 4 != 0) - Header.DataTableStart = (Header.DataTableStart / 4 + 1) * 4; - writer.Write(Header.DataTableStart); - Header.IndexTableEntries = Convert.ToUInt32(Tables.Count); - writer.Write(Header.IndexTableEntries); - - int lastKeyOffset = Convert.ToInt32(Header.KeyTableStart); - int lastValueOffset = Convert.ToInt32(Header.DataTableStart); - for (var i = 0; i < Tables.Count; i++) - { - var entry = Tables[i]; - - writer.BaseStream.Seek(0x14 + i * 0x10, SeekOrigin.Begin); - writer.Write((ushort)(lastKeyOffset - Header.KeyTableStart)); - - - writer.Write((ushort)entry.Indextable.param_data_fmt); - - writer.Write(entry.Indextable.param_data_len); - writer.Write(entry.Indextable.param_data_max_len); - writer.Write(lastValueOffset - Header.DataTableStart); - - writer.BaseStream.Seek(lastKeyOffset, SeekOrigin.Begin); - writer.Write(utf8.GetBytes(entry.Name)); - writer.Write((byte)0); - lastKeyOffset = (int)writer.BaseStream.Position; - - writer.BaseStream.Seek(lastValueOffset, SeekOrigin.Begin); - writer.Write(entry.ValueBuffer); - lastValueOffset = (int)writer.BaseStream.Position; - } - - //I'm doing this to just rewrite the first item (Some Cleanup will be needed) - //Or maybe not as when I checked this gives a 1 - 1 match with how the Sony tool works - //we need to rewrite that first item (PS4/PS3/PSV should be APP-VER) - lastKeyOffset = Convert.ToInt32(Header.KeyTableStart); - lastValueOffset = Convert.ToInt32(Header.DataTableStart); - - var tableentry = Tables[0]; - - writer.BaseStream.Seek(lastKeyOffset, SeekOrigin.Begin); - writer.Write(utf8.GetBytes(tableentry.Name)); - writer.Write((byte)0); - lastKeyOffset = (int)writer.BaseStream.Position; - - } - } - - } - - private string ReadValue(BinaryReader br, index_table table) - { - br.BaseStream.Position = ((Header.DataTableStart) + table.param_data_offset); - switch (table.param_data_fmt) - { - case FMT.ASCII: - //return Encoding.GetEncoding(1252).GetString(br.ReadBytes((int) table.param_data_max_len)).Replace("\0", ""); - return Encoding.UTF8.GetString(br.ReadBytes((int)table.param_data_max_len)).Replace("\0", ""); - case FMT.UINT32: - return br.ReadUInt32().ToString(); - case FMT.UTF_8: - return Encoding.UTF8.GetString(br.ReadBytes((int)table.param_data_max_len)).Replace("\0", ""); - case FMT.Utf8Null: - return Encoding.UTF8.GetString(br.ReadBytes((int)table.param_data_max_len)).Replace("\0", ""); - default: - return null; - } - } - - private string ReadValueSpecialChars(BinaryReader br, index_table table) - { - br.BaseStream.Position = ((Header.DataTableStart) + table.param_data_offset); - switch (table.param_data_fmt) - { - case FMT.ASCII: - return Encoding.UTF8.GetString(br.ReadBytes((int)table.param_data_max_len)).Replace("\0", ""); - case FMT.UINT32: - return br.ReadUInt32().ToString(); - case FMT.UTF_8: - return Encoding.UTF8.GetString(br.ReadBytes((int)table.param_data_max_len)).Replace("\0", ""); - default: - return null; - } - } - - private string ReadName(BinaryReader br, index_table table) - { - br.BaseStream.Position = (Header.KeyTableStart + table.param_key_offset); - string name = ""; - while (((byte)br.PeekChar()) != 0) - name += br.ReadChar(); - br.BaseStream.Position++; - return name; - } - - /// - /// Start Reading the Parameter file - /// - /// Input Stream - private void Init(Stream input) - { - using (var br = new BinaryReader(input)) - { - Header.Read(br); - var tables = new List(); - for (int i = 0; i < Header.IndexTableEntries; i++) - { - var t = new index_table(); - t.Read(br); - tables.Add(t); - } - var xtables = new List
(); - int count = 0; - foreach (index_table t in tables) - { - var x = new Table(); - x.index = count; - x.Indextable = t; - x.Name = ReadName(br, t); - x.Value = ReadValue(br, t); - count++; - xtables.Add(x); - } - Tables = xtables; - br.Close(); - } - } - - - #endregion << Methods >> - - } -} \ No newline at end of file diff --git a/LiLib/LiLib.csproj b/LiLib/LiLib.csproj new file mode 100644 index 0000000..132c02c --- /dev/null +++ b/LiLib/LiLib.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/LiLib/MathUtil.cs b/LiLib/MathUtil.cs new file mode 100644 index 0000000..2f1783e --- /dev/null +++ b/LiLib/MathUtil.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Li.Utilities +{ + public static class MathUtil + { + public static int CalculateDifference(int val1, int val2) + { + int smaller = Convert.ToInt32(Math.Min(val1, val2)); + int larger = Convert.ToInt32(Math.Max(val1, val2)); + + return larger - smaller; + } + + public static byte[] StringToByteArray(string hex) + { + return Enumerable.Range(0, hex.Length).Where(x => x % 2 == 0).Select(x => Convert.ToByte(hex.Substring(x, 2), 16)).ToArray(); + } + + public static int CalculatePaddingAmount(int total, int alignTo) + { + int remainder = total % alignTo; + int padAmt = alignTo - (remainder); + if ((remainder) == 0) return 0; + return padAmt; + } + } +} diff --git a/LiLib/Progress/ProgressInfo.cs b/LiLib/Progress/ProgressInfo.cs new file mode 100644 index 0000000..74e27c7 --- /dev/null +++ b/LiLib/Progress/ProgressInfo.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Li.Progress +{ + public class ProgressInfo + { + private int totalDone; + private int totalRemain; + private string currentlyDoing; + + public int Done + { + get + { + return totalDone; + } + } + + public int Remain + { + get + { + return totalRemain; + } + } + + public string CurrentProcess + { + get + { + return currentlyDoing; + } + } + + public double Progress + { + get + { + return Convert.ToDouble(totalDone) / Convert.ToDouble(totalRemain) * 100.0; + } + } + + public int ProgressInt + { + get + { + return Convert.ToInt32(Math.Floor(Progress)); + } + } + + internal ProgressInfo(int done, int remain, string currentProcess) + { + totalDone = done; + totalRemain = remain; + currentlyDoing = currentProcess; + } + } +} diff --git a/LiLib/Progress/ProgressTracker.cs b/LiLib/Progress/ProgressTracker.cs new file mode 100644 index 0000000..a69bcee --- /dev/null +++ b/LiLib/Progress/ProgressTracker.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Li.Progress +{ + public class ProgressTracker + { + private List> progressCallbacks = new List>(); + + public void RegisterCallback(Action cb) + { + progressCallbacks.Add(cb); + } + + protected void copyToProgress(Stream src, Stream dst, string msg) + { + src.Seek(0, SeekOrigin.Begin); + byte[] readBuffer = new byte[0x30000]; + while (src.Position < src.Length) + { + int readAmt = src.Read(readBuffer, 0x00, readBuffer.Length); + dst.Write(readBuffer, 0x00, readAmt); + + updateProgress(Convert.ToInt32(src.Position), Convert.ToInt32(src.Length), msg); + } + } + + protected void updateProgress(int done, int remain, string what) + { + ProgressInfo inf = new ProgressInfo(done, remain, what); + foreach (Action cb in progressCallbacks) + cb(inf); + } + } +} diff --git a/LiLib/StreamUtil.cs b/LiLib/StreamUtil.cs new file mode 100644 index 0000000..5fc228e --- /dev/null +++ b/LiLib/StreamUtil.cs @@ -0,0 +1,204 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Li.Utilities +{ + public class StreamUtil + { + private Stream s; + public StreamUtil(Stream s) + { + this.s = s; + } + public string ReadStrLen(int len) + { + return Encoding.UTF8.GetString(ReadBytes(len)); + } + public string ReadCDStr(int len) + { + return ReadStrLen(len).Trim(' '); + } + public string ReadCStr() + { + using (MemoryStream ms = new MemoryStream()) + { + while (true) + { + byte c = (byte)s.ReadByte(); + if (c == 0) + break; + ms.WriteByte(c); + } + return Encoding.UTF8.GetString(ms.ToArray()); + } + } + public UInt32 ReadUInt32At(int location) + { + long oldPos = s.Position; + s.Seek(location, SeekOrigin.Begin); + UInt32 outp = ReadUInt32(); + s.Seek(oldPos, SeekOrigin.Begin); + return outp; + } + + public Int32 ReadInt32At(int location) + { + long oldPos = s.Position; + s.Seek(location, SeekOrigin.Begin); + Int32 outp = ReadInt32(); + s.Seek(oldPos, SeekOrigin.Begin); + return outp; + } + + public byte[] ReadBytesAt(int location, int length) + { + long oldPos = s.Position; + s.Seek(location, SeekOrigin.Begin); + byte[] work_buf = ReadBytes(length); + s.Seek(oldPos, SeekOrigin.Begin); + return work_buf; + } + + public string ReadStringAt(int location) + { + long oldPos = s.Position; + s.Seek(location, SeekOrigin.Begin); + string outp = ReadCStr(); + s.Seek(oldPos, SeekOrigin.Begin); + return outp; + } + public byte ReadByte() + { + return (byte)s.ReadByte(); + } + public byte[] ReadBytes(int len) + { + byte[] data = new byte[len]; + s.Read(data, 0x00, len); + return data; + } + public UInt16 ReadUInt16() + { + byte[] vbytes = ReadBytes(0x2); + return BitConverter.ToUInt16(vbytes); + } + public Int16 ReadInt16() + { + byte[] vbytes = ReadBytes(0x2); + return BitConverter.ToInt16(vbytes); + } + public UInt32 ReadUInt32() + { + byte[] vbytes = ReadBytes(0x4); + return BitConverter.ToUInt32(vbytes); + } + public Int32 ReadInt32() + { + byte[] vbytes = ReadBytes(0x4); + return BitConverter.ToInt32(vbytes); + } + public void WriteBytesWithPadding(byte[] data, byte b, int len) + { + if (len < data.Length) + { + s.Write(data, 0, len); + return; + } + else + { + WriteBytes(data); + WritePadding(b, (len - data.Length)); + } + } + public void WriteStrWithPadding(string str, byte b, int len) + { + WriteBytesWithPadding(Encoding.UTF8.GetBytes(str), b, len); + } + public void WriteUInt64(UInt64 v) + { + WriteBytes(BitConverter.GetBytes(v)); + } + public void WriteInt64(Int64 v) + { + WriteBytes(BitConverter.GetBytes(v)); + } + public void WriteUInt16(UInt16 v) + { + WriteBytes(BitConverter.GetBytes(v)); + } + public void WriteInt16(Int16 v) + { + WriteBytes(BitConverter.GetBytes(v)); + } + + public void WriteUInt32(UInt32 v) + { + WriteBytes(BitConverter.GetBytes(v)); + } + public void WriteInt32BE(Int32 v) + { + WriteBytes(BitConverter.GetBytes(v).Reverse().ToArray()); + } + public void WriteInt32At(Int32 v, long location) + { + long oldPos = s.Position; + s.Seek(location, SeekOrigin.Begin); + WriteInt32(v); + s.Seek(oldPos, SeekOrigin.Begin); + } + public void WriteUInt32At(UInt32 v, long location) + { + long oldPos = s.Position; + s.Seek(location, SeekOrigin.Begin); + WriteUInt32(v); + s.Seek(oldPos, SeekOrigin.Begin); + } + + public void WriteInt32(Int32 v) + { + WriteBytes(BitConverter.GetBytes(v)); + } + public void WriteCStr(string str) + { + WriteStr(str); + WriteByte(0x00); + } + public void WriteStr(string str) + { + WriteBytes(Encoding.UTF8.GetBytes(str)); + } + + public void WritePadding(byte b, int len) + { + if (len < 0) return; + for(int i = 0; i < len; i++) + { + WriteByte(b); + } + } + + public void AlignTo(byte padByte, int align) + { + int padAmt = MathUtil.CalculatePaddingAmount(Convert.ToInt32(s.Position), align); + + this.WritePadding(padByte, padAmt); + } + public void PadUntil(byte b, int len) + { + int remain = Convert.ToInt32(len - s.Length); + WritePadding(b, remain); + } + public void WriteBytes(byte[] bytes) + { + s.Write(bytes, 0, bytes.Length); + } + public void WriteByte(byte b) + { + s.WriteByte(b); + } + + } +} diff --git a/PspCrypto/AMCTRL.cs b/PspCrypto/AMCTRL.cs new file mode 100644 index 0000000..36ac756 --- /dev/null +++ b/PspCrypto/AMCTRL.cs @@ -0,0 +1,710 @@ +using System; +using System.Runtime.InteropServices; + +namespace PspCrypto +{ + public class AMCTRL + { + static readonly Memory kirk_buf = new byte[0x0814]; + static readonly Memory kirk_buf2 = new byte[0x8014]; + + // AMCTRL keys. + static readonly byte[] amctrl_key1 = { 0xE3, 0x50, 0xED, 0x1D, 0x91, 0x0A, 0x1F, 0xD0, 0x29, 0xBB, 0x1C, 0x3E, 0xF3, 0x40, 0x77, 0xFB }; + static readonly byte[] amctrl_key2 = { 0x13, 0x5F, 0xA4, 0x7C, 0xAB, 0x39, 0x5B, 0xA4, 0x76, 0xB8, 0xCC, 0xA9, 0x8F, 0x3A, 0x04, 0x45 }; + static readonly byte[] amctrl_key3 = { 0x67, 0x8D, 0x7F, 0xA3, 0x2A, 0x9C, 0xA0, 0xD1, 0x50, 0x8A, 0xD8, 0x38, 0x5E, 0x4B, 0x01, 0x7E }; + + public unsafe struct MAC_KEY + { + public int type; + private fixed byte _key[16]; + + public Span key + { + get + { + fixed (byte* ptr = _key) + { + return new Span(ptr, 16); + } + } + } + private fixed byte _pad[16]; + + public Span pad + { + get + { + fixed (byte* ptr = _pad) + { + return new Span(ptr, 16); + } + } + } + public int pad_size; + } + + public unsafe struct CIPHER_KEY + { + public int type; + public int seed; + fixed byte _key[16]; + + public Span key + { + get + { + fixed (byte* ptr = _key) + { + return new Span(ptr, 16); + } + } + } + } + + /* + * KIRK wrapper functions. + */ + static int Kirk4(Span buf, int size, int type) + { + int retv; + ref var hdr = ref MemoryMarshal.AsRef(buf); + hdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC; + hdr.keyseed = type; + hdr.data_size = size; + + retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_ENCRYPT_IV_0); + + if (retv != 0) + return -2142174447; // 0x80510311; + + return 0; + } + + static int Kirk5(Span buf, int size) + { + int retv; + ref var hdr = ref MemoryMarshal.AsRef(buf); + hdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC; + hdr.keyseed = 0x0100; + hdr.data_size = size; + + retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_ENCRYPT_IV_FUSE); + + if (retv != 0) + return -2142174446; // 0x80510312; + + return 0; + } + + static int Kirk7(Span buf, int size, int type) + { + int retv; + ref var hdr = ref MemoryMarshal.AsRef(buf); + hdr.mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC; + hdr.keyseed = type; + hdr.data_size = size; + + retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_DECRYPT_IV_0); + + if (retv != 0) + return -2142174447; // 0x80510311; + + return 0; + } + + static int Kirk8(Span buf, int size) + { + int retv; + ref var hdr = ref MemoryMarshal.AsRef(buf); + hdr.mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC; + hdr.keyseed = 0x0100; + hdr.data_size = size; + + retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_DECRYPT_IV_FUSE); + + if (retv != 0) + return -2142174446; // 0x80510312; + + return 0; + } + + static int Kirk14(Span buf) + { + int retv; + + retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, 0x14, null, 0, KIRKEngine.KIRK_CMD_PRNG); + + if (retv != 0) + return -2142174443; // 0x80510315; + + return 0; + } + + static int encrypt_buf(Span buf, int size, Span key, int key_type) + { + int i, retv; + + for (i = 0; i < 16; i++) + { + buf[0x14 + i] ^= key[i]; + } + + unsafe + { + fixed (byte* ptr = buf) + { + + } + } + + retv = Kirk4(buf, size, key_type); + + if (retv != 0) + return retv; + + buf.Slice(size + 4, 16).CopyTo(key); + + return 0; + } + + static int decrypt_buf(Span buf, int size, Span key, int key_type) + { + int i, retv; + Span tmp = stackalloc byte[16]; + + buf.Slice(size + 0x14 - 16, 16).CopyTo(tmp); + + retv = Kirk7(buf, size, key_type); + + if (retv != 0) + return retv; + + for (i = 0; i < 16; i++) + { + buf[i] ^= key[i]; + } + + tmp.CopyTo(key); + + return 0; + } + + static int cipher_buf(Span kbuf, Span dbuf, int size, ref CIPHER_KEY ckey) + { + int i, retv; + Span tmp1 = stackalloc byte[16], tmp2 = stackalloc byte[16]; + + ckey.key.CopyTo(kbuf[0x14..]); + + for (i = 0; i < 16; i++) + { + kbuf[0x14 + i] ^= amctrl_key3[i]; + } + + if (ckey.type == 2) + retv = Kirk8(kbuf, 16); + else + retv = Kirk7(kbuf, 16, 0x39); + + if (retv != 0) + return retv; + + for (i = 0; i < 16; i++) + { + kbuf[i] ^= amctrl_key2[i]; + } + + kbuf.Slice(0, 0x10).CopyTo(tmp2); + + if (ckey.seed == 1) + { + tmp1.Fill(0); + } + else + { + tmp2.CopyTo(tmp1); + var tmp = ckey.seed - 1; + MemoryMarshal.Write(tmp1[0x0c..], ref tmp); + } + + for (i = 0; i < size; i += 16) + { + tmp2[..12].CopyTo(kbuf[(0x14 + i)..]); + MemoryMarshal.Write(kbuf[(0x14 + i + 12)..], ref ckey.seed); + ckey.seed += 1; + } + + retv = decrypt_buf(kbuf, size, tmp1, 0x63); + + if (retv != 0) + return retv; + + for (i = 0; i < size; i++) + { + dbuf[i] ^= kbuf[i]; + } + + return 0; + } + + public static int sceDrmBBMacInit(Span mkey, int type) + { + ref MAC_KEY macKey = ref MemoryMarshal.AsRef(mkey); + macKey.type = type; + macKey.key.Clear(); + macKey.pad.Clear(); + return 0; + } + + public static int sceDrmBBMacUpdate(Span mkey, ReadOnlySpan buf, int size) + { + ref MAC_KEY macKey = ref MemoryMarshal.AsRef(mkey); + + int retv = 0, ksize, p, type; + int kbuf; + + if (macKey.pad_size > 16) + { + retv = -2142174462; // 0x80510302 + return retv; + } + + if (macKey.pad_size + size <= 16) + { + buf[..size].CopyTo(macKey.pad[macKey.pad_size..]); + macKey.pad_size += size; + retv = 0; + } + else + { + kbuf = 0x14; + macKey.pad[..macKey.pad_size].CopyTo(kirk_buf[0x14..].Span); + + p = macKey.pad_size; + + macKey.pad_size += size; + macKey.pad_size &= 0x0f; + if (macKey.pad_size == 0) + macKey.pad_size = 16; + + size -= macKey.pad_size; + buf.Slice(size, macKey.pad_size).CopyTo(macKey.pad); + + type = (macKey.type == 2) ? 0x3A : 0x38; + + int offset = 0; + + while (size > 0) + { + ksize = (size + p >= 0x0800) ? 0x0800 : size + p; + buf.Slice(offset, ksize - p).CopyTo(kirk_buf[(kbuf + p)..].Span); + retv = encrypt_buf(kirk_buf.Span, ksize, macKey.key, type); + + if (retv != 0) + return retv; + + size -= (ksize - p); + offset += ksize - p; + p = 0; + } + } + + return retv; + } + + public static int sceDrmBBMacUpdate2(Span mkey, Span buf, int size) + { + ref MAC_KEY macKey = ref MemoryMarshal.AsRef(mkey); + + int retv = 0, ksize, p, type; + int kbuf; + + if (macKey.pad_size > 16) + { + retv = -2142174462; // 0x80510302 + return retv; + } + + if (macKey.pad_size + size <= 16) + { + buf.Slice(0, size).CopyTo(macKey.pad.Slice(macKey.pad_size)); + macKey.pad_size += size; + retv = 0; + } + else + { + kbuf = 0x14; + macKey.pad.Slice(0, macKey.pad_size).CopyTo(kirk_buf.Slice(0x14).Span); + + p = macKey.pad_size; + + macKey.pad_size += (size & 0x0f); + //mkey.pad_size &= 0x0f; + if (macKey.pad_size == 0) + macKey.pad_size = 16; + + size -= macKey.pad_size; + buf.Slice(size, macKey.pad_size).CopyTo(macKey.pad); + + type = (macKey.type == 2) ? 0x3A : 0x38; + + int idx = 0; + + ksize = size + p; + int offset = 0; + if (size + p >= 0x8001) + { + ; + buf.Slice(offset, 0x8000 - p).CopyTo(kirk_buf2.Slice(kbuf + p).Span); + retv = encrypt_buf(kirk_buf2.Span, 0x8000, macKey.key, type); + idx = 0x8000 - p; + var fix = -p; + while (retv == 0) + { + if (size <= 0x10000 - fix) + { + p = 0; + ksize = size; + break; + } + buf.Slice(offset + idx, 0x8000).CopyTo(kirk_buf2.Slice(kbuf).Span); + retv = encrypt_buf(kirk_buf2.Span, 0x8000, macKey.key, type); + fix = idx; + idx += 0x8000; + } + + if (retv != 0) + { + return retv; + } + } + buf.Slice(offset + idx, size - idx).CopyTo(kirk_buf2.Slice(kbuf + p).Span); + retv = encrypt_buf(kirk_buf2.Span, ksize - idx, macKey.key, type); + } + + return retv; + } + + public static int sceDrmBBMacFinal(Span mkey, Span buf, ReadOnlySpan vkey) + { + ref MAC_KEY macKey = ref MemoryMarshal.AsRef(mkey); + int i, retv, code; + Span tmp = stackalloc byte[16], tmp1 = stackalloc byte[16]; + int kbuf; + uint t0, v0, v1; + + if (macKey.pad_size > 16) + return -2142174462; //0x80510302; + + code = (macKey.type == 2) ? 0x3A : 0x38; + kbuf = 0x14; + + kirk_buf.Slice(kbuf, 16).Span.Fill(0); + retv = Kirk4(kirk_buf.Span, 16, code); + if (retv != 0) + { + return retv; + } + + kirk_buf.Slice(kbuf, 16).Span.CopyTo(tmp); + + t0 = ((tmp[0] & 0x80) > 0) ? 0x87u : 0; + for (i = 0; i < 15; i++) + { + v1 = tmp[i + 0]; + v0 = tmp[i + 1]; + v1 <<= 1; + v0 >>= 7; + v0 |= v1; + tmp[i + 0] = (byte)v0; + } + v0 = tmp[15]; + v0 <<= 1; + v0 ^= t0; + tmp[15] = (byte)v0; + + if (macKey.pad_size < 16) + { + t0 = ((tmp[0] & 0x80) > 0) ? 0x87u : 0; + for (i = 0; i < 15; i++) + { + v1 = tmp[i + 0]; + v0 = tmp[i + 1]; + v1 <<= 1; + v0 >>= 7; + v0 |= v1; + tmp[i + 0] = (byte)v0; + } + v0 = tmp[15]; + v0 <<= 1; + v0 ^= t0; + tmp[15] = (byte)v0; + + macKey.pad[macKey.pad_size] = 0x80; + if (macKey.pad_size + 1 < 16) + { + macKey.pad.Slice(macKey.pad_size + 1, 16 - macKey.pad_size - 1).Fill(0); + } + } + + for (i = 0; i < 16; i++) + { + macKey.pad[i] ^= tmp[i]; + } + + macKey.pad.CopyTo(kirk_buf.Slice(kbuf).Span); + macKey.key.CopyTo(tmp1); + + retv = encrypt_buf(kirk_buf.Span, 0x10, tmp1, code); + + if (retv != 0) + return retv; + + for (i = 0; i < 0x10; i++) + { + tmp1[i] ^= amctrl_key1[i]; + } + + if (macKey.type == 2) + { + tmp1.CopyTo(kirk_buf.Slice(kbuf).Span); + + retv = Kirk5(kirk_buf.Span, 0x10); + + if (retv != 0) + return retv; + + retv = Kirk4(kirk_buf.Span, 0x10, code); + + if (retv != 0) + return retv; + + kirk_buf.Slice(kbuf, 16).Span.CopyTo(tmp1); + } + + if (vkey != null) + { + for (i = 0; i < 0x10; i++) + { + tmp1[i] ^= vkey[i]; + } + tmp1.CopyTo(kirk_buf.Slice(kbuf).Span); + + retv = Kirk4(kirk_buf.Span, 0x10, code); + + if (retv != 0) + return retv; + + kirk_buf.Slice(kbuf, 16).Span.CopyTo(tmp1); + } + + tmp1.CopyTo(buf); + + macKey.key.Fill(0); + macKey.pad.Fill(0); + + macKey.pad_size = 0; + macKey.type = 0; + retv = 0; + + return retv; + } + + + + public static int bbmac_getkey(Span mkey, ReadOnlySpan bbmac, Span vkey) + { + int i, retv, type, code; + Span tmp = stackalloc byte[16], tmp1 = stackalloc byte[16]; + int kbuf; + ref MAC_KEY macKey = ref MemoryMarshal.AsRef(mkey); + + type = macKey.type; + retv = sceDrmBBMacFinal(mkey, tmp, null); + + if (retv != 0) + return retv; + + kbuf = 0x14; + + if (type == 3) + { + bbmac[..0x10].CopyTo(kirk_buf[kbuf..].Span); + Kirk7(kirk_buf.Span, 0x10, 0x63); + } + else + { + bbmac[..0x10].CopyTo(kirk_buf.Span); + } + + kirk_buf[..16].Span.CopyTo(tmp1); + tmp1.CopyTo(kirk_buf[kbuf..].Span); + + code = (type == 2) ? 0x3A : 0x38; + Kirk7(kirk_buf.Span, 0x10, code); + + for (i = 0; i < 0x10; i++) + { + vkey[i] = (byte)(tmp[i] ^ kirk_buf.Span[i]); + } + + return 0; + } + + public static int sceDrmBBMacFinal2(Span mkey, ReadOnlySpan hash, ReadOnlySpan vkey) + { + int retv, type; + byte[] tmp = new byte[16]; + int kbuf; + ref MAC_KEY macKey = ref MemoryMarshal.AsRef(mkey); + + type = macKey.type; + retv = sceDrmBBMacFinal(mkey, tmp, vkey); + if (retv != 0) + return retv; + + kbuf = 0x14; + + if (type == 3) + { + hash[..0x10].CopyTo(kirk_buf[kbuf..].Span); + Kirk7(kirk_buf.Span, 0x10, 0x63); + } + else + { + hash[..0x10].CopyTo(kirk_buf.Span); + } + + retv = 0; + if (!kirk_buf.Span[..0x10].SequenceEqual(tmp)) + { + retv = -2142174464; //0x80510300; + } + //for (i = 0; i < 0x10; i++) + //{ + // if (kirk_buf.Span[i] != tmp[i]) + // { + // retv = -2142174464; //0x80510300; + // break; + // } + //} + + return retv; + } + + + /* + BBCipher functions. + */ + public static int sceDrmBBCipherInit(out CIPHER_KEY ckey, int type, int mode, ReadOnlySpan header_key, ReadOnlySpan version_key, int seed) + { + int i, retv; + int kbuf; + + kbuf = 0x14; + ckey = new CIPHER_KEY { type = type }; + if (mode == 2) + { + ckey.seed = seed + 1; + for (i = 0; i < 16; i++) + { + ckey.key[i] = header_key[i]; + } + if (version_key != null) + { + for (i = 0; i < 16; i++) + { + ckey.key[i] ^= version_key[i]; + } + } + retv = 0; + } + else if (mode == 1) + { + ckey.seed = 1; + retv = Kirk14(kirk_buf.Span); + + if (retv != 0) + return retv; + + kirk_buf.Slice(0, 0x10).CopyTo(kirk_buf.Slice(kbuf)); + kirk_buf.Slice(kbuf + 0xC, 4).Span.Fill(0); + + if (ckey.type == 2) + { + for (i = 0; i < 16; i++) + { + kirk_buf.Span[i + kbuf] ^= amctrl_key2[i]; + } + retv = Kirk5(kirk_buf.Span, 0x10); + for (i = 0; i < 16; i++) + { + kirk_buf.Span[i + kbuf] ^= amctrl_key3[i]; + } + } + else + { + for (i = 0; i < 16; i++) + { + kirk_buf.Span[i + kbuf] ^= amctrl_key2[i]; + } + retv = Kirk4(kirk_buf.Span, 0x10, 0x39); + for (i = 0; i < 16; i++) + { + kirk_buf.Span[i + kbuf] ^= amctrl_key3[i]; + } + } + + if (retv != 0) + return retv; + + kirk_buf.Slice(kbuf, 0x10).Span.CopyTo(ckey.key); + // kirk_buf.Slice(kbuf, 0x10).Span.CopyTo(header_key); + + if (version_key != null) + { + for (i = 0; i < 16; i++) + { + ckey.key[i] ^= version_key[i]; + } + } + } + else + { + retv = 0; + } + + return retv; + } + + public static int sceDrmBBCipherUpdate(ref CIPHER_KEY ckey, Span data, int size) + { + int p, retv, dsize; + + retv = 0; + p = 0; + + while (size > 0) + { + dsize = (size >= 0x0800) ? 0x0800 : size; + retv = cipher_buf(kirk_buf.Span, data.Slice(p), dsize, ref ckey); + + if (retv != 0) + break; + + size -= dsize; + p += dsize; + } + + return retv; + } + + public static int sceDrmBBCipherFinal(ref CIPHER_KEY ckey) + { + ckey.key.Fill(0); + ckey.type = 0; + ckey.seed = 0; + return 0; + } + } +} diff --git a/PspCrypto/AesHelper.cs b/PspCrypto/AesHelper.cs new file mode 100644 index 0000000..0a7b99b --- /dev/null +++ b/PspCrypto/AesHelper.cs @@ -0,0 +1,251 @@ +using System; +using System.Linq; +using System.Security.Cryptography; + +namespace PspCrypto +{ + public static class AesHelper + { + private static readonly byte[] padding = { 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }; + + static readonly byte[] IV0 = new byte[16]; + static readonly byte[] Z = new byte[16]; + + public static Aes CreateAes() + { + var aes = Aes.Create(); + aes.KeySize = 128; + if (aes == null) + { + throw new Exception("Create Aes Failed"); + } + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.None; + aes.IV = IV0; + return aes; + } + + public static Aes CreateKirkAes() + { + var aes = CreateAes(); + aes.Key = KeyVault.kirk1_key; + return aes; + } + +#if false + public static byte[] Cmac(Aes aes, byte[] orgdata, int offset = 0, int len = -1) + { + if (len == -1) + { + len = orgdata.Length; + } + + byte[] data; + if (offset == 0 && len == orgdata.Length) + { + data = orgdata; + } + else + { + data = new byte[len]; + Buffer.BlockCopy(orgdata, offset, data, 0, len); + } + // SubKey generation + // step 1, AES-128 with key K is applied to an all-zero input block. + byte[] L = AesEncrypt(aes, Z); + + // step 2, K1 is derived through the following operation: + byte[] FirstSubkey = Rol(L); //If the most significant bit of L is equal to 0, K1 is the left-shift of L by 1 bit. + if ((L[0] & 0x80) == 0x80) + FirstSubkey[15] ^= 0x87; // Otherwise, K1 is the exclusive-OR of c + + // step 3, K2 is derived through the following operation: + byte[] SecondSubkey = Rol(FirstSubkey); // If the most significant bit of K1 is equal to 0, K2 is the left-shift of K1 by 1 bit. + if ((FirstSubkey[0] & 0x80) == 0x80) + SecondSubkey[15] ^= 0x87; // Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of K1 by 1 bit. + + // MAC computing + if (((data.Length != 0) && (data.Length % 16 == 0))) + { + // If the size of the input message block is equal to a positive multiple of the block size (namely, 128 bits), + // the last block shall be exclusive-OR'ed with K1 before processing + for (int j = 0; j < FirstSubkey.Length; j++) + data[data.Length - 16 + j] ^= FirstSubkey[j]; + } + else + { + // Otherwise, the last block shall be padded with 10^i + byte[] padding = new byte[16 - data.Length % 16]; + padding[0] = 0x80; + + data = data.Concat(padding).ToArray(); + + // and exclusive-OR'ed with K2 + for (int j = 0; j < SecondSubkey.Length; j++) + data[data.Length - 16 + j] ^= SecondSubkey[j]; + } + + // The result of the previous process will be the input of the last encryption. + byte[] encResult = AesEncrypt(aes, data); + + byte[] HashValue = new byte[16]; + //Array.Copy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length); + Buffer.BlockCopy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length); + + return HashValue; + } + +#endif + public static void Cmac(Aes aes, Span dst, ReadOnlySpan src) + { + byte[] data = src.ToArray(); + // SubKey generation + // step 1, AES-128 with key K is applied to an all-zero input block. + byte[] L = AesEncrypt(aes, Z); + + // step 2, K1 is derived through the following operation: + byte[] FirstSubkey = Rol(L); //If the most significant bit of L is equal to 0, K1 is the left-shift of L by 1 bit. + if ((L[0] & 0x80) == 0x80) + FirstSubkey[15] ^= 0x87; // Otherwise, K1 is the exclusive-OR of c + + // step 3, K2 is derived through the following operation: + byte[] SecondSubkey = Rol(FirstSubkey); // If the most significant bit of K1 is equal to 0, K2 is the left-shift of K1 by 1 bit. + if ((FirstSubkey[0] & 0x80) == 0x80) + SecondSubkey[15] ^= 0x87; // Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of K1 by 1 bit. + + // MAC computing + if (((data.Length != 0) && (data.Length % 16 == 0))) + { + // If the size of the input message block is equal to a positive multiple of the block size (namely, 128 bits), + // the last block shall be exclusive-OR'ed with K1 before processing + for (int j = 0; j < FirstSubkey.Length; j++) + data[data.Length - 16 + j] ^= FirstSubkey[j]; + } + else + { + // Otherwise, the last block shall be padded with 10^i + byte[] padding = new byte[16 - data.Length % 16]; + padding[0] = 0x80; + + data = data.Concat(padding).ToArray(); + + // and exclusive-OR'ed with K2 + for (int j = 0; j < SecondSubkey.Length; j++) + data[data.Length - 16 + j] ^= SecondSubkey[j]; + } + + // The result of the previous process will be the input of the last encryption. + byte[] encResult = AesEncrypt(aes, data); + + encResult.AsSpan(encResult.Length - 16,16).CopyTo(dst); + + //byte[] HashValue = new byte[16]; + //Array.Copy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length); + //Buffer.BlockCopy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length); + + //return HashValue; + } + + private static byte[] Rol(byte[] b) + { + byte[] r = new byte[b.Length]; + byte carry = 0; + + for (int i = b.Length - 1; i >= 0; i--) + { + ushort u = (ushort)(b[i] << 1); + r[i] = (byte)((u & 0xff) + carry); + carry = (byte)((u & 0xff00) >> 8); + } + + return r; + } + + private static byte[] AesEncrypt(Aes aes, byte[] data) + { + using var encryptor = aes.CreateEncryptor(); + return encryptor.TransformFinalBlock(data, 0, data.Length); + } +#if false + + public static byte[] AesEncrypt(Aes aes, byte[] data, int offset, int length) + { + using var encryptor = aes.CreateEncryptor(); + return encryptor.TransformFinalBlock(data, offset, length); + } +#endif + + public static void AesEncrypt(Aes aes, Span oubput, ReadOnlySpan input, int size = 0) + { + byte[] buffer; + if (size == 0) + { + size = input.Length; + } + if (size % 16 != 0) + { + buffer = new byte[(size + 15) / 16 * 16]; + var bufferSpan = new Span(buffer); + input.CopyTo(bufferSpan); + padding.AsSpan(0, buffer.Length - size).CopyTo(bufferSpan[size..]); + } + else + { + buffer = input[..size].ToArray(); + } + using var encryptor = aes.CreateEncryptor(); + var encData = encryptor.TransformFinalBlock(buffer, 0, buffer.Length); + encData.AsSpan().CopyTo(oubput); + } + +#if false + public static byte[] AesDecrypt(Aes aes, byte[] data, int offset, int length) + { + aes.Padding = PaddingMode.None; + using var encryptor = aes.CreateDecryptor(); + int fixLength = length; + if (length % 16 != 0) + { + fixLength = (length / 16 + 1) * 16; + } + + byte[] ret = encryptor.TransformFinalBlock(data, offset, fixLength); + return ret.Take(length).ToArray(); + } + + public static void AesDecrypt(Aes aes, byte[] src, byte[] dst, int size) + { + var tmp = AesDecrypt(aes, src, 0, size); + Buffer.BlockCopy(tmp, 0, dst, 0, size); + } +#endif + + public static void AesDecrypt(Aes aes, Span dst, ReadOnlySpan src, int length) + { + + int fixLength = length; + if (length % 16 != 0) + { + fixLength = (length + 15) / 16 * 16; + } + var buffer = src[..fixLength].ToArray(); + using var encryptor = aes.CreateDecryptor(); + var decData = encryptor.TransformFinalBlock(buffer, 0, buffer.Length); + decData.AsSpan(0, length).CopyTo(dst); + } + + public static int AesDecrypt(ReadOnlySpan src, Span dst, ReadOnlySpan key) + { + Aes aes = Aes.Create(); + aes.Key = key[..16].ToArray(); + return aes.DecryptEcb(src[..16], dst, PaddingMode.None); + } + + public static int AesEncrypt(ReadOnlySpan src, Span dst, ReadOnlySpan key) + { + Aes aes = Aes.Create(); + aes.Key = key[..16].ToArray(); + return aes.EncryptEcb(src[..16], dst, PaddingMode.None); + } + } +} diff --git a/PspCrypto/AtracCrypto.cs b/PspCrypto/AtracCrypto.cs new file mode 100644 index 0000000..898d2cd --- /dev/null +++ b/PspCrypto/AtracCrypto.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace PspCrypto +{ + public class AtracCrypto + { + + const int NBYTES = 0x180; + private static uint ROTR32(uint v, int n) + { + n &= 32 - 1; + return (v >> n) | (v << (32 - n)); + } + + public static int UnscrambleAtracData(byte[] data, uint key) + { + int blocks = (data.Length / NBYTES) / 0x10; + int chunks_rest = (data.Length / NBYTES) % 0x10; + Span ptr = MemoryMarshal.Cast(data); + uint tmp2 = key; + uint tmp; + uint value; + // for each block + while (blocks > 0) + { + // for each chunk of block + for (int i = 0; i < 0x10; i++) + { + tmp = tmp2; + + // for each value of chunk + for (int k = 0; k < (NBYTES / 4); k++) + { + value = ptr[k]; + ptr[k] = tmp ^ value; + tmp = tmp2 + (value * 123456789); + } + + tmp2 = ROTR32(tmp2, 1); + ptr = ptr[(NBYTES / 4)..]; // pointer on next chunk + } + + blocks--; + } + + // do rest chunks + for (int i = 0; i < chunks_rest; i++) + { + tmp = tmp2; + + // for each value of chunk + for (int k = 0; k < (NBYTES / 4); k++) + { + value = ptr[k]; + ptr[k] = tmp ^ value; + tmp = tmp2 + (value * 123456789); + } + + tmp2 = ROTR32(tmp2, 1); + ptr = ptr[(NBYTES / 4)..]; // next chunk + } + + return 0; + } + + public static void ScrambleAtracData(Stream input, Stream output, uint key) + { + int blocks = (Convert.ToInt32(input.Length) / NBYTES) / 0x10; + int chunks_rest = (Convert.ToInt32(input.Length) / NBYTES) % 0x10; + Span block = stackalloc byte[NBYTES]; + uint tmp2 = key; + uint tmp; + // for each block + while (blocks > 0) + { + // for each chunk of block + for (int i = 0; i < 0x10; i++) + { + tmp = tmp2; + + input.Read(block); + Span ptr = MemoryMarshal.Cast(block); + + // for each value of chunk + for (int k = 0; k < (NBYTES / 4); k++) + { + ptr[k] ^= tmp; + tmp = tmp2 + (ptr[k] * 123456789); + } + output.Write(block); + + tmp2 = ROTR32(tmp2, 1); + ptr = ptr[(NBYTES / 4)..]; // pointer on next chunk + } + + blocks--; + } + + // do rest chunks + for (int i = 0; i < chunks_rest; i++) + { + tmp = tmp2; + + input.Read(block); + Span ptr = MemoryMarshal.Cast(block); + + // for each value of chunk + for (int k = 0; k < (NBYTES / 4); k++) + { + ptr[k] ^= tmp; + tmp = tmp2 + (ptr[k] * 123456789); + } + output.Write(block); + + tmp2 = ROTR32(tmp2, 1); + ptr = ptr[(NBYTES / 4)..]; // next chunk + } + } + } +} diff --git a/PspCrypto/DNASHelper.cs b/PspCrypto/DNASHelper.cs new file mode 100644 index 0000000..088c79a --- /dev/null +++ b/PspCrypto/DNASHelper.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; + +namespace PspCrypto +{ + using PgdHeader = DNASStream.PgdHeader; + using PgdDesc = DNASStream.PgdDesc; + + public static class DNASHelper + { + public static int CalculateSize(int dataSize, int blockSize) + { + int alignSize = (dataSize + 15) & ~15; + int tableSize = ((alignSize + blockSize - 1) & ~(blockSize - 1)) / (blockSize / 16); + int pgdSize = 0x90 + alignSize + tableSize; + return pgdSize; + } + + public static int Encrypt(Span pgdData, ReadOnlySpan data, ReadOnlySpan key, int dataSize, int keyIndex, int drmType, int flag = 2, int blockSize = 0x400) + { + // Additional size variables. + var dataOffset = 0x90; + var alignSize = (dataSize + 15) & ~15; + var tableOffset = dataOffset + alignSize; + var tableSize = ((alignSize + blockSize - 1) & ~(blockSize - 1)) / (blockSize / 16); + var pgdSize = 0x90 + alignSize + tableSize; + + if (pgdData.Length < pgdSize) + { + return -1; + } + + data[..dataSize].CopyTo(pgdData[dataOffset..]); + + ref var pgdHdr = ref MemoryMarshal.AsRef(pgdData); + pgdHdr.Magic = 0x44475000; + pgdHdr.KeyIndex = keyIndex; + pgdHdr.DrmType = drmType; + + // Select the hashing, crypto and open modes. + int macType; + int cipherType; + var openFlag = flag; + if (drmType == 1) + { + macType = 1; + cipherType = 1; + openFlag |= 4; + if (keyIndex > 1) + { + macType = 3; + openFlag |= 0xc; + } + } + else + { + macType = 2; + cipherType = 2; + } + + // Select the fixed DNAS key. + + + byte[] dnasKey = null; + + if ((openFlag & 2) != 0) + { + dnasKey = DNASStream.DnasKey1; + } + else if ((openFlag & 1) != 0) + { + dnasKey = DNASStream.DnasKey2; + } + + if (dnasKey == null) + { + throw new Exception(); + } + + // Set the decryption parameters in the decrypted header. + ref var pgdDesc = ref MemoryMarshal.AsRef(pgdHdr.PgdDesc); + pgdDesc.DataSize = dataSize; + pgdDesc.BlockSize = blockSize; + pgdDesc.DataOffset = dataOffset; + + // Generate random header and data keys. + RandomNumberGenerator.Fill(pgdData.Slice(0x10, 0x30)); + + // Encrypt the data. + DNASStream.DoBBCipher(pgdData[dataOffset..], alignSize, 0, key, pgdDesc.Key, cipherType); + + // Build data MAC hash. + var tableNum = tableSize / 16; + for (int i = 0; i < tableNum; i++) + { + int rsize = alignSize - i * blockSize; + if (rsize > blockSize) + rsize = blockSize; + if (keyIndex < 3) + { + BuildBBMac(pgdData[(dataOffset + i * blockSize)..], rsize, key, + pgdData[(tableOffset + i * 16)..], + macType); + } + else + { + BuildBBMac(pgdData[(dataOffset + i * blockSize)..], rsize, key, + pgdData[(tableOffset + i * 16)..], + macType); + } + } + + // Build table MAC hash. + BuildBBMac(pgdData.Slice(tableOffset), tableSize, key, pgdHdr.MacTableHash, macType); + + // Encrypt the PGD header block (0x30 bytes). + DNASStream.DoBBCipher(pgdHdr.PgdDesc, 0x30, 0, key, pgdHdr.DescKey, cipherType); + + // Build MAC hash at 0x70 (key hash). + BuildBBMac(pgdData, 0x70, key, pgdHdr.Hash70, macType); + + // Build MAC hash at 0x80 (DNAS hash). + BuildBBMac(pgdData, 0x80, dnasKey, pgdHdr.Hash80, macType); + + return pgdSize; + } + + static int BuildBBMac(ReadOnlySpan data, int size, ReadOnlySpan key, Span hash, int macType, int seed = 0) + { + Span mkey = stackalloc byte[Marshal.SizeOf()]; + Span tmpKey = stackalloc byte[0x10]; + int ret = unchecked((int)0x80510201); + if (hash != null) + { + ret = AMCTRL.sceDrmBBMacInit(mkey, macType); + if (ret != 0) + { + return ret; + } + + ret = AMCTRL.sceDrmBBMacUpdate(mkey, data, size); + if (ret != 0) + { + return ret; + } + key.CopyTo(tmpKey); + if (seed != 0) + { + var tmpXor = MemoryMarshal.Cast(tmpKey); + tmpXor[0] ^= seed; + } + + ret = AMCTRL.sceDrmBBMacFinal(mkey, hash, tmpKey); + if (ret != 0) + { + ret = unchecked((int)0x80510207); + } + + if (macType == 3) + { + Utils.BuildDrmBBMacFinal2(hash); + } + + } + + return ret; + } + } +} diff --git a/PspCrypto/DNASStream.cs b/PspCrypto/DNASStream.cs new file mode 100644 index 0000000..f3e6093 --- /dev/null +++ b/PspCrypto/DNASStream.cs @@ -0,0 +1,636 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace PspCrypto +{ + public class DNASStream : Stream + { + internal static readonly byte[] DnasKeyBase = + { + 0x2A, 0x05, 0x54, 0x40, 0x62, 0xD9, 0x1F, 0xE3, 0xF2, 0xD0, 0x2B, 0xC6, 0x21, 0xFF, 0x20, 0x0E, + 0xB1, 0x44, 0x28, 0xDF, 0x0A, 0xCD, 0x14, 0x5B, 0xC8, 0x19, 0x36, 0x90, 0xD1, 0x42, 0x99, 0x2F + }; + + internal static readonly byte[] DnasKey1 = + { + 0xED, 0xE2, 0x5D, 0x2D, 0xBB, 0xF8, 0x12, 0xE5, 0x3C, 0x5C, 0x59, 0x32, 0xFA, 0xE3, 0xE2, 0x43 + }; + + internal static readonly byte[] DnasKey2 = + { + 0x27, 0x74, 0xFB, 0xEB, 0xA4, 0xA0, 0x01, 0xD7, 0x02, 0x56, 0x9E, 0x33, 0x8C, 0x19, 0x57, 0x83 + }; + + private static Memory _gMemory = new byte[0x640]; + private static Memory _gCipherMemory = new byte[0x200]; + + private Stream _baseStream; + private byte[] _versionKey; + + private long _position; + private long _pgdOffset; + private int _keyIndex; + private int _openFlag; + private long _dataOffset; + private long _tableOffset; + + public int KeyIndex => _keyIndex; + + private PgdDesc _desc; + + internal unsafe struct PgdHeader + { + public uint Magic; + public int KeyIndex; + public int DrmType; + public int Unk12; + private fixed byte _descKey[0x10]; + public Span DescKey + { + get + { + fixed (byte* ptr = _descKey) + { + return new Span(ptr, 0x10); + } + } + } + private fixed byte _keyHash[0x10]; + public Span KeyHash + { + get + { + fixed (byte* ptr = _keyHash) + { + return new Span(ptr, 0x10); + } + } + } + private fixed byte _pgdDesc[0x30]; + public Span PgdDesc + { + get + { + fixed (byte* ptr = _pgdDesc) + { + return new Span(ptr, 0x30); + } + } + } + private fixed byte _macTableHash[0x10]; + public Span MacTableHash + { + get + { + fixed (byte* ptr = _macTableHash) + { + return new Span(ptr, 0x10); + } + } + } + private fixed byte _hash70[0x10]; + public Span Hash70 + { + get + { + fixed (byte* ptr = _hash70) + { + return new Span(ptr, 0x10); + } + } + } + private fixed byte _hash80[0x10]; + public Span Hash80 + { + get + { + fixed (byte* ptr = _hash80) + { + return new Span(ptr, 0x10); + } + } + } + } + + internal unsafe struct PgdDesc + { + private fixed byte _key[0x10]; + + public Span Key + { + get + { + fixed (byte* ptr = _key) + { + return new Span(ptr, 0x10); + } + } + } + public int Version; + public int DataSize; + public int BlockSize; + public int DataOffset; + private fixed byte _unk20[0x10]; + + public Span Unk20 + { + get + { + fixed (byte* ptr = _unk20) + { + return new Span(ptr, 0x10); + } + } + } + + } + + public int BlockSize => _desc.BlockSize; + + public DNASStream(Stream stream, long pgdOffset, ReadOnlySpan versionKey, int flag = 2) + : this(stream, pgdOffset, versionKey.ToArray(), flag) + { + + } + + public DNASStream(Stream stream, long pgdOffset, byte[] versionKey = null, int flag = 2) + { + _baseStream = stream; + _pgdOffset = pgdOffset; + var offset = stream.Seek(pgdOffset, SeekOrigin.Begin); + if (offset != _pgdOffset) + { + throw new ArgumentOutOfRangeException(); + } + Span hdr = _gMemory[..0x90].Span; + var size = stream.Read(hdr); + if (size != 0x90) + { + throw new ArgumentException("stream too small", nameof(stream)); + } + var header = MemoryMarshal.AsRef(hdr); + _keyIndex = header.KeyIndex; + if (_keyIndex == 1) + { + _versionKey = versionKey ?? new byte[16]; + } + else + { + if (versionKey == null) + { + throw new ArgumentNullException(nameof(versionKey)); + } + Span mkey = stackalloc byte[Marshal.SizeOf()]; + AMCTRL.sceDrmBBMacInit(mkey, 1); + AMCTRL.sceDrmBBMacUpdate(mkey, DnasKeyBase, (_keyIndex - 1) * 0x10); + AMCTRL.sceDrmBBMacFinal(mkey, _versionKey, versionKey); + return; + } + + int macType; + int cipherType; + + if (header.DrmType == 1) + { + flag |= 4; + macType = 1; + cipherType = 1; + if (header.KeyIndex > 1) + { + flag |= 0xc; + macType = 3; + } + } + else if (header.DrmType == 0 && (flag & 4) == 0) + { + macType = 2; + cipherType = 2; + } + else + { + throw new IOException(); + } + + byte[] dnasKey = null; + + if ((flag & 2) != 0) + { + dnasKey = DnasKey1; + } + else if ((flag & 1) != 0) + { + dnasKey = DnasKey2; + } + + if (dnasKey == null) + { + throw new IOException(); + } + + var ret = CheckBBMac(hdr, 0x80, dnasKey, header.Hash80, macType); + if (ret != 0) + { + throw new IOException("Wrong MAC 0x80"); + } + + if (!Utils.IsEmpty(_versionKey, 0x10)) + { + ret = CheckBBMac(hdr, 0x70, _versionKey, header.Hash70, macType); + } + else + { + ret = GetMacKey(hdr, 0x70, _versionKey, header.Hash70, macType); + } + + if (ret != 0) + { + throw new IOException("Wrong MAC 0x70"); + } + + ret = DoBBCipher(header.PgdDesc, 0x30, 0, _versionKey, header.DescKey, cipherType); + if (ret != 0) + { + throw new IOException($"Error 0x{ret:X8}"); + } + var desc = MemoryMarshal.AsRef(header.PgdDesc); + if (desc.Version != 0) + { + throw new IOException($"Error 0x{8051020:X8}"); + } + + if (desc.BlockSize != 0x400) + { + throw new IOException($"Error 0x{80510204:X8}"); + } + + _openFlag = flag | 0x10; + _desc = desc; + _dataOffset = _desc.DataOffset + pgdOffset; + var blockSize = desc.BlockSize; + var alignSize = (desc.DataSize + 15) & ~15; + var tableSize = ((alignSize + blockSize - 1) & ~(blockSize - 1)) / (blockSize / 16); + _tableOffset = pgdOffset + 0x90 + alignSize; + if (header.KeyIndex < 3 && 0x7ffff < tableSize) + { + + } + { + Span mkey = stackalloc byte[Marshal.SizeOf()]; + ret = AMCTRL.sceDrmBBMacInit(mkey, macType); + stream.Seek(_tableOffset, SeekOrigin.Begin); + int read = 0; + if (tableSize != 0) + { + Span dataBuf = new byte[0x400]; + do + { + var tmpSize = tableSize - read; + if (tmpSize > 0x400) + { + tmpSize = 0x400; + } + + var data = dataBuf.Slice(0, tmpSize); + var readSize = stream.Read(data); + if (readSize != tmpSize) + { + throw new IOException(); + } + ret = AMCTRL.sceDrmBBMacUpdate(mkey, data, tmpSize); + if (ret != 0) + { + throw new Exception(); + } + read += 0x400; + } while (read < tableSize); + } + ret = AMCTRL.sceDrmBBMacFinal2(mkey, header.MacTableHash, _versionKey); + if (ret != 0) + { + throw new IOException($"Error 0x{80510204:X8}"); + } + } + + _position = 0; + + } + + public override void Flush() + { + _baseStream.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + int ret; + Span bufferSpan = buffer; + if ((_openFlag & 0x10) == 0) + { + throw new IOException($"Error 0x{80510207:X8}"); + } + + var dataSize = _desc.DataSize; + var seekOffset = _position; + if (seekOffset < dataSize) + { + var macType = 2; + var cipherType = 2; + if ((_openFlag & 4) != 0) + { + macType = 1; + if ((_openFlag & 8) != 0) + { + macType = 3; + } + + cipherType = 1; + } + + var endOffset = dataSize; + if (seekOffset + count <= dataSize) + { + endOffset = (int)(seekOffset + count); + } + + var blockSize = _desc.BlockSize; + var alignOffset = (int)seekOffset; + var totalReadSize = 0; + while (true) + { + if (endOffset <= alignOffset) + { + return totalReadSize; + } + + if ((_openFlag & 0x10) == 0) + { + break; + } + + var align = alignOffset & blockSize - 1; + + alignOffset -= align; + var alignBlockSize = endOffset - alignOffset; + int readBytes; + int uVar6; + Span readBuffer; + if (align == 0 && blockSize <= alignBlockSize) + { + readBytes = alignBlockSize & ~(blockSize - 1); + readBuffer = bufferSpan; + uVar6 = readBytes; + } + else + { + readBytes = blockSize; + readBuffer = _gMemory.Span; + if (dataSize < alignOffset + blockSize) + { + readBytes = (dataSize - alignOffset + 15) & ~15; + } + + uVar6 = blockSize; + if (endOffset < alignOffset + blockSize) + { + uVar6 = alignBlockSize; + } + } + + _baseStream.Seek(_dataOffset + alignOffset, SeekOrigin.Begin); + var realReadBytes = _baseStream.Read(readBuffer.Slice(0, readBytes)); + if (realReadBytes < readBytes) + { + throw new IOException(); + } + + var tableOffset = (alignOffset / blockSize) * 0x10; + _baseStream.Seek(_tableOffset + tableOffset, SeekOrigin.Begin); + var blockNr = 0; + if (readBytes != 0) + { + var tableReadOffset = 0; + var cipherSpan = _gCipherMemory.Span; + do + { + alignBlockSize = readBytes - tableReadOffset; + if (blockSize < readBytes - tableReadOffset) + { + alignBlockSize = blockSize; + } + + if ((blockNr & 0x1f) == 0) + { + if (blockSize == 0) + { + throw new IOException(); + } + + var tableBlock = readBytes / blockSize - blockNr; + if (tableBlock == 0) + { + tableBlock = 1; + } + + if (0x20 < tableBlock) + { + tableBlock = 0x20; + } + cipherSpan.Fill(0); + realReadBytes = _baseStream.Read(cipherSpan[..(tableBlock * 16)]); + if (realReadBytes < tableBlock * 16) + { + throw new IOException(); + } + } + if (_keyIndex < 3) + { + ret = CheckBBMac(readBuffer[tableReadOffset..], alignBlockSize, _versionKey, + cipherSpan.Slice((blockNr & 0x1f) * 16), macType); + } + else + { + ret = CheckBBMac(readBuffer[tableReadOffset..], alignBlockSize, _versionKey, + cipherSpan[((blockNr & 0x1f) * 16)..], macType, alignOffset); + } + + if (ret != 0) + { + throw new IOException(); + } + + tableReadOffset += blockSize; + blockNr++; + } while (tableReadOffset < readBytes); + } + ret = DoBBCipher(readBuffer, readBytes, alignOffset + align >> 4, _versionKey, _desc.Key, cipherType); + + if (ret != 0) + { + throw new IOException(); + } + var iVar2 = uVar6 - align; + seekOffset += iVar2; + _position = seekOffset; + if (readBuffer != bufferSpan) + { + readBuffer.Slice(align, iVar2).CopyTo(bufferSpan); + } + bufferSpan = bufferSpan[iVar2..]; + totalReadSize += iVar2; + alignOffset += uVar6; + } + } + + return 0; + } + + public override long Seek(long offset, SeekOrigin origin) + { + if ((_openFlag & 0x10) == 0) + { + throw new IOException($"Error 0x{80510206:X8}"); + } + + var dataSize = _desc.DataSize; + + switch (origin) + { + case SeekOrigin.Begin: + break; + case SeekOrigin.Current: + offset += -_position; + break; + case SeekOrigin.End: + offset += dataSize; + break; + } + if (offset > 0xffffffff) + { + offset = 0xffffffff; + } + + if (offset > dataSize) + { + offset = dataSize; + } + + _position = offset; + + return _position; + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + internal static int CheckBBMac(ReadOnlySpan data, int size, ReadOnlySpan key, ReadOnlySpan hash, int macType, int seed = 0) + { + Span mkey = stackalloc byte[Marshal.SizeOf()]; + Span tmpKey = stackalloc byte[0x10]; + int ret = unchecked((int)0x80510201); + if (hash != null) + { + ret = AMCTRL.sceDrmBBMacInit(mkey, macType); + if (ret != 0) + { + return ret; + } + + ret = AMCTRL.sceDrmBBMacUpdate(mkey, data, size); + if (ret != 0) + { + return ret; + } + key.CopyTo(tmpKey); + if (seed != 0) + { + var tmpXor = MemoryMarshal.Cast(tmpKey); + tmpXor[0] ^= seed; + } + + ret = AMCTRL.sceDrmBBMacFinal2(mkey, hash, tmpKey); + if (ret != 0) + { + ret = unchecked((int)0x80510207); + } + + } + + return ret; + } + + internal static int GetMacKey(ReadOnlySpan data, int size, Span key, ReadOnlySpan hash, int macType, int seed = 0) + { + Span mkey = stackalloc byte[Marshal.SizeOf()]; + Span tmpKey = stackalloc byte[0x10]; + int ret = unchecked((int)0x80510201); + if (hash != null) + { + ret = AMCTRL.sceDrmBBMacInit(mkey, macType); + if (ret != 0) + { + return ret; + } + + ret = AMCTRL.sceDrmBBMacUpdate(mkey, data, size); + if (ret != 0) + { + return ret; + } + + ret = AMCTRL.bbmac_getkey(mkey, hash, tmpKey); + if (ret != 0) + { + ret = unchecked((int)0x80510207); + } + if (seed != 0) + { + var tmpXor = MemoryMarshal.Cast(tmpKey); + tmpXor[0] ^= seed; + } + tmpKey.CopyTo(key); + + } + + return ret; + } + + internal static int DoBBCipher(Span data, int size, int seed, ReadOnlySpan versionKey, + ReadOnlySpan headerKey, int cipherType) + { + int ret = AMCTRL.sceDrmBBCipherInit(out var ckey, cipherType, 2, headerKey, versionKey, seed); + if (ret != 0) + { + return ret; + } + + ret = AMCTRL.sceDrmBBCipherUpdate(ref ckey, data, size); + if (ret != 0) + { + return ret; + } + + ret = AMCTRL.sceDrmBBCipherFinal(ref ckey); + return ret; + } + + public byte[] VersionKey => _versionKey; + + public override bool CanRead => _baseStream.CanRead; + public override bool CanSeek => _baseStream.CanSeek; + public override bool CanWrite => false; + public override long Length => _desc.DataSize; + public override long Position + { + get => _position; + set => _position = value; + } + } +} diff --git a/PspCrypto/ECDsaHelper.cs b/PspCrypto/ECDsaHelper.cs new file mode 100644 index 0000000..c8a57e3 --- /dev/null +++ b/PspCrypto/ECDsaHelper.cs @@ -0,0 +1,113 @@ +using PspCrypto.Security.Cryptography; +using System; +using System.Security.Cryptography; + +namespace PspCrypto +{ + public static class ECDsaHelper + { + public static ECCurve SetCurve(byte[] p, byte[] a, byte[] b, byte[] n, byte[] gx, byte[] gy) + { + return new ECCurve + { + A = a, + B = b, + Prime = p, + Order = n, + CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass, + Cofactor = new byte[] { 0x01 }, + G = new ECPoint { X = gx, Y = gy } + }; + } + + public static (byte[], ECPoint) GenerateKey(byte[] p, byte[] a, byte[] b, byte[] n, byte[] gx, byte[] gy) + { + var curve = new ECCurve + { + A = a, + B = b, + Prime = p, + Order = n, + CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass, + Cofactor = new byte[] { 0x01 }, + G = { X = gx, Y = gy } + }; + var ecdsa = new ECDsaManaged(); + ecdsa.GenerateKey(curve); + var parameter = ecdsa.ExportExplicitParameters(true); + return (parameter.D, parameter.Q); + } + + public static ECDsa Create(ECCurve curve, byte[] privateKey) + { + return Create(curve, privateKey, new byte[privateKey.Length], new byte[privateKey.Length]); + } + + + public static ECDsa Create(ECCurve curve, byte[] pubx, byte[] puby) + { + return Create(curve, null, pubx, puby); + } + + public static ECDsa Create(ECCurve curve, Span pubx, Span puby) + { + return Create(curve, null, pubx.ToArray(), puby.ToArray()); + } + + public static ECDsa Create(ECCurve curve, byte[] privateKey, byte[] pubx, byte[] puby, bool ebootPbp = false, int type = 1) + { + var par = new ECParameters + { + Curve = curve, + D = privateKey, + Q = { X = pubx, Y = puby } + }; + return new ECDsaManaged(par, ebootPbp, type); + } + + public static void SignNpImageHeader(Span npHdr) + { + var curve = SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2, + KeyVault.Gy2); + using var ecdsa = Create(curve, KeyVault.ec_Priv2, KeyVault.Px2, KeyVault.Py2); + var hash = ecdsa.SignData(npHdr[..0xD8].ToArray(), HashAlgorithmName.SHA1); + hash.CopyTo(npHdr[0xD8..]); + } + + public static bool VerifyEdat(Span edat) + { + var curve = SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2, + KeyVault.Gy2); + using var ecdsa = Create(curve, KeyVault.EdatPx, KeyVault.EdatPy); + return ecdsa.VerifyData(edat[..0x58], edat.Slice(0x58, 0x28), HashAlgorithmName.SHA1); + } + + public static void SignEdat(Span edat) + { + var curve = SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2, + KeyVault.Gy2); + using var ecdsa = Create(curve, KeyVault.EdatPirv, KeyVault.EdatPx, KeyVault.EdatPy); + var sig = ecdsa.SignData(edat[..0x58].ToArray(), HashAlgorithmName.SHA1); + sig.CopyTo(edat[0x58..]); + } + + public static void SignParamSfo(ReadOnlySpan param, Span sig) + { + var curve = SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2, + KeyVault.Gy2); + using var ecdsa = Create(curve, KeyVault.ec_Priv2, KeyVault.Px2, KeyVault.Py2); + var sigTmp = ecdsa.SignData(param.ToArray(), HashAlgorithmName.SHA1); + sigTmp.CopyTo(sig); + } + + public static bool VerifyEbootPbp(Span data, Span sig) + { + var sha224 = SHA224.Create(); + var hash = sha224.ComputeHash(data.ToArray()); + var curve = SetCurve(KeyVault.Eboot_p, KeyVault.Eboot_a, KeyVault.Eboot_b, KeyVault.Eboot_N, KeyVault.Eboot_Gx, + KeyVault.Eboot_Gy); + using var ecdsa = Create(curve, KeyVault.Eboot_priv2, KeyVault.Eboot_pub2x, KeyVault.Eboot_pub2y, true); + return ecdsa.VerifyHash(hash, sig); + } + } +} diff --git a/PspCrypto/KIRKEngine.cs b/PspCrypto/KIRKEngine.cs new file mode 100644 index 0000000..b6d03de --- /dev/null +++ b/PspCrypto/KIRKEngine.cs @@ -0,0 +1,1113 @@ +using System; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; + +namespace PspCrypto +{ + public static class KIRKEngine + { + // KIRK return values + public const int KIRK_OPERATION_SUCCESS = 0; + public const int KIRK_NOT_ENABLED = 1; + public const int KIRK_INVALID_MODE = 2; + public const int KIRK_HEADER_HASH_INVALID = 3; + public const int KIRK_DATA_HASH_INVALID = 4; + public const int KIRK_SIG_CHECK_INVALID = 5; + public const int KIRK_UNK_1 = 6; + public const int KIRK_UNK_2 = 7; + public const int KIRK_UNK_3 = 8; + public const int KIRK_UNK_4 = 9; + public const int KIRK_UNK_5 = 0xA; + public const int KIRK_UNK_6 = 0xB; + public const int KIRK_NOT_INITIALIZED = 0xC; + public const int KIRK_INVALID_OPERATION = 0xD; + public const int KIRK_INVALID_SEED_CODE = 0xE; + public const int KIRK_INVALID_SIZE = 0xF; + public const int KIRK_DATA_SIZE_ZERO = 0x10; + + // sceUtilsBufferCopyWithRange modes + public const int KIRK_CMD_DECRYPT_PRIVATE = 1; + public const int KIRK_CMD_2 = 2; + public const int KIRK_CMD_3 = 3; + public const int KIRK_CMD_ENCRYPT_IV_0 = 4; + public const int KIRK_CMD_ENCRYPT_IV_FUSE = 5; + public const int KIRK_CMD_ENCRYPT_IV_USER = 6; + public const int KIRK_CMD_DECRYPT_IV_0 = 7; + public const int KIRK_CMD_DECRYPT_IV_FUSE = 8; + public const int KIRK_CMD_DECRYPT_IV_USER = 9; + public const int KIRK_CMD_PRIV_SIGN_CHECK = 10; + public const int KIRK_CMD_SHA1_HASH = 11; + public const int KIRK_CMD_ECDSA_GEN_KEYS = 12; + public const int KIRK_CMD_ECDSA_MULTIPLY_POINT = 13; + public const int KIRK_CMD_PRNG = 14; + public const int KIRK_CMD_15 = 15; + public const int KIRK_CMD_ECDSA_SIGN = 16; + public const int KIRK_CMD_ECDSA_VERIFY = 17; + + // KIRK header modes + public const int KIRK_MODE_CMD1 = 1; + public const int KIRK_MODE_CMD2 = 2; + public const int KIRK_MODE_CMD3 = 3; + public const int KIRK_MODE_ENCRYPT_CBC = 4; + public const int KIRK_MODE_DECRYPT_CBC = 5; + + // sceUtilsBufferCopyWithRange errors + public const int SUBCWR_NOT_16_ALGINED = 0x90A; + public const int SUBCWR_HEADER_HASH_INVALID = 0x920; + public const int SUBCWR_BUFFER_TOO_SMALL = 0x1000; + + [StructLayout(LayoutKind.Sequential)] + public struct KIRK_AES128CBC_HEADER + { + public int mode; + public int unk_4; + public int unk_8; + public int keyseed; + public int data_size; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public unsafe struct KIRK_CMD1_HEADER + { + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + private fixed byte _AES_key[16]; + public Span AES_Key + { + get + { + fixed (byte* ptr = _AES_key) + { + return new Span(ptr, 16); + } + } + } + public Span AESKeys + { + get + { + fixed (byte* ptr = _AES_key) + { + return new Span(ptr, 32); + } + } + } + + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + private fixed byte _CMAC_key[16]; // 0x10 + public Span CMAC_key + { + get + { + fixed (byte* ptr = _CMAC_key) + { + return new Span(ptr, 16); + } + } + } + + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + private fixed byte _CMAC_header_hash[16]; // 0x20 + public Span CMAC_header_hash + { + get + { + fixed (byte* ptr = _CMAC_header_hash) + { + return new Span(ptr, 16); + } + } + } + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + private fixed byte _CMAC_data_hash[16]; // 0x30 + public Span CMAC_data_hash + { + get + { + fixed (byte* ptr = _CMAC_data_hash) + { + return new Span(ptr, 16); + } + } + } + + public Span content + { + get + { + fixed (byte* ptr = unused) + { + return new Span(ptr, 0x40); + } + } + } + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + fixed byte unused[32]; // 0x40 + public uint mode; // 0x60 + public byte ecdsa_hash; // 0x64 + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + fixed byte unk3[11]; // 0x65 + public int data_size; // 0x70 + + public Span off70 + { + get + { + fixed (int* ptr = &data_size) + { + return new Span(ptr, 0x10); + } + } + } + public int data_offset; // 0x74 + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + fixed byte unk4[8]; // 0x78 + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + fixed byte unk5[16]; // 0x80 + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct KIRK_CMD1_ECDSA_HEADER + { + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + private fixed byte _AES_key[16]; + + public Span AES_Key + { + get + { + fixed (byte* ptr = _AES_key) + { + return new Span(ptr, 16); + } + } + } + + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + private fixed byte _header_sig_r[20]; // 0x10 + + public Span header_sig_r + { + get + { + fixed (byte* ptr = _header_sig_r) + { + return new Span(ptr, 20); + } + } + } + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + private fixed byte _header_sig_s[20]; // 0x24 + + public Span header_sig_s + { + get + { + fixed (byte* ptr = _header_sig_s) + { + return new Span(ptr, 20); + } + } + } + + public Span header_sig + { + get + { + fixed (byte* ptr = _header_sig_r) + { + return new Span(ptr, 40); + } + } + } + + + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + private fixed byte _data_sig_r[20]; // 0x38 + + public Span data_sig_r + { + get + { + fixed (byte* ptr = _data_sig_r) + { + return new Span(ptr, 20); + } + } + } + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + private fixed byte _data_sig_s[20]; // 0x4c + public Span data_sig_s + { + get + { + fixed (byte* ptr = _data_sig_s) + { + return new Span(ptr, 20); + } + } + } + + public Span data_sig + { + get + { + fixed (byte* ptr = _data_sig_r) + { + return new Span(ptr, 40); + } + } + } + + + public uint mode; //0x60 + public byte ecdsa_hash; + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + fixed byte unk3[11]; + uint data_size; + uint data_offset; + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + fixed byte unk4[8]; + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + fixed byte unk5[16]; + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct ECDSA_SIG + { + private fixed byte _r[0x14]; + + public Span r + { + get + { + fixed (byte* ptr = _r) + { + return new Span(ptr, 0x14); + } + } + } + private fixed byte _s[0x14]; + + public Span s + { + get + { + fixed (byte* ptr = _s) + { + return new Span(ptr, 0x14); + } + } + } + + public Span sig + { + get + { + fixed (byte* ptr = _r) + { + return new Span(ptr, 0x28); + } + } + } + + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct ECDSA_POINT + { + private fixed byte _x[0x14]; + + public Span x + { + get + { + fixed (byte* ptr = _x) + { + return new Span(ptr, 0x14); + } + } + } + private fixed byte _y[0x14]; + + + public Span y + { + get + { + fixed (byte* ptr = _y) + { + return new Span(ptr, 0x14); + } + } + } + + public Span point + { + get + { + fixed (byte* ptr = _x) + { + return new Span(ptr, 0x28); + } + } + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct KIRK_SHA1_HEADER + { + public int data_size; + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct KIRK_CMD12_BUFFER + { + private fixed byte private_key_[0x14]; + + public Span private_key + { + get + { + fixed (byte* ptr = private_key_) + { + return new Span(ptr, 0x14); + } + } + } + public ECDSA_POINT public_key; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KIRK_CMD13_BUFFER + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x14)] + public byte[] multiplier; + public ECDSA_POINT public_key; + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct KIRK_CMD16_BUFFER + { + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + private fixed byte enc_private_[0x20]; + + public Span enc_private + { + get + { + fixed (byte* ptr = enc_private_) + { + return new Span(ptr, 0x20); + } + } + } + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x14)] + private fixed byte message_hash_[0x14]; + + public Span message_hash + { + get + { + fixed (byte* ptr = message_hash_) + { + return new Span(ptr, 0x14); + } + } + } + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct KIRK_CMD17_BUFFER + { + public ECDSA_POINT public_key; + private fixed byte _message_hash[0x14]; + + public Span message_hash + { + get + { + fixed (byte* ptr = _message_hash) + { + return new Span(ptr, 0x14); + } + } + } + public ECDSA_SIG signature; + } + // KIRK commands + /* + // Private Sig + Cipher + 0x01: Super-Duper decryption (no inverse) + 0x02: Encrypt Operation (inverse of 0x03) + 0x03: Decrypt Operation (inverse of 0x02) + + // Cipher + 0x04: Encrypt Operation (inverse of 0x07) (IV=0) + 0x05: Encrypt Operation (inverse of 0x08) (IV=FuseID) + 0x06: Encrypt Operation (inverse of 0x09) (IV=UserDefined) + 0x07: Decrypt Operation (inverse of 0x04) + 0x08: Decrypt Operation (inverse of 0x05) + 0x09: Decrypt Operation (inverse of 0x06) + + // Sig Gens + 0x0A: Private Signature Check (checks for private SCE sig) + 0x0B: SHA1 Hash + 0x0C: Mul1 + 0x0D: Mul2 + 0x0E: Random Number Gen + 0x0F: (absolutely no idea – could be KIRK initialization) + 0x10: Signature Gen + + // Sig Checks + 0x11: Signature Check (checks for generated sigs) + 0x12: Certificate Check (idstorage signatures) + */ + + // Internal variables + [StructLayout(LayoutKind.Sequential)] + private unsafe struct kirk16_data + { + private fixed byte fuseid_[8]; + + public Span fuseid + { + get + { + fixed (byte* ptr = fuseid_) + { + return new Span(ptr, 8); + } + } + } + private fixed byte mesh_[0x40]; + + public Span mesh + { + get + { + fixed (byte* ptr = mesh_) + { + return new Span(ptr, 0x40); + } + } + } + } + + //[StructLayout(LayoutKind.Sequential)] + //private unsafe struct header_keys + //{ + // // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + // public fixed byte AES[16]; + // // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + // public fixed byte CMAC[16]; + //} + + private static uint g_fuse90; + private static uint g_fuse94; + + private static Aes aes_kirk1; + private static byte[] PRNG_DATA = new byte[0x14]; + + private static bool is_kirk_initialized; + private static readonly byte[] IV0 = new byte[16]; + + // Internal functions + private static byte[] kirk_4_7_get_key(int key_type) + { + if ((key_type < 0) || (key_type >= 0x80)) throw new Exception("KIRK_INVALID_SIZE"); + return KeyVault.kirkKeys[key_type]; + } + + private static Aes CreateAes() + { + var aes_ctx = Aes.Create(); + aes_ctx.Mode = CipherMode.CBC; + aes_ctx.Padding = PaddingMode.None; + aes_ctx.IV = IV0; + return aes_ctx; + } + + public static void decrypt_kirk16_private(Span dA_out, Span dA_enc) + { + int i, k; + kirk16_data keydata; + byte[] subkey_1 = new byte[0x10], subkey_2 = new byte[0x10]; + using var aes_ctx = CreateAes(); + + keydata.fuseid[7] = (byte)(g_fuse90 & 0xFF); + keydata.fuseid[6] = (byte)((g_fuse90 >> 8) & 0xFF); + keydata.fuseid[5] = (byte)((g_fuse90 >> 16) & 0xFF); + keydata.fuseid[4] = (byte)((g_fuse90 >> 24) & 0xFF); + keydata.fuseid[3] = (byte)(g_fuse94 & 0xFF); + keydata.fuseid[2] = (byte)((g_fuse94 >> 8) & 0xFF); + keydata.fuseid[1] = (byte)((g_fuse94 >> 16) & 0xFF); + keydata.fuseid[0] = (byte)((g_fuse94 >> 24) & 0xFF); + + /* set encryption key */ + aes_ctx.Key = KeyVault.kirk16_key; + + /* set the subkeys */ + for (i = 0; i < 0x10; i++) + { + /* set to the fuseid */ + subkey_2[i] = subkey_1[i] = keydata.fuseid[i % 8]; + } + /* do aes crypto */ + using (var encryptor = aes_ctx.CreateEncryptor()) + { + using var decryptor = aes_ctx.CreateDecryptor(); + for (i = 0; i < 3; i++) + { + /* encrypt + decrypt */ + encryptor.TransformBlock(subkey_1, 0, subkey_1.Length, subkey_1, 0); + decryptor.TransformBlock(subkey_2, 0, subkey_2.Length, subkey_2, 0); + } + } + + /* set new key */ + aes_ctx.Key = subkey_1; + using (var encryptor = aes_ctx.CreateEncryptor()) + { + /* now lets make the key mesh */ + for (i = 0; i < 3; i++) + { + /* do encryption in group of 3 */ + for (k = 0; k < 3; k++) + { + /* crypto */ + encryptor.TransformBlock(subkey_2, 0, subkey_2.Length, subkey_2, 0); + } + + /* copy to out block */ + subkey_2.AsSpan().CopyTo(keydata.mesh[(i * 0x10)..]); + } + } + + /* set the key to the mesh */ + aes_ctx.Key = keydata.mesh.Slice(0x20, 0x10).ToArray(); + + using (var encryptor = aes_ctx.CreateEncryptor()) + { + /* do the encryption routines for the aes key */ + for (i = 0; i < 2; i++) + { + /* encrypt the data */ + var tmp = encryptor.TransformFinalBlock(keydata.mesh.ToArray(), 0x10, 0x30); + tmp.CopyTo(keydata.mesh[0x10..]); + } + } + + /* set the key to that mesh shit */ + using var aes = CreateAes(); + aes.Key = keydata.mesh.Slice(0x10, 0x10).ToArray(); + + + /* cbc decrypt the dA */ + AesHelper.AesDecrypt(aes, dA_out, dA_enc, 0x20); + } + + public static void encrypt_kirk16_private(Span dA_out, Span dA_dec) + { + int i, k; + kirk16_data keydata; + byte[] subkey_1 = new byte[0x10], subkey_2 = new byte[0x10]; + using var aes_ctx = CreateAes(); + + keydata.fuseid[7] = (byte)(g_fuse90 & 0xFF); + keydata.fuseid[6] = (byte)((g_fuse90 >> 8) & 0xFF); + keydata.fuseid[5] = (byte)((g_fuse90 >> 16) & 0xFF); + keydata.fuseid[4] = (byte)((g_fuse90 >> 24) & 0xFF); + keydata.fuseid[3] = (byte)(g_fuse94 & 0xFF); + keydata.fuseid[2] = (byte)((g_fuse94 >> 8) & 0xFF); + keydata.fuseid[1] = (byte)((g_fuse94 >> 16) & 0xFF); + keydata.fuseid[0] = (byte)((g_fuse94 >> 24) & 0xFF); + + /* set encryption key */ + aes_ctx.Key = KeyVault.kirk16_key; + + /* set the subkeys */ + for (i = 0; i < 0x10; i++) + { + /* set to the fuseid */ + subkey_2[i] = subkey_1[i] = keydata.fuseid[i % 8]; + } + /* do aes crypto */ + using (var encryptor = aes_ctx.CreateEncryptor()) + { + using var decryptor = aes_ctx.CreateDecryptor(); + for (i = 0; i < 3; i++) + { + /* encrypt + decrypt */ + subkey_1 = encryptor.TransformFinalBlock(subkey_1, 0, subkey_1.Length); + subkey_2 = decryptor.TransformFinalBlock(subkey_2, 0, subkey_2.Length); + } + } + + /* set new key */ + aes_ctx.Key = subkey_1; + using (var encryptor = aes_ctx.CreateEncryptor()) + { + /* now lets make the key mesh */ + for (i = 0; i < 3; i++) + { + /* do encryption in group of 3 */ + for (k = 0; k < 3; k++) + { + /* crypto */ + encryptor.TransformBlock(subkey_2, 0, subkey_2.Length, subkey_2, 0); + } + + /* copy to out block */ + subkey_2.AsSpan().CopyTo(keydata.mesh.Slice(i * 0x10)); + } + } + + /* set the key to the mesh */ + aes_ctx.Key = keydata.mesh.Slice(0x20, 0x10).ToArray(); + + using (var encryptor = aes_ctx.CreateEncryptor()) + { + /* do the encryption routines for the aes key */ + for (i = 0; i < 2; i++) + { + /* encrypt the data */ + var tmp = encryptor.TransformFinalBlock(keydata.mesh.ToArray(), 0x10, 0x30); + tmp.CopyTo(keydata.mesh.Slice(0x10)); + } + } + + /* set the key to that mesh shit */ + using var aes = CreateAes(); + aes.Key = keydata.mesh.Slice(0x10, 0x10).ToArray(); + + + /* cbc encrypt the dA */ + AesHelper.AesEncrypt(aes, dA_out, dA_dec, 0x20); + } + + static KIRKEngine() + { + kirk_init(); + } + + // KIRK commands + + public static int kirk_init() + { + //94 90 + //0x0000332 e6e050311 3000 + //0x0000772 ccda50f12 2000 + //0x1008010 1ef1e7101 vita + return kirk_init2(Encoding.ASCII.GetBytes("Lazy Dev should have initialized!"), 33, 0xBABEF00D, 0xDEADBEEF); + } + + public static int kirk_init2(byte[] rnd_seed, int seed_size, uint fuseid_90, uint fuseid_94) + { + Span temp = stackalloc byte[0x104]; + + // Another randomly selected data for a "key" to add to each randomization + ReadOnlySpan key = stackalloc byte[] { 0x07, 0xAB, 0xEF, 0xF8, 0x96, 0x8C, 0xF3, 0xD6, 0x14, 0xE0, 0xEB, 0xB2, 0x9D, 0x8B, 0x4E, 0x74 }; + uint curtime; + + is_kirk_initialized = true; + + //Set PRNG_DATA initially, otherwise use what ever uninitialized data is in the buffer + if (seed_size > 0) + { + Span seedbuf = stackalloc byte[seed_size + 4]; + RandomNumberGenerator.Fill(seedbuf); + var seedheader = new KIRK_SHA1_HEADER + { + data_size = seed_size + }; + MemoryMarshal.Write(seedbuf, ref seedheader); + kirk_CMD11(PRNG_DATA, seedbuf, seed_size + 4); + } + // Buffer.BlockCopy(PRNG_DATA, 0, header.data, 0, 0x14); + PRNG_DATA.CopyTo(temp.Slice(4)); + + // This uses the standard C time function for portability. + curtime = (uint)DateTimeOffset.Now.ToUnixTimeMilliseconds(); + temp[0x18] = (byte)(curtime & 0xFF); + temp[0x19] = (byte)((curtime >> 8) & 0xFF); + temp[0x1A] = (byte)((curtime >> 16) & 0xFF); + temp[0x1B] = (byte)((curtime >> 24) & 0xFF); + // Buffer.BlockCopy(key, 0, header.data, 0x18, 0x10); + key.CopyTo(temp.Slice(0x1c)); + + // This leaves the remainder of the 0x100 bytes in temp to whatever remains on the stack + // in an uninitialized state. This should add unpredicableness to the results as well + + var header = new KIRK_SHA1_HEADER + { + data_size = 0x100 + }; + MemoryMarshal.Write(temp, ref header); + kirk_CMD11(PRNG_DATA, temp, 0x104); + + + //Set Fuse ID + g_fuse90 = fuseid_90; + g_fuse94 = fuseid_94; + + // Set KIRK1 main key + aes_kirk1 = CreateAes(); + aes_kirk1.Key = KeyVault.kirk1_key; + return 0; + } + + static int kirk_CMD0(Span outbuff, ReadOnlySpan inbuff, int size, bool generate_trash) + { + KIRK_CMD1_HEADER header = MemoryMarshal.AsRef(outbuff); + // header_keys keys = Utils.AsRef(outbuff); + int chk_size; + Aes k1; + Aes cmac_key; + + if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED; + + inbuff[..size].CopyTo(outbuff); + + if (header.mode != KIRK_MODE_CMD1) return KIRK_INVALID_MODE; + + // FILL PREDATA WITH RANDOM DATA + if (generate_trash) kirk_CMD14(outbuff[Unsafe.SizeOf()..], header.data_offset); + + // Make sure data is 16 aligned + chk_size = header.data_size; + if (chk_size % 16 != 0) chk_size += 16 - (chk_size % 16); + + // ENCRYPT DATA + + // ENCRYPT DATA + using (k1 = CreateAes()) + { + k1.Key = header.AES_Key.ToArray(); + AesHelper.AesEncrypt(k1, outbuff[(Unsafe.SizeOf() + header.data_offset)..], + inbuff.Slice(Unsafe.SizeOf() + header.data_offset, header.data_size)); + //byte[] encData = AesHelper.AesEncrypt(k1, inbuff.ToArray(), + // Unsafe.SizeOf() + header.data_offset, + // chk_size); + //encData.CopyTo(outbuff.Slice(Unsafe.SizeOf() + header.data_offset)); + } + + + // CMAC HASHES + using (cmac_key = CreateAes()) + { + cmac_key.Key = header.CMAC_key.ToArray(); + //var cmac_header_hash = AesHelper.Cmac(cmac_key, outbuff.ToArray(), 0x60, 0x30); + //var cmac_data_hash = AesHelper.Cmac(cmac_key, outbuff.ToArray(), 0x60, 0x30 + chk_size); + Span cmac_header_hash = stackalloc byte[16]; + Span cmac_data_hash = stackalloc byte[16]; + AesHelper.Cmac(cmac_key, cmac_header_hash, outbuff.Slice(0x60, 0x30)); + AesHelper.Cmac(cmac_key, cmac_data_hash, outbuff.Slice(0x60, 0x30 + chk_size)); + cmac_header_hash.CopyTo(header.CMAC_header_hash); + cmac_data_hash.CopyTo(header.CMAC_data_hash); + } + + // ENCRYPT KEYS + // AesHelper.AesEncrypt(aes_kirk1) + return KIRK_OPERATION_SUCCESS; + } + + static int kirk_CMD1(Span outbuff, ReadOnlySpan inbuff, int size) + { + KIRK_CMD1_HEADER header = MemoryMarshal.AsRef(inbuff); + // header_keys keys; //0-15 AES key, 16-31 CMAC key + Aes k1; + + if (size < 0x90) return KIRK_INVALID_SIZE; + if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED; + if (header.mode != KIRK_MODE_CMD1) return KIRK_INVALID_MODE; + // byte[] keytmp = AesHelper.AesDecrypt(aes_kirk1, inbuff.ToArray(), 0, 32); + Span keytmp = stackalloc byte[32]; + AesHelper.AesDecrypt(aes_kirk1, keytmp, inbuff, 32); + + + if (header.ecdsa_hash == 1) + { + KIRK_CMD1_ECDSA_HEADER eheader = MemoryMarshal.AsRef(inbuff); + var curve = ECDsaHelper.SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b1, KeyVault.ec_N1, KeyVault.Gx1, + KeyVault.Gy1); + unsafe + { + var ecdsa = ECDsaHelper.Create(curve, KeyVault.ec_Priv1); + if (!ecdsa.VerifyData(inbuff.Slice(0x60, 0x30), eheader.header_sig.ToArray(), + HashAlgorithmName.SHA1)) + { + return KIRK_HEADER_HASH_INVALID; + } + ecdsa = ECDsaHelper.Create(curve, KeyVault.ec_Priv1); + if (!ecdsa.VerifyData(inbuff[0x60..size], eheader.data_sig.ToArray(), HashAlgorithmName.SHA1)) + { + return KIRK_DATA_HASH_INVALID; + } + } + } + else + { + int ret = kirk_CMD10(inbuff, size); + if (ret != KIRK_OPERATION_SUCCESS) return ret; + } + + k1 = CreateAes(); + k1.Key = keytmp.Slice(0, 16).ToArray(); + //var outtmp = AesHelper.AesDecrypt(k1, inbuff.ToArray(), Unsafe.SizeOf() + header.data_offset, header.data_size); + // Buffer.BlockCopy(outtmp, 0, outbuff, 0, (int)header.data_size); + + AesHelper.AesDecrypt(k1, outbuff, inbuff.Slice(Unsafe.SizeOf() + header.data_offset), header.data_size); + + return KIRK_OPERATION_SUCCESS; + } + + static int kirk_CMD4(Span outbuff, ReadOnlySpan inbuff, int size) + { + KIRK_AES128CBC_HEADER header = MemoryMarshal.AsRef(inbuff); + byte[] key; + Aes aes; + + if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED; + if (header.mode != KIRK_MODE_ENCRYPT_CBC) return KIRK_INVALID_MODE; + if (header.data_size == 0) return KIRK_DATA_SIZE_ZERO; + // size = size - 20; + using (aes = CreateAes()) + { + key = kirk_4_7_get_key(header.keyseed); + + // Set the key + aes.Key = key; + //var enc = AesHelper.AesEncrypt(aes, inbuff.ToArray(), Unsafe.SizeOf(), size); + // Buffer.BlockCopy(enc, 0, outbuff, Marshal.SizeOf() + outOffset, size); + //enc.AsSpan(0, size).CopyTo(outbuff.Slice(Unsafe.SizeOf(), size)); + AesHelper.AesEncrypt(aes, outbuff.Slice(Unsafe.SizeOf()), + inbuff.Slice(Unsafe.SizeOf(), header.data_size)); + } + return KIRK_OPERATION_SUCCESS; + } + + static int kirk_CMD7(Span outbuff, ReadOnlySpan inbuff, int size) + { + KIRK_AES128CBC_HEADER header = MemoryMarshal.AsRef(inbuff); + byte[] key; + Aes aes; + + if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED; + if (header.mode != KIRK_MODE_DECRYPT_CBC) return KIRK_INVALID_MODE; + if (header.data_size == 0) return KIRK_DATA_SIZE_ZERO; + using (aes = CreateAes()) + { + key = kirk_4_7_get_key(header.keyseed); + + // Set the key + aes.Key = key; + //var enc = AesHelper.AesDecrypt(aes, inbuff.ToArray(), Unsafe.SizeOf(), header.data_size); + //Buffer.BlockCopy(enc, 0, outbuff, outOffset, header.data_size); + //enc.AsSpan(0, header.data_size).CopyTo(outbuff); + AesHelper.AesDecrypt(aes, outbuff, inbuff.Slice(Unsafe.SizeOf()), header.data_size); + } + return KIRK_OPERATION_SUCCESS; + } + + static int kirk_CMD10(ReadOnlySpan inbuff, int insize) + { + KIRK_CMD1_HEADER header = MemoryMarshal.AsRef(inbuff); + // header_keys keys; //0-15 AES key, 16-31 CMAC key + Span cmac_header_hash = stackalloc byte[16]; + Span cmac_data_hash = stackalloc byte[16]; + using Aes cmac_key = CreateAes(); + int chk_size; + + if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED; + if (!(header.mode == KIRK_MODE_CMD1 || header.mode == KIRK_MODE_CMD2 || header.mode == KIRK_MODE_CMD3)) return KIRK_INVALID_MODE; + if (header.data_size == 0) return KIRK_DATA_SIZE_ZERO; + if (header.mode == KIRK_MODE_CMD1) + { + // var decdata = AesHelper.AesDecrypt(aes_kirk1, inbuff.ToArray(), 0, 32); + Span tmpKey = stackalloc byte[32]; + AesHelper.AesDecrypt(aes_kirk1, tmpKey, inbuff, 32); + cmac_key.Key = tmpKey[16..].ToArray(); + //cmac_header_hash = AesHelper.Cmac(cmac_key, inbuff.ToArray(), 0x60, 0x30); + AesHelper.Cmac(cmac_key, cmac_header_hash, inbuff.Slice(0x60, 0x30)); + + // Make sure data is 16 aligned + chk_size = header.data_size; + if (chk_size % 16 != 0) chk_size += 16 - (chk_size % 16); + //cmac_data_hash = AesHelper.Cmac(cmac_key, inbuff.ToArray(), 0x60, 0x30 + chk_size + header.data_offset); + AesHelper.Cmac(cmac_key, cmac_data_hash, inbuff.Slice(0x60, 0x30 + chk_size + header.data_offset)); + + if (!header.CMAC_header_hash.SequenceEqual(cmac_header_hash)) return KIRK_HEADER_HASH_INVALID; + if (!header.CMAC_data_hash.SequenceEqual(cmac_data_hash)) return KIRK_DATA_HASH_INVALID; + + return KIRK_OPERATION_SUCCESS; + } + + return KIRK_SIG_CHECK_INVALID; //Checks for cmd 2 & 3 not included right now + } + + static int kirk_CMD11(Span outbuff, ReadOnlySpan inbuff, int size) + { + KIRK_SHA1_HEADER header = MemoryMarshal.AsRef(inbuff); + if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED; + if (header.data_size == 0 || size == 0) return KIRK_DATA_SIZE_ZERO; + + //byte[] buff = new byte[header.data_size + 4]; + //using (var ms = new MemoryStream(buff)) + //{ + // using var bw = new BinaryWriter(ms); + // bw.Write(inbuff.data_size); + // bw.Write(inbuff.data); + //} + var sha = SHA1.Create(); + var hash = sha.ComputeHash(inbuff.Slice(4, header.data_size).ToArray()); + // Buffer.BlockCopy(hash, 0, outbuff, 0, hash.Length); + hash.CopyTo(outbuff); + return KIRK_OPERATION_SUCCESS; + } + + static int kirk_CMD12(Span outbuff, int outsize) + { + if (outsize != 0x3C) return KIRK_INVALID_SIZE; + + var (d, q) = ECDsaHelper.GenerateKey(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2, + KeyVault.Gy2); + d.AsSpan(0, 0x14).CopyTo(outbuff); + q.X.AsSpan(0, 0x14).CopyTo(outbuff.Slice(0x14)); + q.Y.AsSpan(0, 0x14).CopyTo(outbuff.Slice(0x28)); + //Buffer.BlockCopy(d, 0, outbuff, 0, 0x14); + //Buffer.BlockCopy(q.X, 0, outbuff, 0x14, 0x14); + //Buffer.BlockCopy(q.Y, 0, outbuff, 0x28, 0x14); + + return KIRK_OPERATION_SUCCESS; + } + + //static int kirk_CMD13() + + static int kirk_CMD14(Span outbuff, int outsize) + { + Span temp = stackalloc byte[0x104]; + + // Some randomly selected data for a "key" to add to each randomization + Span key = stackalloc byte[] { 0xA7, 0x2E, 0x4C, 0xB6, 0xC3, 0x34, 0xDF, 0x85, 0x70, 0x01, 0x49, 0xFC, 0xC0, 0x87, 0xC4, 0x77 }; + uint curtime; + + if (outsize <= 0) return KIRK_OPERATION_SUCCESS; + // Buffer.BlockCopy(PRNG_DATA, 0, header.data, 0, 0x14); + PRNG_DATA.CopyTo(temp.Slice(4)); + + // This uses the standard C time function for portability. + curtime = (uint)DateTimeOffset.Now.ToUnixTimeMilliseconds(); + temp[0x18] = (byte)(curtime & 0xFF); + temp[0x19] = (byte)((curtime >> 8) & 0xFF); + temp[0x1A] = (byte)((curtime >> 16) & 0xFF); + temp[0x1B] = (byte)((curtime >> 24) & 0xFF); + // Buffer.BlockCopy(key, 0, header.data, 0x18, 0x10); + key.CopyTo(temp[0x1C..]); + + // This leaves the remainder of the 0x100 bytes in temp to whatever remains on the stack + // in an uninitialized state. This should add unpredicableness to the results as well + // header.data_size = 0x100; + var header = new KIRK_SHA1_HEADER + { + data_size = 0x100 + }; + MemoryMarshal.Write(temp, ref header); + kirk_CMD11(PRNG_DATA, temp, 0x104); + + while (outsize > 0) + { + int blockrem = outsize % 0x14; + int block = outsize / 0x14; + + if (block > 0) + { + // Buffer.BlockCopy(PRNG_DATA, 0, outbuff, outoff, 0x14); + PRNG_DATA.CopyTo(outbuff); + outsize -= 0x14; + kirk_CMD14(outbuff[0x14..], outsize); + } + else if (blockrem > 0) + { + // Buffer.BlockCopy(PRNG_DATA, 0, outbuff, outoff, blockrem); + PRNG_DATA.AsSpan(0, blockrem).CopyTo(outbuff); + outsize -= blockrem; + } + } + + return KIRK_OPERATION_SUCCESS; + } + + static int kirk_CMD16(Span outbuff, int outsize, ReadOnlySpan inbuff, int insize) + { + byte[] dec_private = new byte[0x20]; + KIRK_CMD16_BUFFER signbuf = MemoryMarshal.AsRef(inbuff); + //ECDSA_SIG sig = BufferToStruct(outbuff); + + if (insize != 0x34) return KIRK_INVALID_SIZE; + if (outsize != 0x28) return KIRK_INVALID_SIZE; + + + decrypt_kirk16_private(dec_private, signbuf.enc_private); + + // Clear out the padding for safety + //Array.Clear(dec_private, 0x14, 0xC); + + var curve = ECDsaHelper.SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2, + KeyVault.Gy2); + var ecdsa = ECDsaHelper.Create(curve, dec_private.Take(0x14).ToArray()); + unsafe + { + var hashSig = ecdsa.SignHash(signbuf.message_hash.ToArray()); + // Buffer.BlockCopy(hashSig, 0, outbuff, outoffset, 0x28); + hashSig.CopyTo(outbuff); + } + + return KIRK_OPERATION_SUCCESS; + } + + static int kirk_CMD17(ReadOnlySpan inbuff, int insize) + { + KIRK_CMD17_BUFFER sig = MemoryMarshal.AsRef(inbuff); + + if (insize != 0x64) return KIRK_INVALID_SIZE; + + var curve = ECDsaHelper.SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2, + KeyVault.Gy2); + + unsafe + { + ECDsa ecdsa = ECDsaHelper.Create(curve, sig.public_key.x, sig.public_key.y); + + if (ecdsa.VerifyHash(sig.message_hash, sig.signature.sig)) + { + return KIRK_OPERATION_SUCCESS; + + } + } + return KIRK_SIG_CHECK_INVALID; + } + + // SCE functions + public static int sceUtilsBufferCopyWithRange(Span outbuff, int outsize, ReadOnlySpan inbuff, int insize, int cmd) + { + switch (cmd) + { + case KIRK_CMD_DECRYPT_PRIVATE: return kirk_CMD1(outbuff, inbuff, insize); + case KIRK_CMD_ENCRYPT_IV_0: return kirk_CMD4(outbuff, inbuff, insize); + case KIRK_CMD_DECRYPT_IV_0: return kirk_CMD7(outbuff, inbuff, insize); + case KIRK_CMD_PRIV_SIGN_CHECK: return kirk_CMD10(inbuff, insize); + case KIRK_CMD_SHA1_HASH: return kirk_CMD11(outbuff, inbuff, insize); + case KIRK_CMD_ECDSA_GEN_KEYS: return kirk_CMD12(outbuff, outsize); + //case KIRK_CMD_ECDSA_MULTIPLY_POINT: return kirk_CMD13(outbuff, outoffset, outsize, inbuff, insize); + case KIRK_CMD_PRNG: return kirk_CMD14(outbuff, outsize); + case KIRK_CMD_ECDSA_SIGN: return kirk_CMD16(outbuff, outsize, inbuff, insize); + case KIRK_CMD_ECDSA_VERIFY: return kirk_CMD17(inbuff, insize); + } + return -1; + } + } +} diff --git a/PspCrypto/KeyVault.cs b/PspCrypto/KeyVault.cs new file mode 100644 index 0000000..d136e7e --- /dev/null +++ b/PspCrypto/KeyVault.cs @@ -0,0 +1,231 @@ +using System; + +namespace PspCrypto +{ + + public static class KeyVault + { + // KIRK AES keys + public static readonly byte[][] kirkKeys = + { + new byte[] {0x2C, 0x92, 0xE5, 0x90, 0x2B, 0x86, 0xC1, 0x06, 0xB7, 0x2E, 0xEA, 0x6C, 0xD4, 0xEC, 0x72, 0x48}, + new byte[] {0x05, 0x8D, 0xC8, 0x0B, 0x33, 0xA5, 0xBF, 0x9D, 0x56, 0x98, 0xFA, 0xE0, 0xD3, 0x71, 0x5E, 0x1F}, + new byte[] {0xB8, 0x13, 0xC3, 0x5E, 0xC6, 0x44, 0x41, 0xE3, 0xDC, 0x3C, 0x16, 0xF5, 0xB4, 0x5E, 0x64, 0x84}, + new byte[] {0x98, 0x02, 0xC4, 0xE6, 0xEC, 0x9E, 0x9E, 0x2F, 0xFC, 0x63, 0x4C, 0xE4, 0x2F, 0xBB, 0x46, 0x68}, + new byte[] {0x99, 0x24, 0x4C, 0xD2, 0x58, 0xF5, 0x1B, 0xCB, 0xB0, 0x61, 0x9C, 0xA7, 0x38, 0x30, 0x07, 0x5F}, + new byte[] {0x02, 0x25, 0xD7, 0xBA, 0x63, 0xEC, 0xB9, 0x4A, 0x9D, 0x23, 0x76, 0x01, 0xB3, 0xF6, 0xAC, 0x17}, + new byte[] {0x60, 0x99, 0xF2, 0x81, 0x70, 0x56, 0x0E, 0x5F, 0x74, 0x7C, 0xB5, 0x20, 0xC0, 0xCD, 0xC2, 0x3C}, + new byte[] {0x76, 0x36, 0x8B, 0x43, 0x8F, 0x77, 0xD8, 0x7E, 0xFE, 0x5F, 0xB6, 0x11, 0x59, 0x39, 0x88, 0x5C}, + new byte[] {0x14, 0xA1, 0x15, 0xEB, 0x43, 0x4A, 0x1B, 0xA4, 0x90, 0x5E, 0x03, 0xB6, 0x17, 0xA1, 0x5C, 0x04}, + new byte[] {0xE6, 0x58, 0x03, 0xD9, 0xA7, 0x1A, 0xA8, 0x7F, 0x05, 0x9D, 0x22, 0x9D, 0xAF, 0x54, 0x53, 0xD0}, + new byte[] {0xBA, 0x34, 0x80, 0xB4, 0x28, 0xA7, 0xCA, 0x5F, 0x21, 0x64, 0x12, 0xF7, 0x0F, 0xBB, 0x73, 0x23}, + new byte[] {0x72, 0xAD, 0x35, 0xAC, 0x9A, 0xC3, 0x13, 0x0A, 0x77, 0x8C, 0xB1, 0x9D, 0x88, 0x55, 0x0B, 0x0C}, + new byte[] {0x84, 0x85, 0xC8, 0x48, 0x75, 0x08, 0x43, 0xBC, 0x9B, 0x9A, 0xEC, 0xA7, 0x9C, 0x7F, 0x60, 0x18}, + new byte[] {0xB5, 0xB1, 0x6E, 0xDE, 0x23, 0xA9, 0x7B, 0x0E, 0xA1, 0x7C, 0xDB, 0xA2, 0xDC, 0xDE, 0xC4, 0x6E}, + new byte[] {0xC8, 0x71, 0xFD, 0xB3, 0xBC, 0xC5, 0xD2, 0xF2, 0xE2, 0xD7, 0x72, 0x9D, 0xDF, 0x82, 0x68, 0x82}, + new byte[] {0x0A, 0xBB, 0x33, 0x6C, 0x96, 0xD4, 0xCD, 0xD8, 0xCB, 0x5F, 0x4B, 0xE0, 0xBA, 0xDB, 0x9E, 0x03}, + new byte[] {0x32, 0x29, 0x5B, 0xD5, 0xEA, 0xF7, 0xA3, 0x42, 0x16, 0xC8, 0x8E, 0x48, 0xFF, 0x50, 0xD3, 0x71}, + new byte[] {0x46, 0xF2, 0x5E, 0x8E, 0x4D, 0x2A, 0xA5, 0x40, 0x73, 0x0B, 0xC4, 0x6E, 0x47, 0xEE, 0x6F, 0x0A}, + new byte[] {0x5D, 0xC7, 0x11, 0x39, 0xD0, 0x19, 0x38, 0xBC, 0x02, 0x7F, 0xDD, 0xDC, 0xB0, 0x83, 0x7D, 0x9D}, + new byte[] {0x51, 0xDD, 0x65, 0xF0, 0x71, 0xA4, 0xE5, 0xEA, 0x6A, 0xAF, 0x12, 0x19, 0x41, 0x29, 0xB8, 0xF4}, + new byte[] {0x03, 0x76, 0x3C, 0x68, 0x65, 0xC6, 0x9B, 0x0F, 0xFE, 0x8F, 0xD8, 0xEE, 0xA4, 0x36, 0x16, 0xA0}, + new byte[] {0x7D, 0x50, 0xB8, 0x5C, 0xAF, 0x67, 0x69, 0xF0, 0xE5, 0x4A, 0xA8, 0x09, 0x8B, 0x0E, 0xBE, 0x1C}, + new byte[] {0x72, 0x68, 0x4B, 0x32, 0xAC, 0x3B, 0x33, 0x2F, 0x2A, 0x7A, 0xFC, 0x9E, 0x14, 0xD5, 0x6F, 0x6B}, + new byte[] {0x20, 0x1D, 0x31, 0x96, 0x4A, 0xD9, 0x9F, 0xBF, 0x32, 0xD5, 0xD6, 0x1C, 0x49, 0x1B, 0xD9, 0xFC}, + new byte[] {0xF8, 0xD8, 0x44, 0x63, 0xD6, 0x10, 0xD1, 0x2A, 0x44, 0x8E, 0x96, 0x90, 0xA6, 0xBB, 0x0B, 0xAD}, + new byte[] {0x5C, 0xD4, 0x05, 0x7F, 0xA1, 0x30, 0x60, 0x44, 0x0A, 0xD9, 0xB6, 0x74, 0x5F, 0x24, 0x4F, 0x4E}, + new byte[] {0xF4, 0x8A, 0xD6, 0x78, 0x59, 0x9C, 0x22, 0xC1, 0xD4, 0x11, 0x93, 0x3D, 0xF8, 0x45, 0xB8, 0x93}, + new byte[] {0xCA, 0xE7, 0xD2, 0x87, 0xA2, 0xEC, 0xC1, 0xCD, 0x94, 0x54, 0x2B, 0x5E, 0x1D, 0x94, 0x88, 0xB2}, + new byte[] {0xDE, 0x26, 0xD3, 0x7A, 0x39, 0x95, 0x6C, 0x2A, 0xD8, 0xC3, 0xA6, 0xAF, 0x21, 0xEB, 0xB3, 0x01}, + new byte[] {0x7C, 0xB6, 0x8B, 0x4D, 0xA3, 0x8D, 0x1D, 0xD9, 0x32, 0x67, 0x9C, 0xA9, 0x9F, 0xFB, 0x28, 0x52}, + new byte[] {0xA0, 0xB5, 0x56, 0xB4, 0x69, 0xAB, 0x36, 0x8F, 0x36, 0xDE, 0xC9, 0x09, 0x2E, 0xCB, 0x41, 0xB1}, + new byte[] {0x93, 0x9D, 0xE1, 0x9B, 0x72, 0x5F, 0xEE, 0xE2, 0x45, 0x2A, 0xBC, 0x17, 0x06, 0xD1, 0x47, 0x69}, + new byte[] {0xA4, 0xA4, 0xE6, 0x21, 0x38, 0x2E, 0xF1, 0xAF, 0x7B, 0x17, 0x7A, 0xE8, 0x42, 0xAD, 0x00, 0x31}, + new byte[] {0xC3, 0x7F, 0x13, 0xE8, 0xCF, 0x84, 0xDB, 0x34, 0x74, 0x7B, 0xC3, 0xA0, 0xF1, 0x9D, 0x3A, 0x73}, + new byte[] {0x2B, 0xF7, 0x83, 0x8A, 0xD8, 0x98, 0xE9, 0x5F, 0xA5, 0xF9, 0x01, 0xDA, 0x61, 0xFE, 0x35, 0xBB}, + new byte[] {0xC7, 0x04, 0x62, 0x1E, 0x71, 0x4A, 0x66, 0xEA, 0x62, 0xE0, 0x4B, 0x20, 0x3D, 0xB8, 0xC2, 0xE5}, + new byte[] {0xC9, 0x33, 0x85, 0x9A, 0xAB, 0x00, 0xCD, 0xCE, 0x4D, 0x8B, 0x8E, 0x9F, 0x3D, 0xE6, 0xC0, 0x0F}, + new byte[] {0x18, 0x42, 0x56, 0x1F, 0x2B, 0x5F, 0x34, 0xE3, 0x51, 0x3E, 0xB7, 0x89, 0x77, 0x43, 0x1A, 0x65}, + new byte[] {0xDC, 0xB0, 0xA0, 0x06, 0x5A, 0x50, 0xA1, 0x4E, 0x59, 0xAC, 0x97, 0x3F, 0x17, 0x58, 0xA3, 0xA3}, + new byte[] {0xC4, 0xDB, 0xAE, 0x83, 0xE2, 0x9C, 0xF2, 0x54, 0xA3, 0xDD, 0x37, 0x4E, 0x80, 0x7B, 0xF4, 0x25}, + new byte[] {0xBF, 0xAE, 0xEB, 0x49, 0x82, 0x65, 0xC5, 0x7C, 0x64, 0xB8, 0xC1, 0x7E, 0x19, 0x06, 0x44, 0x09}, + new byte[] {0x79, 0x7C, 0xEC, 0xC3, 0xB3, 0xEE, 0x0A, 0xC0, 0x3B, 0xD8, 0xE6, 0xC1, 0xE0, 0xA8, 0xB1, 0xA4}, + new byte[] {0x75, 0x34, 0xFE, 0x0B, 0xD6, 0xD0, 0xC2, 0x8D, 0x68, 0xD4, 0xE0, 0x2A, 0xE7, 0xD5, 0xD1, 0x55}, + new byte[] {0xFA, 0xB3, 0x53, 0x26, 0x97, 0x4F, 0x4E, 0xDF, 0xE4, 0xC3, 0xA8, 0x14, 0xC3, 0x2F, 0x0F, 0x88}, + new byte[] {0xEC, 0x97, 0xB3, 0x86, 0xB4, 0x33, 0xC6, 0xBF, 0x4E, 0x53, 0x9D, 0x95, 0xEB, 0xB9, 0x79, 0xE4}, + new byte[] {0xB3, 0x20, 0xA2, 0x04, 0xCF, 0x48, 0x06, 0x29, 0xB5, 0xDD, 0x8E, 0xFC, 0x98, 0xD4, 0x17, 0x7B}, + new byte[] {0x5D, 0xFC, 0x0D, 0x4F, 0x2C, 0x39, 0xDA, 0x68, 0x4A, 0x33, 0x74, 0xED, 0x49, 0x58, 0xA7, 0x3A}, + new byte[] {0xD7, 0x5A, 0x54, 0x22, 0xCE, 0xD9, 0xA3, 0xD6, 0x2B, 0x55, 0x7D, 0x8D, 0xE8, 0xBE, 0xC7, 0xEC}, + new byte[] {0x6B, 0x4A, 0xEE, 0x43, 0x45, 0xAE, 0x70, 0x07, 0xCF, 0x8D, 0xCF, 0x4E, 0x4A, 0xE9, 0x3C, 0xFA}, + new byte[] {0x2B, 0x52, 0x2F, 0x66, 0x4C, 0x2D, 0x11, 0x4C, 0xFE, 0x61, 0x31, 0x8C, 0x56, 0x78, 0x4E, 0xA6}, + new byte[] {0x3A, 0xA3, 0x4E, 0x44, 0xC6, 0x6F, 0xAF, 0x7B, 0xFA, 0xE5, 0x53, 0x27, 0xEF, 0xCF, 0xCC, 0x24}, + new byte[] {0x2B, 0x5C, 0x78, 0xBF, 0xC3, 0x8E, 0x49, 0x9D, 0x41, 0xC3, 0x3C, 0x5C, 0x7B, 0x27, 0x96, 0xCE}, + new byte[] {0xF3, 0x7E, 0xEA, 0xD2, 0xC0, 0xC8, 0x23, 0x1D, 0xA9, 0x9B, 0xFA, 0x49, 0x5D, 0xB7, 0x08, 0x1B}, + new byte[] {0x70, 0x8D, 0x4E, 0x6F, 0xD1, 0xF6, 0x6F, 0x1D, 0x1E, 0x1F, 0xCB, 0x02, 0xF9, 0xB3, 0x99, 0x26}, + new byte[] {0x0F, 0x67, 0x16, 0xE1, 0x80, 0x69, 0x9C, 0x51, 0xFC, 0xC7, 0xAD, 0x6E, 0x4F, 0xB8, 0x46, 0xC9}, + new byte[] {0x56, 0x0A, 0x49, 0x4A, 0x84, 0x4C, 0x8E, 0xD9, 0x82, 0xEE, 0x0B, 0x6D, 0xC5, 0x7D, 0x20, 0x8D}, + new byte[] {0x12, 0x46, 0x8D, 0x7E, 0x1C, 0x42, 0x20, 0x9B, 0xBA, 0x54, 0x26, 0x83, 0x5E, 0xB0, 0x33, 0x03}, + new byte[] {0xC4, 0x3B, 0xB6, 0xD6, 0x53, 0xEE, 0x67, 0x49, 0x3E, 0xA9, 0x5F, 0xBC, 0x0C, 0xED, 0x6F, 0x8A}, + new byte[] {0x2C, 0xC3, 0xCF, 0x8C, 0x28, 0x78, 0xA5, 0xA6, 0x63, 0xE2, 0xAF, 0x2D, 0x71, 0x5E, 0x86, 0xBA}, + new byte[] {0x83, 0x3D, 0xA7, 0x0C, 0xED, 0x6A, 0x20, 0x12, 0xD1, 0x96, 0xE6, 0xFE, 0x5C, 0x4D, 0x37, 0xC5}, + new byte[] {0xC7, 0x43, 0xD0, 0x67, 0x42, 0xEE, 0x90, 0xB8, 0xCA, 0x75, 0x50, 0x35, 0x20, 0xAD, 0xBC, 0xCE}, + new byte[] {0x8A, 0xE3, 0x66, 0x3F, 0x8D, 0x9E, 0x82, 0xA1, 0xED, 0xE6, 0x8C, 0x9C, 0xE8, 0x25, 0x6D, 0xAA}, + new byte[] {0x7F, 0xC9, 0x6F, 0x0B, 0xB1, 0x48, 0x5C, 0xA5, 0x5D, 0xD3, 0x64, 0xB7, 0x7A, 0xF5, 0xE4, 0xEA}, + new byte[] {0x91, 0xB7, 0x65, 0x78, 0x8B, 0xCB, 0x8B, 0xD4, 0x02, 0xED, 0x55, 0x3A, 0x66, 0x62, 0xD0, 0xAD}, + new byte[] {0x28, 0x24, 0xF9, 0x10, 0x1B, 0x8D, 0x0F, 0x7B, 0x6E, 0xB2, 0x63, 0xB5, 0xB5, 0x5B, 0x2E, 0xBB}, + new byte[] {0x30, 0xE2, 0x57, 0x5D, 0xE0, 0xA2, 0x49, 0xCE, 0xE8, 0xCF, 0x2B, 0x5E, 0x4D, 0x9F, 0x52, 0xC7}, + new byte[] {0x5E, 0xE5, 0x04, 0x39, 0x62, 0x32, 0x02, 0xFA, 0x85, 0x39, 0x3F, 0x72, 0xBB, 0x77, 0xFD, 0x1A}, + new byte[] {0xF8, 0x81, 0x74, 0xB1, 0xBD, 0xE9, 0xBF, 0xDD, 0x45, 0xE2, 0xF5, 0x55, 0x89, 0xCF, 0x46, 0xAB}, + new byte[] {0x7D, 0xF4, 0x92, 0x65, 0xE3, 0xFA, 0xD6, 0x78, 0xD6, 0xFE, 0x78, 0xAD, 0xBB, 0x3D, 0xFB, 0x63}, + new byte[] {0x74, 0x7F, 0xD6, 0x2D, 0xC7, 0xA1, 0xCA, 0x96, 0xE2, 0x7A, 0xCE, 0xFF, 0xAA, 0x72, 0x3F, 0xF7}, + new byte[] {0x1E, 0x58, 0xEB, 0xD0, 0x65, 0xBB, 0xF1, 0x68, 0xC5, 0xBD, 0xF7, 0x46, 0xBA, 0x7B, 0xE1, 0x00}, + new byte[] {0x24, 0x34, 0x7D, 0xAF, 0x5E, 0x4B, 0x35, 0x72, 0x7A, 0x52, 0x27, 0x6B, 0xA0, 0x54, 0x74, 0xDB}, + new byte[] {0x09, 0xB1, 0xC7, 0x05, 0xC3, 0x5F, 0x53, 0x66, 0x77, 0xC0, 0xEB, 0x36, 0x77, 0xDF, 0x83, 0x07}, + new byte[] {0xCC, 0xBE, 0x61, 0x5C, 0x05, 0xA2, 0x00, 0x33, 0x37, 0x8E, 0x59, 0x64, 0xA7, 0xDD, 0x70, 0x3D}, + new byte[] {0x0D, 0x47, 0x50, 0xBB, 0xFC, 0xB0, 0x02, 0x81, 0x30, 0xE1, 0x84, 0xDE, 0xA8, 0xD4, 0x84, 0x13}, + new byte[] {0x0C, 0xFD, 0x67, 0x9A, 0xF9, 0xB4, 0x72, 0x4F, 0xD7, 0x8D, 0xD6, 0xE9, 0x96, 0x42, 0x28, 0x8B}, + new byte[] {0x7A, 0xD3, 0x1A, 0x8B, 0x4B, 0xEF, 0xC2, 0xC2, 0xB3, 0x99, 0x01, 0xA9, 0xFE, 0x76, 0xB9, 0x87}, + new byte[] {0xBE, 0x78, 0x78, 0x17, 0xC7, 0xF1, 0x6F, 0x1A, 0xE0, 0xEF, 0x3B, 0xDE, 0x4C, 0xC2, 0xD7, 0x86}, + new byte[] {0x7C, 0xD8, 0xB8, 0x91, 0x91, 0x0A, 0x43, 0x14, 0xD0, 0x53, 0x3D, 0xD8, 0x4C, 0x45, 0xBE, 0x16}, + new byte[] {0x32, 0x72, 0x2C, 0x88, 0x07, 0xCF, 0x35, 0x7D, 0x4A, 0x2F, 0x51, 0x19, 0x44, 0xAE, 0x68, 0xDA}, + new byte[] {0x7E, 0x6B, 0xBF, 0xF6, 0xF6, 0x87, 0xB8, 0x98, 0xEE, 0xB5, 0x1B, 0x32, 0x16, 0xE4, 0x6E, 0x5D}, + new byte[] {0x08, 0xEA, 0x5A, 0x83, 0x49, 0xB5, 0x9D, 0xB5, 0x3E, 0x07, 0x79, 0xB1, 0x9A, 0x59, 0xA3, 0x54}, + new byte[] {0xF3, 0x12, 0x81, 0xBF, 0xE6, 0x9F, 0x51, 0xD1, 0x64, 0x08, 0x25, 0x21, 0xFF, 0xBB, 0x22, 0x61}, + new byte[] {0xAF, 0xFE, 0x8E, 0xB1, 0x3D, 0xD1, 0x7E, 0xD8, 0x0A, 0x61, 0x24, 0x1C, 0x95, 0x92, 0x56, 0xB6}, + new byte[] {0x92, 0xCD, 0xB4, 0xC2, 0x5B, 0xF2, 0x35, 0x5A, 0x23, 0x09, 0xE8, 0x19, 0xC9, 0x14, 0x42, 0x35}, + new byte[] {0xE1, 0xC6, 0x5B, 0x22, 0x6B, 0xE1, 0xDA, 0x02, 0xBA, 0x18, 0xFA, 0x21, 0x34, 0x9E, 0xF9, 0x6D}, + new byte[] {0x14, 0xEC, 0x76, 0xCE, 0x97, 0xF3, 0x8A, 0x0A, 0x34, 0x50, 0x6C, 0x53, 0x9A, 0x5C, 0x9A, 0xB4}, + new byte[] {0x1C, 0x9B, 0xC4, 0x90, 0xE3, 0x06, 0x64, 0x81, 0xFA, 0x59, 0xFD, 0xB6, 0x00, 0xBB, 0x28, 0x70}, + new byte[] {0x43, 0xA5, 0xCA, 0xCC, 0x0D, 0x6C, 0x2D, 0x3F, 0x2B, 0xD9, 0x89, 0x67, 0x6B, 0x3F, 0x7F, 0x57}, + new byte[] {0x00, 0xEF, 0xFD, 0x18, 0x08, 0xA4, 0x05, 0x89, 0x3C, 0x38, 0xFB, 0x25, 0x72, 0x70, 0x61, 0x06}, + new byte[] {0xEE, 0xAF, 0x49, 0xE0, 0x09, 0x87, 0x9B, 0xEF, 0xAA, 0xD6, 0x32, 0x6A, 0x32, 0x13, 0xC4, 0x29}, + new byte[] {0x8D, 0x26, 0xB9, 0x0F, 0x43, 0x1D, 0xBB, 0x08, 0xDB, 0x1D, 0xDA, 0xC5, 0xB5, 0x2C, 0x92, 0xED}, + new byte[] {0x57, 0x7C, 0x30, 0x60, 0xAE, 0x6E, 0xBE, 0xAE, 0x3A, 0xAB, 0x18, 0x19, 0xC5, 0x71, 0x68, 0x0B}, + new byte[] {0x11, 0x5A, 0x5D, 0x20, 0xD5, 0x3A, 0x8D, 0xD3, 0x9C, 0xC5, 0xAF, 0x41, 0x0F, 0x0F, 0x18, 0x6F}, + new byte[] {0x0D, 0x4D, 0x51, 0xAB, 0x23, 0x79, 0xBF, 0x80, 0x3A, 0xBF, 0xB9, 0x0E, 0x75, 0xFC, 0x14, 0xBF}, + new byte[] {0x99, 0x93, 0xDA, 0x3E, 0x7D, 0x2E, 0x5B, 0x15, 0xF2, 0x52, 0xA4, 0xE6, 0x6B, 0xB8, 0x5A, 0x98}, + new byte[] {0xF4, 0x28, 0x30, 0xA5, 0xFB, 0x0D, 0x8D, 0x76, 0x0E, 0xA6, 0x71, 0xC2, 0x2B, 0xDE, 0x66, 0x9D}, + new byte[] {0xFB, 0x5F, 0xEB, 0x7F, 0xC7, 0xDC, 0xDD, 0x69, 0x37, 0x01, 0x97, 0x9B, 0x29, 0x03, 0x5C, 0x47}, + new byte[] {0x02, 0x32, 0x6A, 0xE7, 0xD3, 0x96, 0xCE, 0x7F, 0x1C, 0x41, 0x9D, 0xD6, 0x52, 0x07, 0xED, 0x09}, + new byte[] {0x9C, 0x9B, 0x13, 0x72, 0xF8, 0xC6, 0x40, 0xCF, 0x1C, 0x62, 0xF5, 0xD5, 0x92, 0xDD, 0xB5, 0x82}, + new byte[] {0x03, 0xB3, 0x02, 0xE8, 0x5F, 0xF3, 0x81, 0xB1, 0x3B, 0x8D, 0xAA, 0x2A, 0x90, 0xFF, 0x5E, 0x61}, + new byte[] {0xBC, 0xD7, 0xF9, 0xD3, 0x2F, 0xAC, 0xF8, 0x47, 0xC0, 0xFB, 0x4D, 0x2F, 0x30, 0x9A, 0xBD, 0xA6}, + new byte[] {0xF5, 0x55, 0x96, 0xE9, 0x7F, 0xAF, 0x86, 0x7F, 0xAC, 0xB3, 0x3A, 0xE6, 0x9C, 0x8B, 0x6F, 0x93}, + new byte[] {0xEE, 0x29, 0x70, 0x93, 0xF9, 0x4E, 0x44, 0x59, 0x44, 0x17, 0x1F, 0x8E, 0x86, 0xE1, 0x70, 0xFC}, + new byte[] {0xE4, 0x34, 0x52, 0x0C, 0xF0, 0x88, 0xCF, 0xC8, 0xCD, 0x78, 0x1B, 0x6C, 0xCF, 0x8C, 0x48, 0xC4}, + new byte[] {0xC1, 0xBF, 0x66, 0x81, 0x8E, 0xF9, 0x53, 0xF2, 0xE1, 0x26, 0x6B, 0x6F, 0x55, 0x0C, 0xC9, 0xCD}, + new byte[] {0x56, 0x0F, 0xFF, 0x8F, 0x3C, 0x96, 0x49, 0x14, 0x45, 0x16, 0xF1, 0xBC, 0xBF, 0xCE, 0xA3, 0x0C}, + new byte[] {0x24, 0x08, 0xDC, 0x75, 0x37, 0x60, 0xA2, 0x9F, 0x05, 0x54, 0xB5, 0xF2, 0x43, 0x85, 0x73, 0x99}, + new byte[] {0xDD, 0xD5, 0xB5, 0x6A, 0x59, 0xC5, 0x5A, 0xE8, 0x3B, 0x96, 0x67, 0xC7, 0x5C, 0x2A, 0xE2, 0xDC}, + new byte[] {0xAA, 0x68, 0x67, 0x72, 0xE0, 0x2D, 0x44, 0xD5, 0xCD, 0xBB, 0x65, 0x04, 0xBC, 0xD5, 0xBF, 0x4E}, + new byte[] {0x1F, 0x17, 0xF0, 0x14, 0xE7, 0x77, 0xA2, 0xFE, 0x4B, 0x13, 0x6B, 0x56, 0xCD, 0x7E, 0xF7, 0xE9}, + new byte[] {0xC9, 0x35, 0x48, 0xCF, 0x55, 0x8D, 0x75, 0x03, 0x89, 0x6B, 0x2E, 0xEB, 0x61, 0x8C, 0xA9, 0x02}, + new byte[] {0xDE, 0x34, 0xC5, 0x41, 0xE7, 0xCA, 0x86, 0xE8, 0xBE, 0xA7, 0xC3, 0x1C, 0xEC, 0xE4, 0x36, 0x0F}, + new byte[] {0xDD, 0xE5, 0xFF, 0x55, 0x1B, 0x74, 0xF6, 0xF4, 0xE0, 0x16, 0xD7, 0xAB, 0x22, 0x31, 0x1B, 0x6A}, + new byte[] {0xB0, 0xE9, 0x35, 0x21, 0x33, 0x3F, 0xD7, 0xBA, 0xB4, 0x76, 0x2C, 0xCB, 0x4D, 0x80, 0x08, 0xD8}, + new byte[] {0x38, 0x14, 0x69, 0xC4, 0xC3, 0xF9, 0x1B, 0x96, 0x33, 0x63, 0x8E, 0x4D, 0x5F, 0x3D, 0xF0, 0x29}, + new byte[] {0xFA, 0x48, 0x6A, 0xD9, 0x8E, 0x67, 0x16, 0xEF, 0x6A, 0xB0, 0x87, 0xF5, 0x89, 0x45, 0x7F, 0x2A}, + new byte[] {0x32, 0x1A, 0x09, 0x12, 0x50, 0x14, 0x8A, 0x3E, 0x96, 0x3D, 0xEA, 0x02, 0x59, 0x32, 0xE1, 0x8F}, + new byte[] {0x4B, 0x00, 0xBE, 0x29, 0xBC, 0xB0, 0x28, 0x64, 0xCE, 0xFD, 0x43, 0xA9, 0x6F, 0xD9, 0x5C, 0xED}, + new byte[] {0x57, 0x7D, 0xC4, 0xFF, 0x02, 0x44, 0xE2, 0x80, 0x91, 0xF4, 0xCA, 0x0A, 0x75, 0x69, 0xFD, 0xA8}, + new byte[] {0x83, 0x53, 0x36, 0xC6, 0x18, 0x03, 0xE4, 0x3E, 0x4E, 0xB3, 0x0F, 0x6B, 0x6E, 0x79, 0x9B, 0x7A}, + new byte[] {0x5C, 0x92, 0x65, 0xFD, 0x7B, 0x59, 0x6A, 0xA3, 0x7A, 0x2F, 0x50, 0x9D, 0x85, 0xE9, 0x27, 0xF8}, + new byte[] {0x9A, 0x39, 0xFB, 0x89, 0xDF, 0x55, 0xB2, 0x60, 0x14, 0x24, 0xCE, 0xA6, 0xD9, 0x65, 0x0A, 0x9D}, + new byte[] {0x8B, 0x75, 0xBE, 0x91, 0xA8, 0xC7, 0x5A, 0xD2, 0xD7, 0xA5, 0x94, 0xA0, 0x1C, 0xBB, 0x95, 0x91}, + new byte[] {0x95, 0xC2, 0x1B, 0x8D, 0x05, 0xAC, 0xF5, 0xEC, 0x5A, 0xEE, 0x77, 0x81, 0x23, 0x95, 0xC4, 0xD7}, + new byte[] {0xB9, 0xA4, 0x61, 0x64, 0x36, 0x33, 0xFA, 0x5D, 0x94, 0x88, 0xE2, 0xD3, 0x28, 0x1E, 0x01, 0xA2}, + new byte[] {0xB8, 0xB0, 0x84, 0xFB, 0x9F, 0x4C, 0xFA, 0xF7, 0x30, 0xFE, 0x73, 0x25, 0xA2, 0xAB, 0x89, 0x7D}, + new byte[] {0x5F, 0x8C, 0x17, 0x9F, 0xC1, 0xB2, 0x1D, 0xF1, 0xF6, 0x36, 0x7A, 0x9C, 0xF7, 0xD3, 0xD4, 0x7C}, + }; + + public static readonly byte[] kirk1_key = { 0x98, 0xC9, 0x40, 0x97, 0x5C, 0x1D, 0x10, 0xE8, 0x7F, 0xE6, 0x0E, 0xA3, 0xFD, 0x03, 0xA8, 0xBA }; + public static readonly byte[] kirk16_key = { 0x47, 0x5E, 0x09, 0xF4, 0xA2, 0x37, 0xDA, 0x9B, 0xEF, 0xFF, 0x3B, 0xC0, 0x77, 0x14, 0x3D, 0x8A }; + + /* ECC Curves for Kirk 1 and Kirk 0x11 */ + // Common Curve paramters p and a + public static readonly byte[] ec_p = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + public static readonly byte[] ec_a = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC }; // mon + + // Kirk 0xC,0xD,0x10,0x11,(likely 0x12)- Unique curve parameters for b, N, and base point G for Kirk 0xC,0xD,0x10,0x11,(likely 0x12) service + // Since public key is variable, it is not specified here + public static readonly byte[] ec_b2 = { 0xA6, 0x8B, 0xED, 0xC3, 0x34, 0x18, 0x02, 0x9C, 0x1D, 0x3C, 0xE3, 0x3B, 0x9A, 0x32, 0x1F, 0xCC, 0xBB, 0x9E, 0x0F, 0x0B };// mon + public static readonly byte[] ec_N2 = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xB5, 0xAE, 0x3C, 0x52, 0x3E, 0x63, 0x94, 0x4F, 0x21, 0x27 }; + public static readonly byte[] Gx2 = { 0x12, 0x8E, 0xC4, 0x25, 0x64, 0x87, 0xFD, 0x8F, 0xDF, 0x64, 0xE2, 0x43, 0x7B, 0xC0, 0xA1, 0xF6, 0xD5, 0xAF, 0xDE, 0x2C }; + public static readonly byte[] Gy2 = { 0x59, 0x58, 0x55, 0x7E, 0xB1, 0xDB, 0x00, 0x12, 0x60, 0x42, 0x55, 0x24, 0xDB, 0xC3, 0x79, 0xD5, 0xAC, 0x5F, 0x4A, 0xDF }; + + // KIRK 1 - Unique curve parameters for b, N, and base point G + // Since public key is hard coded, it is also included + public static readonly byte[] ec_b1 = { 0x65, 0xD1, 0x48, 0x8C, 0x03, 0x59, 0xE2, 0x34, 0xAD, 0xC9, 0x5B, 0xD3, 0x90, 0x80, 0x14, 0xBD, 0x91, 0xA5, 0x25, 0xF9 }; + public static readonly byte[] ec_N1 = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0xB5, 0xC6, 0x17, 0xF2, 0x90, 0xEA, 0xE1, 0xDB, 0xAD, 0x8F }; + public static readonly byte[] Gx1 = { 0x22, 0x59, 0xAC, 0xEE, 0x15, 0x48, 0x9C, 0xB0, 0x96, 0xA8, 0x82, 0xF0, 0xAE, 0x1C, 0xF9, 0xFD, 0x8E, 0xE5, 0xF8, 0xFA }; + public static readonly byte[] Gy1 = { 0x60, 0x43, 0x58, 0x45, 0x6D, 0x0A, 0x1C, 0xB2, 0x90, 0x8D, 0xE9, 0x0F, 0x27, 0xD7, 0x5C, 0x82, 0xBE, 0xC1, 0x08, 0xC0 }; + + public static readonly byte[] Px1 = { 0xED, 0x9C, 0xE5, 0x82, 0x34, 0xE6, 0x1A, 0x53, 0xC6, 0x85, 0xD6, 0x4D, 0x51, 0xD0, 0x23, 0x6B, 0xC3, 0xB5, 0xD4, 0xB9 }; + public static readonly byte[] Py1 = { 0x04, 0x9D, 0xF1, 0xA0, 0x75, 0xC0, 0xE0, 0x4F, 0xB3, 0x44, 0x85, 0x8B, 0x61, 0xB7, 0x9B, 0x69, 0xA6, 0x3D, 0x2C, 0x39 }; + public static readonly byte[] ec_Priv1 = { 0xF3, 0x92, 0xE2, 0x64, 0x90, 0xB8, 0x0F, 0xD8, 0x89, 0xF2, 0xD9, 0x72, 0x2C, 0x1F, 0x34, 0xD7, 0x27, 0x4F, 0x98, 0x3D }; + + public static readonly byte[] Px2 = { 0x01, 0x21, 0xEA, 0x6E, 0xCD, 0xB2, 0x3A, 0x3E, 0x23, 0x75, 0x67, 0x1C, 0x53, 0x62, 0xE8, 0xE2, 0x8B, 0x1E, 0x78, 0x3B }; + public static readonly byte[] Py2 = { 0x1A, 0x27, 0x32, 0x15, 0x8B, 0x8C, 0xED, 0x98, 0x46, 0x6C, 0x18, 0xA3, 0xAC, 0x3B, 0x11, 0x06, 0xAF, 0xB4, 0xEC, 0x3B }; + public static readonly byte[] ec_Priv2 = { 0x14, 0xB0, 0x22, 0xE8, 0x92, 0xCF, 0x86, 0x14, 0xA4, 0x45, 0x57, 0xDB, 0x09, 0x5C, 0x92, 0x8D, 0xE9, 0xB8, 0x99, 0x70 }; + + public static readonly byte[] EdatPx = { 0x1F, 0x07, 0x2B, 0xCC, 0xC1, 0x62, 0xF2, 0xCF, 0xAE, 0xA0, 0xE7, 0xF4, 0xCD, 0xFD, 0x9C, 0xAE, 0xC6, 0xC4, 0x55, 0x21 }; + public static readonly byte[] EdatPy = { 0x53, 0x01, 0xF4, 0xE3, 0x70, 0xC3, 0xED, 0xE2, 0xD4, 0xF5, 0xDB, 0xC3, 0xA7, 0xDE, 0x8C, 0xAA, 0xE8, 0xAD, 0x5B, 0x7D }; + public static readonly byte[] EdatPirv = { 0xe5, 0xc4, 0xd0, 0xa8, 0x24, 0x9a, 0x6f, 0x27, 0xe5, 0xe0, 0xc9, 0xd5, 0x34, 0xf4, 0xda, 0x15, 0x22, 0x3f, 0x42, 0xad }; + + public static readonly byte[] Eboot_p = { 0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x53, 0x73, 0xD3, 0x79, 0xF6, 0x9D, 0xA2, 0x8D, 0x09, 0x99, 0x9F, 0xED, 0x57, 0xA9, 0x0F }; + public static readonly byte[] Eboot_a = { 0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x53, 0x73, 0xD3, 0x79, 0xF6, 0x9D, 0xA2, 0x8D, 0x09, 0x99, 0x9F, 0xED, 0x57, 0xA9, 0x0C }; + public static readonly byte[] Eboot_b = { 0x90, 0x65, 0x94, 0x1D, 0x29, 0x37, 0x4A, 0x8F, 0x11, 0xDD, 0x1E, 0x54, 0x01, 0x89, 0x43, 0x4E, 0x4A, 0x6E, 0xBF, 0xAF, 0x54, 0x77, 0xF6, 0xC1, 0x72, 0xF6, 0x85, 0x5E }; + public static readonly byte[] Eboot_N = { 0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x52, 0x26, 0x98, 0xDE, 0xEF, 0x58, 0xDB, 0x1A, 0xD9, 0xAB, 0x7F, 0x04, 0xE3, 0xAE, 0x7F }; + public static readonly byte[] Eboot_Gx = { 0x7E, 0x06, 0x09, 0x82, 0x47, 0xE6, 0xB5, 0x9F, 0x31, 0x10, 0xBC, 0xBB, 0x3A, 0xB6, 0xC2, 0x50, 0xBC, 0x5A, 0xB0, 0x6C, 0x03, 0x2D, 0xAD, 0x43, 0x68, 0x4C, 0x24, 0x8F }; + public static readonly byte[] Eboot_Gy = { 0x0B, 0xD9, 0x41, 0x8D, 0xE8, 0xE3, 0xE4, 0x5D, 0x2D, 0x70, 0x1E, 0x02, 0x37, 0xFD, 0x7F, 0x2A, 0xDE, 0x0D, 0x48, 0xB7, 0x4C, 0xEE, 0xF2, 0xF1, 0xC8, 0xAC, 0x48, 0x4E }; + public static readonly byte[] Eboot_pub1x = { 0x5F, 0x9D, 0x17, 0x1A, 0x2B, 0xDD, 0xA8, 0xD4, 0x08, 0x78, 0xBF, 0x98, 0x5A, 0xC3, 0x26, 0xED, 0x5E, 0xFF, 0x43, 0xC9, 0x37, 0x6C, 0x77, 0xEC, 0x0A, 0x00, 0xC7, 0xBB }; + public static readonly byte[] Eboot_pub1y = { 0xA3, 0x44, 0xE4, 0x4E, 0x6E, 0xAC, 0x25, 0x52, 0x35, 0xF9, 0x54, 0xF5, 0xB6, 0x17, 0xC7, 0xBD, 0x49, 0xF1, 0x80, 0x26, 0x24, 0x54, 0xAA, 0xE1, 0xB6, 0x2A, 0x9F, 0x2C }; + public static readonly byte[] Eboot_priv1 = { 0x76, 0x74, 0x36, 0xA6, 0x99, 0x9D, 0x88, 0x48, 0x0E, 0xC8, 0x56, 0xF5, 0x5C, 0xEA, 0xBB, 0x43, 0x96, 0x85, 0x9E, 0x37, 0x45, 0x99, 0x40, 0x39, 0x21, 0xF5, 0x55, 0x98 }; + public static readonly byte[] Eboot_pub2x = { 0x67, 0x00, 0x2D, 0x9B, 0xB8, 0xE4, 0x2D, 0x2B, 0xF9, 0x61, 0x0B, 0x27, 0xFE, 0xAB, 0x9B, 0x34, 0x56, 0x15, 0x50, 0x92, 0x13, 0x12, 0xDF, 0xEE, 0x7A, 0x3A, 0x86, 0xEC }; + public static readonly byte[] Eboot_pub2y = { 0x6C, 0xA7, 0x14, 0x42, 0x6F, 0x6D, 0x4E, 0x96, 0x09, 0xA6, 0x38, 0xBF, 0x4A, 0xFB, 0x18, 0x2B, 0xFA, 0x50, 0xC8, 0x2F, 0xF2, 0xB4, 0xC5, 0xEC, 0x6C, 0xCD, 0x97, 0x65 }; + public static readonly byte[] Eboot_priv2 = { 0x60, 0x7A, 0x2E, 0x55, 0x68, 0xB4, 0xB9, 0xA0, 0x32, 0xF4, 0x52, 0x53, 0xCF, 0xED, 0x20, 0xDB, 0x2E, 0x6E, 0x44, 0x6C, 0x37, 0x82, 0xE8, 0x2A, 0x1A, 0xB9, 0xC9, 0x23 }; + public static readonly byte[][] Eboot_priv = { Eboot_priv1, Eboot_priv2 }; + public static readonly byte[][] Eboot_pubx = { Eboot_pub1x, Eboot_pub2x }; + public static readonly byte[][] Eboot_puby = { Eboot_pub1y, Eboot_pub2y }; + + public static readonly byte[] Eboot_hmacKey = { 0x54, 0x88, 0xA9, 0x81, 0x1C, 0x9A, 0x2C, 0xBC, 0xCC, 0x59, 0x6B, 0x1F, 0xAD, 0x1A, 0x7E, 0x29, 0xE0, 0x75, 0x84, 0x0F, 0x47, 0x43, 0x1F, 0x37, 0xAC, 0x06, 0x02, 0x46, 0x4A, 0x27, 0x9E, 0x02, 0xDF, 0x2E, 0x71, 0x65, 0xF1, 0x13, 0x7B, 0xF6, 0x9A, 0xE6, 0xDC, 0xB9, 0xDC, 0x38, 0x8C, 0x9D, 0xCC, 0xB3, 0x64, 0xC4, 0xCA, 0x26, 0xCB, 0x8F, 0x1A, 0xF0, 0x63, 0x8A, 0x6E, 0xAD, 0xB5, 0x4D }; + + + public static readonly byte[] VitaKirk18PubKey0x = { 0x5F, 0x9D, 0x17, 0x1A, 0x2B, 0xDD, 0xA8, 0xD4, 0x08, 0x78, 0xBF, 0x98, 0x5A, 0xC3, 0x26, 0xED, 0x5E, 0xFF, 0x43, 0xC9, 0x37, 0x6C, 0x77, 0xEC, 0x0A, 0x00, 0xC7, 0xBB }; + public static readonly byte[] VitaKirk18PubKey0y = { 0xA3, 0x44, 0xE4, 0x4E, 0x6E, 0xAC, 0x25, 0x52, 0x35, 0xF9, 0x54, 0xF5, 0xB6, 0x17, 0xC7, 0xBD, 0x49, 0xF1, 0x80, 0x26, 0x24, 0x54, 0xAA, 0xE1, 0xB6, 0x2A, 0x9F, 0x2C }; + + public static readonly byte[] VitaKirk18PubKey1x = { 0x67, 0x00, 0x2D, 0x9B, 0xB8, 0xE4, 0x2D, 0x2B, 0xF9, 0x61, 0x0B, 0x27, 0xFE, 0xAB, 0x9B, 0x34, 0x56, 0x15, 0x50, 0x92, 0x13, 0x12, 0xDF, 0xEE, 0x7A, 0x3A, 0x86, 0xEC }; + public static readonly byte[] VitaKirk18PubKey1y = { 0x6C, 0xA7, 0x14, 0x42, 0x6F, 0x6D, 0x4E, 0x96, 0x09, 0xA6, 0x38, 0xBF, 0x4A, 0xFB, 0x18, 0x2B, 0xFA, 0x50, 0xC8, 0x2F, 0xF2, 0xB4, 0xC5, 0xEC, 0x6C, 0xCD, 0x97, 0x65 }; + + public static readonly byte[] VitaKirk18PubKey1000x = { 0x64, 0xDD, 0xD3, 0x1E, 0x46, 0x7A, 0x90, 0x8F, 0x99, 0x0D, 0x63, 0xF4, 0x59, 0x32, 0x3C, 0x1C, 0xA3, 0xCE, 0xCF, 0x00, 0xA8, 0x1C, 0x57, 0x40, 0xA9, 0x6D, 0x2E, 0x1C }; + public static readonly byte[] VitaKirk18PubKey1000y = { 0x38, 0x61, 0xA1, 0x9D, 0x0A, 0xBD, 0xC5, 0xED, 0xDB, 0xD6, 0x04, 0xFA, 0x67, 0xC6, 0xDA, 0xB4, 0x28, 0x3C, 0x29, 0x67, 0x86, 0xD9, 0xA8, 0x07, 0xE0, 0xC1, 0x3B, 0xA8 }; + + public static readonly byte[] drmActRifSig = + { + 0x62, 0x27, 0xB0, 0x0A, 0x02, 0x85, 0x6F, 0xB0, + 0x41, 0x08, 0x87, 0x67, 0x19, 0xE0, 0xA0, 0x18, + 0x32, 0x91, 0xEE, 0xB9, 0x6E, 0x73, 0x6A, 0xBF, + 0x81, 0xF7, 0x0E, 0xE9, 0x16, 0x1B, 0x0D, 0xDE, + 0xB0, 0x26, 0x76, 0x1A, 0xFF, 0x7B, 0xC8, 0x5B + }; + + public static readonly byte[] drmRifKey = { 0xDA, 0x7D, 0x4B, 0x5E, 0x49, 0x9A, 0x4F, 0x53, 0xB1, 0xC1, 0xA1, 0x4A, 0x74, 0x84, 0x44, 0x3B }; + + public static readonly byte[] drmActdatKey = { 0x5E, 0x06, 0xE0, 0x4F, 0xD9, 0x4A, 0x71, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + + public static readonly byte[] drmVersionKeyKey = + { + 0xF0, 0x79, 0xD5, 0x19, 0x8F, 0x23, 0xEF, 0xCE, + 0xB5, 0x4B, 0x9E, 0xCD, 0xCD, 0xFD, 0xD3, 0xD7, + 0x07, 0x3D, 0x9E, 0x9D, 0xA8, 0xFD, 0x3B, 0x2F, + 0x63, 0x18, 0x93, 0x2E, 0xF8, 0x57, 0xA6, 0x64, + 0x37, 0x49, 0xB7, 0x01, 0xCA, 0xE2, 0xE0, 0xC5, + 0x44, 0x2E, 0x06, 0xB6, 0x1E, 0xFF, 0x84, 0xF2, + 0x9D, 0x31, 0xB8, 0x5A, 0xC8, 0xFA, 0x16, 0x80, + 0x73, 0x60, 0x18, 0x82, 0x18, 0x77, 0x91, 0x9D, + + }; + + public static readonly byte[] DrmFixedKey = { 0x38, 0x20, 0xD0, 0x11, 0x07, 0xA3, 0xFF, 0x3E, 0x0A, 0x4C, 0x20, 0x85, 0x39, 0x10, 0xB5, 0x54 }; + } +} diff --git a/PspCrypto/Libraries.cs b/PspCrypto/Libraries.cs new file mode 100644 index 0000000..ea48f77 --- /dev/null +++ b/PspCrypto/Libraries.cs @@ -0,0 +1,8 @@ +using System; +using System.Collections.Generic; +using System.Text; + +internal static class Libraries +{ + internal const string CryptoNative = "PspCryptoHelper"; +} diff --git a/PspCrypto/Lz.cs b/PspCrypto/Lz.cs new file mode 100644 index 0000000..5e7661e --- /dev/null +++ b/PspCrypto/Lz.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text; + +namespace PspCrypto +{ + public class Lz + { + public static byte[] compress(byte[] in_buf, bool np9660=false) + { + //Decoder decoder = new Decoder(); + //using var inStream = new MemoryStream(@in); + //using var outStream = new MemoryStream(@out); + //byte[] properties = new byte[5]; + //inStream.Read(properties, 0, 5); + //decoder.SetDecoderProperties(properties); + //decoder.Code(inStream, outStream, insize, size, null); + //return 0; + var lzrc = new Lzrc(np9660); + + // compress data, and get the compressed data length + return lzrc.lzrc_compress(in_buf, in_buf.Length); + } + public static int decompress(byte[] @out, byte[] @in, int size, int insize, bool np9660=false) + { + //Decoder decoder = new Decoder(); + //using var inStream = new MemoryStream(@in); + //using var outStream = new MemoryStream(@out); + //byte[] properties = new byte[5]; + //inStream.Read(properties, 0, 5); + //decoder.SetDecoderProperties(properties); + //decoder.Code(inStream, outStream, insize, size, null); + //return 0; + var lzrc = new Lzrc(np9660); + lzrc.lzrc_decompress(@out, size, @in, insize); + return 0; + } + } +} diff --git a/PspCrypto/Lzrc.cs b/PspCrypto/Lzrc.cs new file mode 100644 index 0000000..9f5cfb3 --- /dev/null +++ b/PspCrypto/Lzrc.cs @@ -0,0 +1,908 @@ +using System; +using System.Collections.Generic; +using System.Net.NetworkInformation; +using System.Text; + +namespace PspCrypto +{ + public class Lzrc + { + private bool np9660; + + private byte[] input; + private int in_ptr; + private int in_len; + + private byte[] output; + private int out_ptr; + private int out_len; + + private uint range; + private uint code; + private uint out_code; + private byte lc; + private byte[][] bm_literal; + private byte[][] bm_dist_bits; + private byte[][] bm_dist; + private byte[][] bm_match; + private byte[][] bm_len; + + const int MAX_WIN_SZ = 16384; + const int MAX_TBL_SZ = 65280; + const int TBL_SZ = 65536; + + private byte[] text_buf = new byte[TBL_SZ]; + private int t_start, t_end, t_fill, sp_fill; + private int t_len, t_pos; + + private int[] prev = new int[TBL_SZ], next = new int[TBL_SZ]; + private int[] root = new int[TBL_SZ]; + + public Lzrc(bool np9660 = false) + { + this.np9660 = np9660; + + if (np9660) + { + this.bm_literal = new byte[8][]; + this.bm_dist_bits = new byte[8][]; + this.bm_dist = new byte[18][]; + this.bm_match = new byte[8][]; + this.bm_len = new byte[8][]; + } + else + { + this.bm_literal = new byte[8][]; + this.bm_dist_bits = new byte[8][]; + this.bm_dist = new byte[16][]; + this.bm_match = new byte[8][]; + this.bm_len = new byte[8][]; + } + } + + static void Init(byte[][] arr, byte value, int length) + { + for (int i = 0; i < arr.Length; i++) + { + arr[i] = new byte[length]; + for (int j = 0; j < length; j++) + { + arr[i][j] = value; + } + } + } + + private byte rc_getbyte() + { + if (in_ptr == in_len) + { + throw new Exception("End of input!"); + } + + return input[in_ptr++]; + } + + void rc_putbyte(byte b) + { + if (out_ptr == out_len) + { + throw new Exception("Output overflow!"); + } + + output[out_ptr++] = b; + } + + void re_init(ref byte[] in_buf, int in_len) + { + input = in_buf; + this.in_len = in_len; + in_ptr = 0; + + this.output = new byte[in_len]; + this.out_len = in_len; + out_ptr = 0; + + range = 0xffffffff; + code = 0x00000000; + lc = 5; + out_code = 0xffffffff; + + re_putbyte(lc); + + + if (this.np9660) + { + Init(bm_literal, 0x80, 256); + Init(bm_dist_bits, 0x80, 39); + Init(bm_dist, 0x80, 8); + Init(bm_match, 0x80, 8); + Init(bm_len, 0x80, 31); + } + else + { + Init(bm_literal, 0x80, 256); // 2048 2680 2656 + Init(bm_dist_bits, 0x80, 23); // 184 + Init(bm_dist, 0x80, 8); // 128 + Init(bm_match, 0x80, 8); // 64 + Init(bm_len, 0x80, 32); // 256 + + } + //memset(re->bm_literal, 0x80, 2048); + //memset(re->bm_dist_bits, 0x80, 312); + //memset(re->bm_dist, 0x80, 144); + //memset(re->bm_match, 0x80, 64); + //memset(re->bm_len, 0x80, 248); + } + + void rc_init(byte[] out_buf, int out_len, byte[] in_buf, int in_len) + { + input = in_buf; + this.in_len = in_len; + in_ptr = 0; + + output = out_buf; + this.out_len = out_len; + out_ptr = 0; + + range = 0xffffffff; + lc = rc_getbyte(); + code = (uint)((rc_getbyte() << 24) | + (rc_getbyte() << 16) | + (rc_getbyte() << 8) | + rc_getbyte()); + out_code = 0xffffffff; + + if (this.np9660) + { + Init(bm_literal, 0x80, 256); + Init(bm_dist_bits, 0x80, 39); + Init(bm_dist, 0x80, 8); + Init(bm_match, 0x80, 8); + Init(bm_len, 0x80, 31); + } + else + { + Init(bm_literal, 0x80, 256); // 2048 2680 2656 + Init(bm_dist_bits, 0x80, 23); // 184 + Init(bm_dist, 0x80, 8); // 128 + Init(bm_match, 0x80, 8); // 64 + Init(bm_len, 0x80, 32); // 256 + + } + + } + + void normalize() + { + if (range < 0x01000000) + { + range <<= 8; + code = (code << 8) + input[in_ptr]; + in_ptr++; + } + } + + int rc_bit(byte[] probs, int index) + { + uint bound; + + normalize(); + + bound = (range >> 8) * probs[index]; + probs[index] -= (byte)(probs[index] >> 3); + + if (code < bound) + { + range = bound; + probs[index] += 31; + return 1; + } + else + { + code -= bound; + range -= bound; + return 0; + } + } + + int rc_bittree(byte[] probs, int index, int limit) + { + int number = 1; + do + { + number = (number << 1) + rc_bit(probs, index + number); + } while (number < limit); + + number -= limit; + + return number; + } + + int rc_number(byte[] prob, int index, int n) + { + int i, number = 1; + + if (n > 3) + { + number = (number << 1) + rc_bit(prob, index + 3); + if (n > 4) + { + number = (number << 1) + rc_bit(prob, index + 3); + } + + if (n > 5) + { + normalize(); + for (i = 0; i < n - 5; i++) + { + range >>= 1; + number <<= 1; + if (code < range) + { + number += 1; + } + else + { + code -= range; + } + } + } + } + + if (n > 0) + { + number = (number << 1) + rc_bit(prob, index + 0); + if (n > 1) + { + number = (number << 1) + rc_bit(prob, index + 1); + if (n > 2) + { + number = (number << 1) + rc_bit(prob, index + 2); + } + } + } + + return number; + } + + public void init_tree() + { + int i; + + for (i = 0; i < TBL_SZ; i++) + { + root[i] = -1; + prev[i] = -1; + next[i] = -1; + } + + t_start = 0; + t_end = 0; + t_fill = 0; + sp_fill = 0; + } + + void fill_buffer() + { + //void *memcpy(void *dest, const void * src, size_t n) + + int content_size, back_size, front_size; + + if (sp_fill == in_len) + return; + + content_size = (t_fill < t_end) ? (MAX_TBL_SZ + t_fill - t_end) : (t_fill - t_end); + if (content_size >= 509) + return; + + if (t_fill < t_start) + { + back_size = t_start - t_fill - 1; + if (sp_fill + back_size > in_len) + back_size = in_len - sp_fill; + + Array.ConstrainedCopy(input, sp_fill, text_buf, t_fill, back_size); + // memcpy(text_buf + t_fill, re->input + sp_fill, back_size); + + sp_fill += back_size; + t_fill += back_size; + } + else + { + back_size = MAX_TBL_SZ - t_fill; + if (t_start == 0) + back_size -= 1; + if (sp_fill + back_size > in_len) + back_size = in_len - sp_fill; + + Array.ConstrainedCopy(input, sp_fill, text_buf, t_fill, back_size); + //memcpy(text_buf + t_fill, re->input + sp_fill, back_size); + + sp_fill += back_size; + t_fill += back_size; + + front_size = t_start; + if (t_start != 0) + front_size -= 1; + if (sp_fill + front_size > in_len) + front_size = in_len - sp_fill; + + Array.ConstrainedCopy(input, sp_fill, text_buf, 0, front_size); + //memcpy(text_buf, re->input + sp_fill, front_size); + + sp_fill += front_size; + + Array.ConstrainedCopy(text_buf, 255, text_buf, MAX_TBL_SZ, front_size); + //memcpy(text_buf + max_tbl_sz, text_buf, 255); + + t_fill += front_size; + if (t_fill >= MAX_TBL_SZ) + t_fill -= MAX_TBL_SZ; + } + } + void remove_node(int p) + { + int t, q; + + if (prev[p] == -1) + return; + + t = text_buf[p + 0]; + t = (t << 8) | text_buf[p + 1]; + + q = next[p]; + if (q != -1) + prev[q] = prev[p]; + + if (prev[p] == -2) + root[t] = q; + else + next[prev[p]] = q; + + prev[p] = -1; + next[p] = -1; + } + + int insert_node(int pos, out int match_len, out int match_dist, int do_cmp) + { + //Span src, win; + int i, t, p; + int content_size; + + //src = text_buf[pos..]; + //win = text_buf[t_start..]; + content_size = (t_fill < pos) ? (MAX_TBL_SZ + t_fill - pos) : (t_fill - pos); + t_len = 1; + t_pos = 0; + match_len = t_len; + match_dist = t_pos; + + if (in_ptr >= in_len) + { + match_len = 256; + return 0; + } + + if (in_ptr >= (in_len - 1)) + return 0; + + t = text_buf[pos]; + t = (t << 8) | text_buf[pos+1]; + if (root[t] == -1) + { + root[t] = pos; + prev[pos] = -2; + next[pos] = -1; + return 0; + } + + p = root[t]; + root[t] = pos; + prev[pos] = -2; + next[pos] = p; + + if (p != -1) + prev[p] = pos; + + while (do_cmp == 1 && p != -1) + { + for (i = 0; (i < 255 && i < content_size); i++) + { + if (text_buf[pos+i] != text_buf[p + i]) + break; + } + + if (i > t_len) + { + t_len = i; + t_pos = pos - p; + } + else if (i == t_len) + { + int mp = pos - p; + if (mp < 0) + mp += MAX_TBL_SZ; + if (mp < t_pos) + { + t_len = i; + t_pos = pos - p; + } + } + if (i == 255) + { + remove_node(p); + break; + } + + p = next[p]; + } + + if (this.np9660) + { + // have we calculated match_dist of 256 when its not the end? + if (t_len == 256 && in_ptr < in_len) + return 1; + } + if (t_pos < 0) throw new Exception("t_pos was < 0 :?"); // TODO: figure out why this happens on np9660. + + match_len = t_len; + match_dist = t_pos; + + return 1; + } + void update_tree(int length) + { + int i, win_size; + int tmp_len, tmp_pos; + + win_size = (t_end >= t_start) ? (t_end - t_start) : (MAX_TBL_SZ + t_end - t_start); + + for (i = 0; i < length; i++) + { + if (win_size == MAX_WIN_SZ) + { + remove_node(t_start); + t_start += 1; + if (t_start == MAX_TBL_SZ) + t_start = 0; + } + else + { + win_size += 1; + } + + if (i > 0) + { + insert_node(t_end, out tmp_len, out tmp_pos, 0); + } + t_end += 1; + if (t_end >= MAX_TBL_SZ) + t_end -= MAX_TBL_SZ; + } + } + void re_bittree(ref byte[] probs,int index, int limit, int number) + { + int n, tmp, bit; + + number += limit; + + // Get total bits used by number + tmp = number; + n = 0; + while (tmp > 1) + { + tmp >>= 1; + n++; + } + + do + { + tmp = number >> n; + bit = (number >> (n - 1)) & 1; + re_bit(ref probs, index + tmp, bit); + n -= 1; + } while (n > 0); + } + + void re_bit(ref byte[] prob, int index, int bit) + { + uint bound; + uint old_r, old_c; + byte old_p; + + re_normalize(); + + old_r = range; + old_c = code; + old_p = prob[index]; + + var pProb = prob[index]; + + bound = (range >> 8) * (pProb); + pProb -= (byte)(pProb >> 3); + + if (bit != 0) + { + range = bound; + pProb += 31; + } + else + { + code += bound; + if (code < old_c) + out_code += 1; + range -= bound; + } + + prob[index] = pProb; + } + + void re_normalize() + { + if (range < 0x01000000) + { + if (out_code != 0xffffffff) + { + if (out_code > 255) + { + int p, old_c; + p = out_ptr - 1; + do + { + old_c = output[p]; + output[p] += 1; + p -= 1; + } while (old_c == 0xff); + } + + re_putbyte((byte)(out_code & 0xff)); + } + out_code = (code >> 24) & 0xff; + range <<= 8; + code <<= 8; + } + } + + void re_putbyte(byte out_byte) + { + if (out_ptr == out_len) + { + out_len += 0x1000; + Array.Resize(ref output, out_len); + } + + output[out_ptr++] = out_byte; + } + byte re_getbyte() + { + if (in_ptr == in_len) + { + throw new Exception("End of input!"); + } + + return input[in_ptr++]; + } + + void re_number(ref byte[] prob, int index, int n, int number) + { + int i; + UInt32 old_c; + + i = 1; + + if (n > 3) + { + re_bit(ref prob, index + 3,(number >> (n - i)) & 1); + i += 1; + if (n > 4) + { + re_bit(ref prob, index + 3, (number >> (n - i)) & 1); + i += 1; + if (n > 5) + { + re_normalize(); + for (i = 3; i < n - 2; i++) + { + range >>= 1; + if (((number >> (n - i)) & 1) == 0) + { + old_c = code; + code += range; + if (code < old_c) + out_code += 1; + } + } + } + } + } + + if (n > 0) + { + re_bit(ref prob, index + 0, (number >> (n - i - 0)) & 1); + if (n > 1) + { + re_bit(ref prob, index + 1, (number >> (n - i - 1)) & 1); + if (n > 2) + { + re_bit(ref prob, index + 2, (number >> (n - i - 2)) & 1); + } + } + } + } + void re_flush() + { + re_putbyte((byte)((out_code) & 0xff)); + re_putbyte((byte)((code >> 24) & 0xff)); + re_putbyte((byte)((code >> 16) & 0xff)); + re_putbyte((byte)((code >> 8) & 0xff)); + re_putbyte((byte)((code >> 0) & 0xff)); + } + + private byte[] re_trunc() + { + Array.Resize(ref output, out_ptr); + return output; + } + + public byte[] lzrc_compress(byte[] in_buf, int in_len) + { + int match_step, re_state, len_state, dist_state; + int i, cur_byte, last_byte; + int match_len, len_bits; + int match_dist, dist_bits, limit; + int round = -1; + + // initalize buffers to all 0x80 + re_init(ref in_buf, in_len); + + // initalize the tree + init_tree(); + + // initalize variable to 0 ... + re_state = 0; + last_byte = 0; + match_len = 0; + match_dist = 0; + + bool flg = false; + + while (true) + { + round += 1; + match_step = 0; + + fill_buffer(); + insert_node(t_end, out match_len, out match_dist, 1); + + if (match_len < 256) + { + // condition is different if np9660 vs pops + if (this.np9660) + flg = (match_len < 4 && match_dist > 255); + else + flg = (match_len <= 4 && match_dist > 255); + + if(flg) // if (condition) + match_len = 1; + update_tree(match_len); + } + + // condition is different if np9660 vs pops + if (this.np9660) + flg = (match_len == 1 || (match_len < 4 && match_dist > 255)); + else + flg = (match_len == 1 || (match_len <= 4 && match_dist > 255)); + + if (flg) + { + re_bit(ref bm_match[re_state], match_step, 0); + + if (re_state > 0) + re_state -= 1; + + cur_byte = re_getbyte(); + re_bittree(ref bm_literal[((last_byte >> lc) & 0x07)], 0, 0x100, cur_byte); + + if (!this.np9660 && in_ptr >= in_len) + { + re_normalize(); + re_flush(); + return re_trunc(); + } + } + else + { + re_bit(ref bm_match[re_state], match_step, 1); + + // write bitstream length (8 bits, where 0 marks the end of it) + len_bits = 0; + for (i = 1; i < 8; i++) + { + match_step += 1; + if ((match_len - 1) < (1 << i)) + break; + re_bit(ref bm_match[re_state], match_step, 1); + len_bits += 1; + } + if (i != 8) + re_bit(ref bm_match[re_state], match_step, 0); + + if (len_bits > 0) + { + len_state = ((len_bits - 1) << 2) + ((in_ptr << (len_bits - 1)) & 0x03); + re_number(ref bm_len[re_state], len_state, len_bits, (match_len - 1)); + + if (this.np9660) + flg = (match_len == 256); + else + flg = (in_ptr >= in_len); + + if (flg) + { + re_normalize(); + re_flush(); + return re_trunc(); + } + } + + // determine limit ... + dist_state = 0; + limit = 8; + + // condition is different if np9660 vs pops + if (this.np9660) + flg = (match_len > 3); + else + flg = (match_len > 4); + + + if (flg) // if (condition) + { + dist_state += 7; + + if (this.np9660) + { + limit = 44; + } + else + { + limit = 16; + } + + } + + // find total 1s in the match_dist + dist_bits = 0; + if(match_dist > 0) { + while ((match_dist >> dist_bits) != 1) + { + dist_bits += 1; + } + } + else + { + throw new Exception("Match dist is 0.. uhh cant match with yourself.."); + } + + re_bittree(ref bm_dist_bits[len_bits], dist_state, limit, dist_bits); + + if (dist_bits > 0) + re_number(ref bm_dist[dist_bits], 0, dist_bits, match_dist); + + + in_ptr += match_len; + re_state = 6 + ((in_ptr + 1) & 1); + } + last_byte = input[in_ptr - 1]; + } + + } + + public int lzrc_decompress(byte[] out_buf, int out_len, byte[] in_buf, int in_len) + { + int match_step, rc_state, len_state, dist_state = 0; + int i, bit, cur_byte, last_byte; + int match_len, len_bits; + int match_dist, dist_bits, limit; + int match_src; + int round = -1; + + bool flg = false; + len_state = 0; + + rc_init(out_buf, out_len, in_buf, in_len); + + /*if ((lc & 0x80) != 0) + { + Buffer.BlockCopy(in_buf, 5, out_buf, 0, (int)code); + return (int)code; + }*/ + + rc_state = 0; + last_byte = 0; + + while (true) + { + round += 1; + match_step = 0; + bit = rc_bit(bm_match[rc_state], match_step); + // if bit is 0, just copy from the bit tree into the output ? + if (bit == 0) + { + if (rc_state > 0) + rc_state -= 1; + + cur_byte = rc_bittree(bm_literal[(((out_ptr & 7) << 8) + last_byte >> lc) & 0x07], 0, 0x100); + + rc_putbyte((byte)cur_byte); + if (out_ptr == out_len) return out_ptr; + } + else // This essentially goes; "hey the bytes that go here, are the same ones that were already *here* + { + // Determine bit length? + len_bits = 0; + for (i = 0; i < 7; i++) + { + match_step += 1; + bit = rc_bit(bm_match[rc_state], match_step); + if (bit == 0) + break; + len_bits += 1; + } + + // Get the match length .. + if (len_bits == 0) + { + match_len = 1; + } + else + { + len_state = ((len_bits - 1) << 2) + ((out_ptr << (len_bits - 1)) & 0x03); + match_len = rc_number(bm_len[rc_state], len_state, len_bits); + if (this.np9660 && match_len == 0xFF) + return out_ptr; + } + + dist_state = 0; + limit = 8; + if (this.np9660) + flg = (match_len > 2); + else + flg = (match_len > 3); + + if (flg) + { + dist_state += 7; + if (this.np9660) + limit = 44; + else + limit = 16; + } + dist_bits = rc_bittree(bm_dist_bits[len_bits], dist_state, limit); + + if (dist_bits > 0) + match_dist = rc_number(bm_dist[dist_bits], 0, dist_bits); + else + match_dist = 1; + + match_src = out_ptr - match_dist; + if (match_dist > out_ptr || match_dist < 0) + { + //Console.WriteLine($"match_dist out of range! 0x{match_dist:x8}"); + //return -1; // test + throw new Exception($"match_dist out of range! 0x{match_dist:x8}"); + } + + + for (i = 0; i < match_len + 1; i++) + { + rc_putbyte(output[match_src++]); + } + rc_state = 6 + ((out_ptr + 1) & 1); + if (out_ptr == out_len) return out_ptr; + } + last_byte = output[out_ptr - 1]; + } + } + } +} diff --git a/PspCrypto/PspCrypto.csproj b/PspCrypto/PspCrypto.csproj new file mode 100644 index 0000000..12d46cb --- /dev/null +++ b/PspCrypto/PspCrypto.csproj @@ -0,0 +1,29 @@ + + + + net6.0 + true + + + + + + + + + + + True + True + Resource.resx + + + + + + ResXFileCodeGenerator + Resource.Designer.cs + + + + diff --git a/PspCrypto/PspParameter.cs b/PspCrypto/PspParameter.cs new file mode 100644 index 0000000..0102eb6 --- /dev/null +++ b/PspCrypto/PspParameter.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ECDsaTest +{ + internal class PspParameter + { + public byte[] Kinv { get; set; } + public byte[] Rp { get; set; } + } +} diff --git a/PspCrypto/Resource.Designer.cs b/PspCrypto/Resource.Designer.cs new file mode 100644 index 0000000..7da05f0 --- /dev/null +++ b/PspCrypto/Resource.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PspCrypto { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resource { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PspCrypto.Resource", typeof(Resource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] @__sce_discinfo { + get { + object obj = ResourceManager.GetObject("__sce_discinfo", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/PspCrypto/Resource.resx b/PspCrypto/Resource.resx new file mode 100644 index 0000000..ac10a00 --- /dev/null +++ b/PspCrypto/Resource.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + __sce_discinfo;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/PspCrypto/SceDdrdb.cs b/PspCrypto/SceDdrdb.cs new file mode 100644 index 0000000..dacd1c7 --- /dev/null +++ b/PspCrypto/SceDdrdb.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; + +namespace PspCrypto +{ + public static class SceDdrdb + { + public static int sceDdrdbHash(ReadOnlySpan src, int size, Span digest) + { + SHA1.HashData(src[..size], digest); + return 0; + } + + public static int sceDdrdbSigvry(ReadOnlySpan pubKey, ReadOnlySpan hash, ReadOnlySpan sig) + { + Span buff = stackalloc byte[Marshal.SizeOf()]; + ref KIRKEngine.KIRK_CMD17_BUFFER buffer = ref MemoryMarshal.AsRef(buff); + pubKey[..0x28].CopyTo(buffer.public_key.point); + hash[..20].CopyTo(buffer.message_hash); + sig[..0x28].CopyTo(buffer.signature.sig); + return KIRKEngine.sceUtilsBufferCopyWithRange(null, 0, buff, 100, KIRKEngine.KIRK_CMD_ECDSA_VERIFY); + } + } +} diff --git a/PspCrypto/SceMemlmd.cs b/PspCrypto/SceMemlmd.cs new file mode 100644 index 0000000..ea3205c --- /dev/null +++ b/PspCrypto/SceMemlmd.cs @@ -0,0 +1,513 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace PspCrypto +{ + public static class SceMemlmd + { + private static readonly Memory MemlmdKirkMemory = new byte[0x150]; // DAT_00002604 + private static readonly Memory MemlmdMem_BFC00000 = new byte[0x3000]; + private static readonly Memory MemlmdMem_BFC00280 = MemlmdMem_BFC00000.Slice(0x280, 0xC0); + private static readonly Memory MemlmdMem_BFC00340 = MemlmdMem_BFC00000.Slice(0x340, 0x300); + private static readonly Memory MemlmdMem_BFC00A00 = MemlmdMem_BFC00000.Slice(0xA00, 0x200); + private static readonly Memory MemlmdMem_2780 = new byte[0x200]; + + private static readonly byte[] key7A90 = + { + 0x77, 0x3F, 0x4B, 0xE1, 0x4C, 0x0A, 0xB4, 0x52, 0x67, 0x2B, 0x67, 0x56, 0x82, 0x4C, 0xCF, 0x42, + 0xAA, 0x37, 0xFF, 0xC0, 0x89, 0x41, 0xE5, 0x63, 0x5E, 0x84, 0xE9, 0xFB, 0x53, 0xDA, 0x94, 0x9E, + 0x9B, 0xB7, 0xC2, 0xA4, 0x22, 0x9F, 0xDF, 0x1F + }; + internal static readonly byte[] key_4C940AF0 = { 0xA8, 0xB1, 0x47, 0x77, 0xDC, 0x49, 0x6A, 0x6F, 0x38, 0x4C, 0x4D, 0x96, 0xBD, 0x49, 0xEC, 0x9B }; + internal static readonly byte[] key_4C940BF0 = { 0x3B, 0x9B, 0x1A, 0x56, 0x21, 0x80, 0x14, 0xED, 0x8E, 0x8B, 0x08, 0x42, 0xFA, 0x2C, 0xDC, 0x3A }; + internal static readonly byte[] key_4C9410F0 = { 0x31, 0x1F, 0x98, 0xD5, 0x7B, 0x58, 0x95, 0x45, 0x32, 0xAB, 0x3A, 0xE3, 0x89, 0x32, 0x4B, 0x34 }; + internal static readonly byte[] key_4C9412F0 = { 0x26, 0x38, 0x0A, 0xAC, 0xA5, 0xD8, 0x74, 0xD1, 0x32, 0xB7, 0x2A, 0xBF, 0x79, 0x9E, 0x6D, 0xDB }; + internal static readonly byte[] key_4C9413F0 = { 0x53, 0xE7, 0xAB, 0xB9, 0xC6, 0x4A, 0x4B, 0x77, 0x92, 0x17, 0xB5, 0x74, 0x0A, 0xDA, 0xA9, 0xEA }; + internal static readonly byte[] key_4C9414F0 = { 0x45, 0xEF, 0x5C, 0x5D, 0xED, 0x81, 0x99, 0x84, 0x12, 0x94, 0x8F, 0xAB, 0xE8, 0x05, 0x6D, 0x7D }; + internal static readonly byte[] key_4C9415F0 = { 0x70, 0x1B, 0x08, 0x25, 0x22, 0xA1, 0x4D, 0x3B, 0x69, 0x21, 0xF9, 0x71, 0x0A, 0xA8, 0x41, 0xA9 }; + internal static readonly byte[] key_4C949AF0 = { 0x48, 0x58, 0xAA, 0x38, 0x78, 0x9A, 0x6C, 0x0D, 0x42, 0xEA, 0xC8, 0x19, 0x23, 0x34, 0x4D, 0xF0 }; + internal static readonly byte[] key_4C949BF0 = { 0x20, 0x00, 0x5B, 0x67, 0x48, 0x77, 0x02, 0x60, 0xCF, 0x0C, 0xAB, 0x7E, 0xAE, 0x0C, 0x55, 0xA1 }; + internal static readonly byte[] key_4C949CF0 = { 0x3F, 0x67, 0x09, 0xA1, 0x47, 0x71, 0xD6, 0x9E, 0x27, 0x7C, 0x7B, 0x32, 0x67, 0x0E, 0x65, 0x8A }; + internal static readonly byte[] key_4C949DF0 = { 0x9B, 0x92, 0x99, 0x91, 0xA2, 0xE8, 0xAA, 0x4A, 0x87, 0x10, 0xA0, 0x9A, 0xBF, 0x88, 0xC0, 0xAC }; + internal static readonly byte[] key_4C949EF0 = { 0x90, 0x22, 0x66, 0xE9, 0x59, 0x11, 0x9B, 0x99, 0x67, 0x39, 0x49, 0x81, 0xAB, 0x98, 0x08, 0xA6 }; + internal static readonly byte[] key_4C949FF0 = { 0xA0, 0xA5, 0x55, 0x0A, 0xFA, 0xB2, 0x16, 0x62, 0x05, 0xDC, 0x4B, 0x8E, 0xDA, 0xD5, 0xA5, 0xCA }; + internal static readonly byte[] key_4C94A0F0 = { 0x78, 0x96, 0xAE, 0x9C, 0xE7, 0x89, 0x2D, 0xF5, 0x34, 0x9C, 0x29, 0x36, 0xD1, 0xF9, 0xE8, 0x3C }; + internal static readonly byte[] key_4C94A1F0 = { 0x71, 0x44, 0x53, 0xB6, 0xE6, 0x75, 0x3F, 0xF0, 0x8D, 0x5E, 0xB4, 0xB2, 0xEA, 0x06, 0x23, 0x6A }; + internal static readonly byte[] key_4C9491F0 = { 0x85, 0x93, 0x1F, 0xED, 0x2C, 0x4D, 0xA4, 0x53, 0x59, 0x9C, 0x3F, 0x16, 0xF3, 0x50, 0xDE, 0x46 }; + internal static readonly byte[] key_4C9494F0 = { 0x76, 0xF2, 0x6C, 0x0A, 0xCA, 0x3A, 0xBA, 0x4E, 0xAC, 0x76, 0xD2, 0x40, 0xF5, 0xC3, 0xBF, 0xF9 }; + internal static readonly byte[] key_4C9490F0 = { 0xFA, 0x79, 0x09, 0x36, 0xE6, 0x19, 0xE8, 0xA4, 0xA9, 0x41, 0x37, 0x18, 0x81, 0x02, 0xE9, 0xB3 }; + + internal static readonly byte[] key_00000000 = + { + 0x6A, 0x19, 0x71, 0xF3, 0x18, 0xDE, 0xD3, 0xA2, 0x6D, 0x3B, 0xDE, 0xC7, 0xBE, 0x98, 0xE2, 0x4C, + 0xE3, 0xDC, 0xDF, 0x42, 0x7B, 0x5B, 0x12, 0x28, 0x7D, 0xC0, 0x7A, 0x59, 0x86, 0xF0, 0xF5, 0xB5, + 0x58, 0xD8, 0x64, 0x18, 0x84, 0x24, 0x7F, 0xE9, 0x57, 0xAB, 0x4F, 0xC6, 0x92, 0x6D, 0x70, 0x29, + 0xD3, 0x61, 0x87, 0x87, 0xD0, 0xAE, 0x2C, 0xE7, 0x37, 0x77, 0xC7, 0x3C, 0x96, 0x7E, 0x21, 0x1F, + 0x65, 0x95, 0xC0, 0x61, 0x57, 0xAC, 0x64, 0xD8, 0x5A, 0x6D, 0x14, 0xD2, 0x9C, 0x54, 0xC6, 0x68, + 0x5D, 0xF5, 0xC3, 0xF0, 0x50, 0xDA, 0xEA, 0x19, 0x43, 0xA7, 0xAD, 0xC3, 0x2A, 0x14, 0xCA, 0xC8, + 0x4C, 0x83, 0x86, 0x18, 0xAE, 0x86, 0x49, 0xFB, 0x4F, 0x45, 0x75, 0xD2, 0xC3, 0xD6, 0xE1, 0x13, + 0x69, 0x37, 0xC6, 0x90, 0xCF, 0xF9, 0x79, 0xA1, 0x77, 0x3A, 0x3E, 0xBB, 0xBB, 0xD5, 0x3B, 0x84, + 0x1B, 0x9A, 0xB8, 0x79, 0xF0, 0xD3, 0x5F, 0x6F, 0x4C, 0xC0, 0x28, 0x87, 0xBC, 0xAE, 0xDA, 0x00 + }; + + internal static readonly byte[] key_01000000 = + { + 0x50, 0xCC, 0x03, 0xAC, 0x3F, 0x53, 0x1A, 0xFA, 0x0A, 0xA4, 0x34, 0x23, 0x86, 0x61, 0x7F, 0x97, + 0x84, 0x1C, 0x1A, 0x1D, 0x08, 0xD4, 0x50, 0xB6, 0xD9, 0x73, 0x27, 0x80, 0xD1, 0xDE, 0xEE, 0xCA, + 0x49, 0x8B, 0x84, 0x37, 0xDB, 0xF0, 0x70, 0xA2, 0xA6, 0x2B, 0x09, 0x4D, 0x3B, 0x29, 0xDE, 0x0B, + 0xE1, 0x6F, 0x04, 0x7A, 0xC4, 0x18, 0x7A, 0x69, 0x73, 0xBF, 0x02, 0xD8, 0xA1, 0xD0, 0x58, 0x7E, + 0x69, 0xCE, 0xAC, 0x5E, 0x1B, 0x0A, 0xF8, 0x19, 0xE6, 0x9A, 0xC0, 0xDE, 0xA0, 0xB2, 0xCE, 0x04, + 0x43, 0xC0, 0x9D, 0x50, 0x5D, 0x0A, 0xD7, 0xFD, 0xC6, 0x53, 0xAA, 0x13, 0xDD, 0x2C, 0x3B, 0x2B, + 0xBF, 0xAB, 0x7C, 0xF5, 0xA0, 0x4A, 0x79, 0xE3, 0xF1, 0x7B, 0x2E, 0xB2, 0xA3, 0xAC, 0x8E, 0x0A, + 0x38, 0x9B, 0x9E, 0xAA, 0xEC, 0x2B, 0xA3, 0x75, 0x13, 0x75, 0x77, 0x98, 0x6A, 0x66, 0x92, 0x65, + 0xBC, 0x97, 0x80, 0x0E, 0x32, 0x88, 0x9F, 0x64, 0xBA, 0x99, 0x8A, 0x72, 0x96, 0x9F, 0xE1, 0xE0 + }; + + internal static readonly byte[] key_16D59E03 = { 0xC3, 0x24, 0x89, 0xD3, 0x80, 0x87, 0xB2, 0x4E, 0x4C, 0xD7, 0x49, 0xE4, 0x9D, 0x1D, 0x34, 0xD1 }; + + internal static readonly byte[] key_4467415D = + { + 0x66, 0x0F, 0xCB, 0x3B, 0x30, 0x75, 0xE3, 0x10, 0x0A, 0x95, 0x65, 0xC7, 0x3C, 0x93, 0x87, 0x22, + 0xF3, 0xA4, 0xB1, 0xE8, 0x9A, 0xFB, 0x53, 0x52, 0x8F, 0x64, 0xB2, 0xDA, 0xB7, 0x76, 0xB9, 0x56, + 0x96, 0xB6, 0x4C, 0x02, 0xE6, 0x9B, 0xAE, 0xED, 0x86, 0x48, 0xBA, 0xA6, 0x4F, 0x23, 0x15, 0x03, + 0x1F, 0xC4, 0xF7, 0x3A, 0x05, 0xC3, 0x3C, 0xE2, 0x2F, 0x36, 0xC4, 0x26, 0xF2, 0x42, 0x40, 0x1F, + 0x97, 0xEE, 0x9C, 0xC6, 0xD9, 0x68, 0xE0, 0xE7, 0xE3, 0x9F, 0xCE, 0x05, 0xE8, 0xD1, 0x8B, 0x1B, + 0x57, 0x34, 0x3D, 0x0D, 0xDF, 0xA8, 0x64, 0xBF, 0x8F, 0x4C, 0x37, 0x3F, 0x93, 0xD5, 0x45, 0x9E, + 0x2B, 0x25, 0x2C, 0x62, 0x74, 0xDE, 0xC1, 0x53, 0xAB, 0x6D, 0xDF, 0x2C, 0xCE, 0x5A, 0x6B, 0x1F, + 0x5E, 0x24, 0x4A, 0xFB, 0x7D, 0xFF, 0xE8, 0xF5, 0x19, 0x77, 0xEF, 0xCC, 0x74, 0xFE, 0x8B, 0x63, + 0x31, 0xAE, 0x99, 0x05, 0x7F, 0x51, 0xF2, 0x72, 0x6A, 0x20, 0x8D, 0x1C, 0xAC, 0x4C, 0xF6, 0x50 + }; + + internal static readonly byte[] key_CFEF05F0 = { 0xCA, 0xFB, 0xBF, 0xC7, 0x50, 0xEA, 0xB4, 0x40, 0x8E, 0x44, 0x5C, 0x63, 0x53, 0xCE, 0x80, 0xB1 }; + internal static readonly byte[] key_CFEF06F0 = { 0x9F, 0x67, 0x1A, 0x7A, 0x22, 0xF3, 0x59, 0x0B, 0xAA, 0x6D, 0xA4, 0xC6, 0x8B, 0xD0, 0x03, 0x77 }; + internal static readonly byte[] key_CFEF08F0 = { 0x2E, 0x00, 0xF6, 0xF7, 0x52, 0xCF, 0x95, 0x5A, 0xA1, 0x26, 0xB4, 0x84, 0x9B, 0x58, 0x76, 0x2F }; + + public static int memlmd_EF73E85B(Span modData, int size, out int newSize) => KernelModuleDecrypt(modData, size, out newSize, 0); + + public static int memlmd_CF03556B(Span modData, int size, out int newSize) => KernelModuleDecrypt(modData, size, out newSize, 1); + + static int KernelModuleDecrypt(Span modData, int size, out int newSize, int use_polling) + { + int ret; + newSize = 0; + Span local_80 = stackalloc byte[48]; + Span local_50 = stackalloc byte[32]; + if (modData.IsEmpty) + { + return -0xc9; + } + if (size < 0x160) + { + return -0xca; + } + //if ((modData[0] & 0x3f) != 0) + //{ + // return -0xcb; + //} + + //if ((0x220202 >> (MemoryMarshal.Read(modData) >> 0x1b)) == 0) + //{ + // return -0xcc; + //} + modData[..0x150].CopyTo(MemlmdKirkMemory.Span); + var hdr = MemoryMarshal.Read(MemlmdKirkMemory.Span); + int? keySeed = null; + bool? keyFlag = null; + Span key = null; + if (hdr.tag == 0x4C94A1F0) + { + keySeed = 0x43; + keyFlag = true; + key = key_4C94A1F0; + } + else if (hdr.tag == 0x4C949BF0) + { + keySeed = 0x43; + keyFlag = true; + key = key_4C949BF0; + } + else if (hdr.tag == 0xB1B9C434) + { + } + else + { + if (hdr.tag == 0x4C9491F0) + { + key = key_4C9491F0; + } + else if (hdr.tag == 0x4C9494F0) + { + key = key_4C9494F0; + } + else if (hdr.tag == 0x4C9490F0) + { + key = key_4C9490F0; + } + else + { + if (hdr.tag == 0x00000000) + { + key = key_00000000; + keySeed = 0x42; + } + else if (hdr.tag == 0x01000000) + { + key = key_01000000; + keySeed = 0x43; + } + keyFlag = false; + goto keytagout; + } + keySeed = 0x43; + keyFlag = true; + } + keytagout: + //if (keyFlag == true && size < 0x160) + //{ + // return -0xca; + //} + if (keyFlag == true) + { + for (var i = 0; i < 0x30; i++) + { + if (hdr.sCheck[i] != 0) + { + ret = -0x12e; + goto errout; + } + } + } + if (keyFlag == false) + { + // TODO blacklistCheck + } + newSize = MemoryMarshal.Read(hdr.sizeInfo); + if (size - 0x150 < newSize) + { + ret = -0xce; + goto errout; + } + if (keyFlag == true) + { + for (byte i = 0; i < 9; i++) + { + key.CopyTo(MemlmdMem_BFC00A00.Span[(i * 0x10 + 0x14)..]); + MemlmdMem_BFC00A00.Span[i * 0x10 + 0x14] = i; + } + ref var refHdr = ref MemoryMarshal.AsRef(modData); + refHdr.sCheck.Slice(0x30, 0x28).CopyTo(MemlmdMem_2780.Span); + refHdr.sCheck.Slice(0x30, 0x28).Fill(0); + MemlmdMem_2780.Span.Slice(0, 0x28).CopyTo(local_80); + var tmp = size - 4; + MemoryMarshal.Write(modData, ref tmp); + if (use_polling == 0) + { + ret = KIRKEngine.sceUtilsBufferCopyWithRange(modData, size, modData, size, KIRKEngine.KIRK_CMD_SHA1_HASH); + } + else + { + // TODO + ret = -1; + } + if (ret == 0) + { + modData.Slice(0, 0x14).CopyTo(local_50); + MemlmdKirkMemory.Span.Slice(0, 0x20).CopyTo(modData); + key7A90.CopyTo(MemlmdMem_BFC00340); + local_50.Slice(0, 0x14).CopyTo(MemlmdMem_BFC00340.Span[0x28..]); + local_80.Slice(0, 0x28).CopyTo(MemlmdMem_BFC00340.Span[0x3C..]); + if (use_polling == 0) + { + ret = KIRKEngine.sceUtilsBufferCopyWithRange(null, 0, MemlmdMem_BFC00340.Span, 100, KIRKEngine.KIRK_CMD_ECDSA_VERIFY); + } + else + { + // TODO + ret = -1; + } + if (ret == 0) + { + // clear key_4C9494F0 psp 660 + // clear key_4C9495F0 psp 660 + // clear key_4C94A1F0 psv + } + else + { + ret = -0x132; + goto errout; + } + } + else + { + if (ret < 0) + { + ret = -0x66; + } + else if (ret == 0xc) + { + ret = -0x6b; + } + else + { + ret = -0x69; + } + goto errout; + } + } + else + { + key[..0x90].CopyTo(MemlmdMem_BFC00A00.Span[0x14..]); + } + ret = Kirk7(MemlmdMem_BFC00A00.Span, 0x90, keySeed.Value, use_polling); + if (ret == 0) + { + MemlmdMem_BFC00A00[..0x90].CopyTo(MemlmdMem_BFC00280); + if (keyFlag == true) + { + hdr.CheckData[..0x5C].CopyTo(MemlmdMem_BFC00A00.Span); + hdr.keyData4.CopyTo(MemlmdMem_BFC00A00[0x5C..].Span); + hdr.sha1Hash.CopyTo(MemlmdMem_BFC00A00[0x6C..].Span); + hdr.keyData.CopyTo(MemlmdMem_BFC00A00[0x80..].Span); + hdr.cmacDataHash.CopyTo(MemlmdMem_BFC00A00[0xB0..].Span); + hdr.sizeInfo.CopyTo(MemlmdMem_BFC00A00[0xC0..].Span); + hdr.RawHdr.CopyTo(MemlmdMem_BFC00A00[0xD0..].Span); + MemlmdMem_BFC00A00.Slice(0x34, 0x28).Span.Fill(0); + } + else + { + hdr.CheckData.CopyTo(MemlmdMem_BFC00A00.Span); + hdr.keyData50.CopyTo(MemlmdMem_BFC00A00[0x80..].Span); + hdr.RawHdr.CopyTo(MemlmdMem_BFC00A00[0xD0..].Span); + } + if (keyFlag == true) + { + MemlmdMem_BFC00A00.Slice(0x5C, 0x60).CopyTo(MemlmdMem_BFC00340[0x14..]); + ret = Kirk7(MemlmdMem_BFC00340.Span, 0x60, keySeed.Value, use_polling); + if (ret == 0) + { + MemlmdMem_BFC00340.Slice(0, 0x60).CopyTo(MemlmdMem_BFC00A00[0x5C..]); + } + else + { + goto kirkerr; + } + } + if (keyFlag == true) + { + MemlmdMem_BFC00A00.Slice(0x6C, 0x14).CopyTo(MemlmdMem_BFC00340); + MemlmdMem_BFC00A00.Slice(0x5C, 0x10).CopyTo(MemlmdMem_BFC00A00[0x70..]); + MemlmdMem_BFC00A00.Slice(0x18, 0x58).Span.Fill(0); + MemlmdMem_BFC00A00[..4].CopyTo(MemlmdMem_BFC00A00[4..]); + var tmp = 0x14c; + MemoryMarshal.Write(MemlmdMem_BFC00A00.Span, ref tmp); + MemlmdMem_BFC00280[..0x10].CopyTo(MemlmdMem_BFC00A00[8..]); + MemlmdMem_BFC00280[..0x10].Span.Fill(0); + } + else + { + MemlmdMem_BFC00A00.Slice(4, 0x14).CopyTo(MemlmdMem_BFC00340); + var tmp = 0x14c; + MemoryMarshal.Write(MemlmdMem_BFC00A00.Span, ref tmp); + MemlmdMem_BFC00280[..0x14].CopyTo(MemlmdMem_BFC00A00[4..]); + } + if (use_polling == 0) + { + ret = KIRKEngine.sceUtilsBufferCopyWithRange(MemlmdMem_BFC00A00.Span, 0x150, MemlmdMem_BFC00A00.Span, 0x150, KIRKEngine.KIRK_CMD_SHA1_HASH); + } + else + { + // TODO + ret = -1; + } + if (ret == 0) + { + if (!MemlmdMem_BFC00A00[..0x14].Span.SequenceEqual(MemlmdMem_BFC00340.Span[..0x14])) + { + ret = -0x12e; + goto errout; + } + if (keyFlag == true) + { + for (var i = 0; i < 0x40; i++) + { + MemlmdMem_BFC00A00[0x80..].Span[i] ^= MemlmdMem_BFC00280[0x10..].Span[i]; + } + MemlmdMem_BFC00280.Slice(0x10, 0x40).Span.Fill(0); + ret = Kirk7(MemlmdMem_BFC00A00[0x6C..].Span, 0x40, keySeed.Value, use_polling); + if (ret != 0) + { + goto kirkerr; + } + for (var i = 0; i < 0x40; i++) + { + modData[0x40..][i] = (byte)(MemlmdMem_BFC00A00[0x6C..].Span[i] ^ MemlmdMem_BFC00280[0x50..].Span[i]); + } + MemlmdMem_BFC00280.Slice(0x50, 0x40).Span.Fill(0); + modData.Slice(0x80, 0x30).Fill(0); + + ref var cmd1Hdr = ref MemoryMarshal.AsRef(modData[0x40..]); + cmd1Hdr.mode = 1; + MemlmdMem_BFC00A00.Slice(0xc0, 0x10).Span.CopyTo(cmd1Hdr.off70); // DAT_00009e80 + modData.Slice(0xc0, 0x10).Fill(0); + MemlmdMem_BFC00A00.Slice(0xd0, 0x80).Span.CopyTo(modData[0xd0..]); // psp hdr size 0x80 + } + else + { + for (var i = 0; i < 0x70; i++) + { + MemlmdMem_BFC00A00[0x40..].Span[i] ^= MemlmdMem_BFC00280[0x14..].Span[i]; + } + ret = Kirk7(MemlmdMem_BFC00A00[0x2C..].Span, 0x70, keySeed.Value, use_polling); + if (ret == 0) + { + for (var i = 0; i < 0x70; i++) + { + modData[0x40..][i] = (byte)(MemlmdMem_BFC00A00[0x2C..].Span[i] ^ MemlmdMem_BFC00280[0x20..].Span[i]); + } + MemlmdMem_BFC00A00.Slice(0xB0, 0xA0).Span.CopyTo(modData[0xB0..]); + ref var cmd1ecdsaHdr = ref MemoryMarshal.AsRef(modData[0x40..]); + if (cmd1ecdsaHdr.ecdsa_hash != 1) + { + ret = -0x12f; + goto errout; + } + } + else + { + // goto kirk err; + goto kirkerr; + } + } + if (use_polling == 0) + { + // File.WriteAllBytes("wrongdata", modData.ToArray()); + ret = KIRKEngine.sceUtilsBufferCopyWithRange(modData, size, modData[0x40..], size - 0x40, KIRKEngine.KIRK_CMD_DECRYPT_PRIVATE); + } + else + { + // TODO + } + if (ret == 0) + { + goto rout; + } + } + } + errout: + + MemlmdKirkMemory.Span.Fill(0); + newSize = 0; + rout: + MemlmdMem_BFC00A00.Span.Fill(0); + + return ret; + kirkerr: + ret ^= 0xC; + ret = -0x6a; + goto errout; + } + + static int Kirk7(Span data, int size, int seed, int use_polling) + { + KIRKEngine.KIRK_AES128CBC_HEADER hdr = new KIRKEngine.KIRK_AES128CBC_HEADER + { + mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC, + keyseed = seed, + data_size = size + }; + MemoryMarshal.Write(data, ref hdr); + //using (var ms = new MemoryStream(data)) + //{ + // ms.Seek(offset, SeekOrigin.Begin); + // using var bw = new BinaryWriter(ms); + // bw.Write(KIRKEngine.KIRK_MODE_DECRYPT_CBC); + // bw.Write(0); + // bw.Write(0); + // bw.Write(seed); + // bw.Write(size); + //} + if (use_polling == 0) + { + KIRKEngine.sceUtilsBufferCopyWithRange(data, size + 20, data, size + 20, + KIRKEngine.KIRK_CMD_DECRYPT_IV_0); + } + return 0; + } + static int Kirk8(Span buf, int size, int use_polling) + { + int retv; + ref var hdr = ref MemoryMarshal.AsRef(buf); + hdr.mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC; + hdr.keyseed = 0x0100; + hdr.data_size = size; + + retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_DECRYPT_IV_FUSE); + + return retv; + } + + private static readonly byte[] key_XOR_2304 = + { + 0x71, 0xF6, 0xA8, 0x31, 0x1E, 0xE0, 0xFF, 0x1E, 0x50, 0xBA, 0x6C, 0xD2, 0x98, 0x2D, 0xD6, 0x2D + }; + + private static readonly byte[] key_XOR_2314 = + { + 0xAA, 0x85, 0x4D, 0xB0, 0xFF, 0xCA, 0x47, 0xEB, 0x38, 0x7F, 0xD7, 0xE4, 0x3D, 0x62, 0xB0, 0x10 + }; + + static int memlmd_6192F715(Span modData, int size) => KernelModuleSignCheck(modData, size, 0); + + static int memlmd_EA94592C(Span modData, int size) => KernelModuleSignCheck(modData, size, 1); + + static int KernelModuleSignCheck(Span modData, int size, int use_polling) + { + int ret = -0xc9; + if (modData.IsEmpty) + { + goto errorout; + } + if (size < 0x15F) + { + ret = -0xca; + goto errorout; + } + modData.Slice(0x80, 0xD0).CopyTo(MemlmdMem_BFC00A00.Span.Slice(0x14)); + + for (var i = 0; i < 0xD0; i++) + { + MemlmdMem_BFC00A00[0x14..].Span[i] ^= key_XOR_2314[i & 0xF]; + } + ret = Kirk8(MemlmdMem_BFC00A00.Span, 0xD0, use_polling); + if (ret == 0) + { + for (var i = 0; i < 0xD0; i++) + { + MemlmdMem_BFC00A00.Span[i] ^= key_XOR_2304[i & 0xF]; + } + MemlmdMem_BFC00A00.Slice(0x40, 0x90).Span.CopyTo(modData[0x80..]); + MemlmdMem_BFC00A00.Slice(0, 0x40).Span.CopyTo(modData[0x110..]); + } + else + { + if (ret < 0) + { + ret = -0x67; + } + else if (ret != 0xc) + { + ret = -0x6a; + } + else + { + ret = -0x67; + } + } + errorout: + MemlmdMem_BFC00A00.Slice(0, 0x164).Span.Fill(0); + return ret; + } + } +} diff --git a/PspCrypto/SceMesgLed.cs b/PspCrypto/SceMesgLed.cs new file mode 100644 index 0000000..8ed6a99 --- /dev/null +++ b/PspCrypto/SceMesgLed.cs @@ -0,0 +1,2662 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; +using Elf32_Half = System.UInt16; +using Elf32_Word = System.UInt32; +using Elf32_Addr = System.UInt32; +using Elf32_Off = System.UInt32; +using System.Linq; + +namespace PspCrypto +{ + public static class SceMesgLed + { + #region sceMesgLed_driver + private static readonly byte[] key_2E5E90F0 = { 0x67, 0xE4, 0x8F, 0x4C, 0x08, 0xA0, 0x7D, 0xB1, 0x5F, 0x51, 0xA7, 0x72, 0x98, 0xA8, 0x2D, 0x7E }; + private static readonly byte[] key_2E5E90F0_xor = { 0x69, 0xBA, 0x55, 0x34, 0xF0, 0xC0, 0xD6, 0x71, 0xE3, 0x1F, 0xDB, 0x97, 0xE0, 0x7C, 0xD2, 0x2A }; + private static readonly byte[] key_2E5E80F0 = { 0x0F, 0x74, 0xAF, 0x43, 0x75, 0xCD, 0xDA, 0x39, 0x81, 0x56, 0xD9, 0x61, 0x3E, 0x16, 0xC8, 0x92 }; + private static readonly byte[] key_2E5E80F0_xor = { 0x69, 0xBA, 0x55, 0x34, 0xF0, 0xC0, 0xD6, 0x71, 0xE3, 0x1F, 0xDB, 0x97, 0xE0, 0x7C, 0xD2, 0x2A }; + private static readonly byte[] key_2E5E11F0 = { 0x75, 0xEB, 0xE8, 0x43, 0xF4, 0x87, 0x8F, 0xD0, 0x14, 0x7F, 0x7E, 0x39, 0xAD, 0xAF, 0x04, 0x9D }; + private static readonly byte[] key_2E5E11F0_xor = { 0x69, 0xBA, 0x55, 0x34, 0xF0, 0xC0, 0xD6, 0x71, 0xE3, 0x1F, 0xDB, 0x97, 0xE0, 0x7C, 0xD2, 0x2A }; + private static readonly byte[] key_2E5E12F0 = { 0x8A, 0x7B, 0xC9, 0xD6, 0x52, 0x58, 0x88, 0xEA, 0x51, 0x83, 0x60, 0xCA, 0x16, 0x79, 0xE2, 0x07 }; + private static readonly byte[] key_2E5E13F0 = { 0xFF, 0xA4, 0x68, 0xC3, 0x31, 0xCA, 0xB7, 0x4C, 0xF1, 0x23, 0xFF, 0x01, 0x65, 0x3D, 0x26, 0x36 }; + private static readonly byte[] key_2E5E10F0 = { 0x9D, 0x5C, 0x5B, 0xAF, 0x8C, 0xD8, 0x69, 0x7E, 0x51, 0x9F, 0x70, 0x96, 0xE6, 0xD5, 0xC4, 0xE8 }; + private static readonly byte[] key_2E5E10F0_xor = { 0x69, 0xBA, 0x55, 0x34, 0xF0, 0xC0, 0xD6, 0x71, 0xE3, 0x1F, 0xDB, 0x97, 0xE0, 0x7C, 0xD2, 0x2A }; + + public static int sceMesgLed_driver_31D6D8AA(Span modData, int size, out int newSize, ReadOnlySpan versionKey) + { + var ret = Decrypt(0x2E5E90F0, key_2E5E90F0, 0x48, modData, size, out newSize, 0, null, 10, key_2E5E90F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x2E5E80F0, key_2E5E80F0, 0x48, modData, size, out newSize, 0, null, 7, key_2E5E80F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x2E5E13F0, key_2E5E13F0, 0x48, modData, size, out newSize, 0, null, 5, key_2E5E11F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x2E5E12F0, key_2E5E12F0, 0x48, modData, size, out newSize, 0, null, 5, key_2E5E11F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x2E5E11F0, key_2E5E11F0, 0x48, modData, size, out newSize, 0, null, 5, key_2E5E11F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x2E5E10F0, key_2E5E10F0, 0x48, modData, size, out newSize, 0, null, 5, key_2E5E10F0_xor, versionKey); + } + } + } + } + } + return ret; + } + + private static readonly byte[] key_38029AF0 = { 0xF9, 0x4A, 0x6B, 0x96, 0x79, 0x3F, 0xEE, 0x0A, 0x04, 0xC8, 0x8D, 0x7E, 0x5F, 0x38, 0x3A, 0xCF }; + private static readonly byte[] key_380293F0 = { 0xCB, 0x93, 0x12, 0x38, 0x31, 0xC0, 0x2D, 0x2E, 0x7A, 0x18, 0x5C, 0xAC, 0x92, 0x93, 0xAB, 0x32 }; + private static readonly byte[] key_380292F0 = { 0xD1, 0xB0, 0xAE, 0xC3, 0x24, 0x36, 0x13, 0x49, 0xD6, 0x49, 0xD7, 0x88, 0xEA, 0xA4, 0x99, 0x86 }; + private static readonly byte[] key_380291F0 = { 0x86, 0xA0, 0x7D, 0x4D, 0xB3, 0x6B, 0xA2, 0xFD, 0xF4, 0x15, 0x85, 0x70, 0x2D, 0x6A, 0x0D, 0x3A }; + private static readonly byte[] key_380290F0 = { 0xF9, 0x4A, 0x6B, 0x96, 0x79, 0x3F, 0xEE, 0x0A, 0x04, 0xC8, 0x8D, 0x7E, 0x5F, 0x38, 0x3A, 0xCF }; + private static readonly byte[] key_02000000 = + { + 0x72, 0x81, 0x2F, 0xB3, 0x39, 0x5A, 0x3D, 0xBD, 0x38, 0x8A, 0x10, 0x74, 0x96, 0x55, 0xB1, 0xDF, + 0x88, 0x9F, 0xEE, 0xA1, 0xB5, 0x71, 0x74, 0x89, 0x56, 0xE1, 0xA3, 0xBB, 0x7E, 0x9F, 0xC3, 0xC2, + 0x9E, 0xF8, 0x9B, 0xB9, 0x87, 0xBD, 0x22, 0x88, 0x57, 0xDE, 0x1B, 0x88, 0xC9, 0x9A, 0x3B, 0x1A, + 0xBA, 0xBD, 0xC7, 0xA6, 0x58, 0xCB, 0x8F, 0xA1, 0x0E, 0xDF, 0x64, 0x3B, 0x4A, 0x96, 0x96, 0xCB, + 0x36, 0xD0, 0x4F, 0x2D, 0x32, 0xDD, 0x19, 0xAB, 0xE1, 0xD6, 0x54, 0xFE, 0x97, 0x13, 0x57, 0x5C, + 0x7A, 0x68, 0x05, 0x71, 0x34, 0x7D, 0x31, 0x1E, 0x33, 0x66, 0xDD, 0x6D, 0x7B, 0x76, 0x17, 0x1B, + 0x25, 0x9B, 0xAF, 0x21, 0x79, 0x17, 0x72, 0x10, 0xFD, 0xB5, 0x55, 0x35, 0xA9, 0xBE, 0x55, 0xAE, + 0x72, 0x45, 0xCE, 0x55, 0xA2, 0x70, 0x80, 0xE5, 0xAD, 0xD0, 0xBE, 0xB9, 0xE4, 0x7E, 0x02, 0xA9, + 0x92, 0x46, 0xC3, 0x35, 0x05, 0xF1, 0x7A, 0x93, 0xC1, 0x3A, 0x1A, 0x48, 0x99, 0x3B, 0x3C, 0x1B + }; + + // sceKernelWaitSema + public static int sceMesgLed_driver_5C3A61FE(Span modData, int size, out int newSize) + { + var ret = Decrypt(0x38029AF0, key_38029AF0, 0x5A, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x380293F0, key_380293F0, 0x5A, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x380292F0, key_380292F0, 0x5A, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x380291F0, key_380291F0, 0x5A, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x380290F0, key_380290F0, 0x5A, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x02000000, key_02000000, 0x45, modData, size, out newSize, 0, null, 8, null, null); + } + } + } + } + } + + return ret; + } + + // sceKernelPollSema + static int sceMesgLed_driver_3783B0AD(Span modData, int size, out int newSize) => sceMesgLed_driver_5C3A61FE(modData, size, out newSize); + + private static readonly byte[] key_EFD228F0 = { 0x22, 0xDD, 0x51, 0x6E, 0xF2, 0xD2, 0x1C, 0xA1, 0xE9, 0xD5, 0xBD, 0x88, 0x49, 0x52, 0xDE, 0x5B }; + private static readonly byte[] key_EFD21EF0 = { 0x30, 0x33, 0x7F, 0xFE, 0x67, 0xE1, 0x95, 0x8D, 0xF2, 0xC2, 0xD1, 0x70, 0x8A, 0xD5, 0x4A, 0xE5 }; + private static readonly byte[] key_EFD210F0 = { 0xE2, 0x7E, 0xDE, 0xBC, 0x27, 0x3D, 0x41, 0xD4, 0x03, 0x4A, 0x1A, 0x2B, 0xAA, 0xEE, 0x4A, 0x21 }; + private static readonly byte[] key_0A000000 = + { + 0x80, 0xE4, 0x89, 0x5A, 0x27, 0xDB, 0x39, 0x7D, 0x6B, 0x7B, 0x7B, 0xF2, 0x3D, 0xDF, 0x92, 0xDD, + 0x50, 0xD4, 0xB5, 0x72, 0xAC, 0x6A, 0xF8, 0x7C, 0x67, 0x29, 0x42, 0x32, 0x61, 0x37, 0x79, 0x13, + 0x74, 0xE4, 0x5F, 0xB9, 0x57, 0x56, 0x1A, 0x14, 0xF3, 0x10, 0x5D, 0x8B, 0x7C, 0x74, 0x5C, 0x2F, + 0xBB, 0x96, 0x6B, 0xE4, 0x00, 0x67, 0xEC, 0xF6, 0x28, 0x81, 0xFC, 0x61, 0x01, 0xF0, 0x42, 0x83, + 0x71, 0x7F, 0xCE, 0xB6, 0xD4, 0x59, 0x84, 0xCE, 0xE9, 0xAB, 0x38, 0x5B, 0x7C, 0xD1, 0xB7, 0xFB, + 0x30, 0xDC, 0x87, 0xDF, 0x3B, 0x0C, 0x78, 0xC8, 0x35, 0xF7, 0xA8, 0xC7, 0x2F, 0x33, 0xC7, 0xA0, + 0x31, 0xDD, 0x23, 0x40, 0xE2, 0x77, 0xDF, 0xC2, 0x06, 0xD7, 0x4E, 0x78, 0x4C, 0xA4, 0xD4, 0x22, + 0x73, 0x49, 0x2D, 0x98, 0xEE, 0x17, 0xA1, 0x9A, 0x90, 0xF7, 0x96, 0x48, 0xDB, 0x6D, 0x81, 0x71, + 0xF1, 0xDB, 0x07, 0x85, 0x91, 0x68, 0xE5, 0x26, 0x95, 0xEA, 0xDF, 0xEE, 0xA1, 0xB8, 0x9D, 0x36 + }; + + // sceKernelWaitSema + public static int sceMesgLed_driver_B2CDAC3F(Span modData, int size, out int newSize) + { + var ret = Decrypt(0xEFD228F0, key_EFD228F0, 0x4D, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xEFD21EF0, key_EFD21EF0, 0x4D, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xEFD210F0, key_EFD210F0, 0x4D, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x0A000000, key_0A000000, 0x4D, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + return ret; + } + + // sceKernelPollSema + static int sceMesgLed_driver_B5596BE4(Span modData, int size, out int newSize) => sceMesgLed_driver_B2CDAC3F(modData, size, out newSize); + + private static readonly byte[] key_0B000000 = + { + 0x0B, 0x01, 0x1C, 0xE7, 0x31, 0x15, 0x6B, 0x83, 0x3E, 0x26, 0x0D, 0xCC, 0x69, 0x36, 0x12, 0xCB, + 0xA7, 0xFD, 0x26, 0x66, 0x93, 0x2A, 0x6E, 0x1A, 0x91, 0x2E, 0xC6, 0xFC, 0xD8, 0x2F, 0x00, 0x13, + 0x5A, 0xE2, 0xDF, 0xB6, 0xA2, 0xE4, 0x27, 0xC8, 0x18, 0xC3, 0x50, 0x50, 0xB7, 0xE9, 0x4A, 0xED, + 0xCC, 0x3C, 0x30, 0xFD, 0x10, 0x6A, 0x2B, 0x0A, 0x22, 0xCB, 0xC6, 0xE0, 0x20, 0x65, 0x12, 0xEB, + 0x7D, 0x4E, 0x2A, 0x37, 0x0B, 0x0A, 0xEF, 0x88, 0xDA, 0x06, 0x54, 0xD4, 0x30, 0xAF, 0xCD, 0xCA, + 0x9A, 0xF9, 0xDA, 0x1A, 0xB0, 0x1B, 0xBB, 0x62, 0x0C, 0xDB, 0xF8, 0x44, 0x73, 0x56, 0x14, 0x8E, + 0x93, 0xB1, 0x2C, 0xFD, 0x67, 0xE2, 0x5D, 0xCB, 0x48, 0x5B, 0xD9, 0xB3, 0x54, 0x14, 0xD7, 0x9F, + 0x79, 0x9C, 0x24, 0xE9, 0xC2, 0x7A, 0x4E, 0x8C, 0x4D, 0x24, 0x19, 0x94, 0xFF, 0xC9, 0xC2, 0x2D, + 0x23, 0x63, 0x51, 0xB8, 0xFA, 0xD6, 0x7F, 0xE6, 0x5E, 0xBC, 0x32, 0xB2, 0x02, 0x13, 0xC4, 0x76 + }; + //private static readonly byte[] key_0B000000_blackList = + //{ + // 0xFD, 0xB7, 0xC4, 0xDD, 0x64, 0x48, 0x2C, 0x6C, 0x53, 0xFE, 0x58, 0x42, 0xA1, 0x13, 0x3A, 0xD3, + // 0x4A, 0x07, 0x0E, 0xD2, 0xEA, 0xBA, 0x2F, 0xAD, 0x21, 0x31, 0x48, 0xB8, 0x9D, 0x3B, 0x1E, 0x35, + // 0xBE, 0x8A, 0x5F, 0x54, 0x8E, 0x25, 0xB9, 0xB8, 0xB8, 0xAA, 0x8D, 0xE4, 0x2A, 0xF7, 0x66, 0xE3, + // 0xC1, 0x8A, 0xA6, 0x89, 0x15, 0xFD, 0x88, 0xE3, 0xF1, 0x93, 0x60, 0x63, 0x84, 0x9D, 0x09, 0xD4, + // 0x75, 0xDD, 0x9C, 0x3F, 0xBC, 0x6F, 0x61, 0xC0, 0xB1, 0x82, 0x11, 0x8A, 0xE3, 0x56, 0x68, 0x9E, + // 0x2F, 0x2B, 0xD9, 0x07, 0xA1, 0x14, 0xB4, 0x6F, 0xF6, 0x4E, 0x85, 0x51, 0x5F, 0x64, 0x04, 0xF0, + // 0xF2, 0xDD, 0xE4, 0xBC, 0x09, 0x1E, 0xF2, 0xEC, 0xCB, 0x56, 0xD2, 0x66, 0x3E, 0x2F, 0xE4, 0x31, + // 0x3A, 0xD7, 0xF3, 0x2A, 0x20, 0xB1, 0x01, 0x7E, 0xB9, 0xA2, 0x1C, 0x5D, 0x3E, 0x1C, 0x77, 0x71, + // 0x05, 0x71, 0x9C, 0x14, 0xB0, 0xC7, 0x35, 0xBA, 0x25, 0x04, 0xA1, 0xF8, 0xA8, 0x23, 0x2B, 0x5F + //}; + + // sceKernelWaitSema + public static int sceMesgLed_driver_C79E3488(Span modData, int size, out int newSize) + { + return Decrypt(0x0B000000, key_0B000000, 0x4E, modData, size, out newSize, 0, null, 8, null, null); + } + + // sceKernelPollSema + static int sceMesgLed_driver_6BF453D3(Span modData, int size, out int newSize) => sceMesgLed_driver_C79E3488(modData, size, out newSize); + + private static readonly byte[] key_457B9AF0 = { 0x08, 0x57, 0xC2, 0x49, 0x15, 0xD6, 0x2C, 0xDB, 0x62, 0xBE, 0x86, 0x6C, 0x75, 0x19, 0xDC, 0x4D }; + private static readonly byte[] key_457B93F0 = { 0x88, 0xAF, 0x18, 0xE9, 0xC3, 0xAA, 0x6B, 0x56, 0xF7, 0xC5, 0xA8, 0xBF, 0x1A, 0x84, 0xE9, 0xF3 }; + private static readonly byte[] key_457B92F0 = { 0x92, 0x8C, 0xA4, 0x12, 0xD6, 0x5C, 0x55, 0x31, 0x5B, 0x94, 0x23, 0x9B, 0x62, 0xB3, 0xDB, 0x47 }; + private static readonly byte[] key_457B91F0 = { 0xC5, 0x9C, 0x77, 0x9C, 0x41, 0x01, 0xE4, 0x85, 0x79, 0xC8, 0x71, 0x63, 0xA5, 0x7D, 0x4F, 0xFB }; + private static readonly byte[] key_457B90F0 = { 0xBA, 0x76, 0x61, 0x47, 0x8B, 0x55, 0xA8, 0x72, 0x89, 0x15, 0x79, 0x6D, 0xD7, 0x2F, 0x78, 0x0E }; + private static readonly byte[] key_457B8AF0 = { 0x47, 0xEC, 0x60, 0x15, 0x12, 0x2C, 0xE3, 0xE0, 0x4A, 0x22, 0x6F, 0x31, 0x9F, 0xFA, 0x97, 0x3E }; + private static readonly byte[] key_457B80F0 = { 0xD4, 0x35, 0x18, 0x02, 0x29, 0x68, 0xFB, 0xA0, 0x6A, 0xA9, 0xA5, 0xED, 0x78, 0xFD, 0x2E, 0x9D }; + private static readonly byte[] key_457B10F0 = { 0x71, 0x10, 0xF0, 0xA4, 0x16, 0x14, 0xD5, 0x93, 0x12, 0xFF, 0x74, 0x96, 0xDF, 0x1F, 0xDA, 0x89 }; + private static readonly byte[] key_457B1EF0 = { 0xA3, 0x5D, 0x51, 0xE6, 0x56, 0xC8, 0x01, 0xCA, 0xE3, 0x77, 0xBF, 0xCD, 0xFF, 0x24, 0xDA, 0x4D }; + private static readonly byte[] key_457B28F0 = { 0xB1, 0xB3, 0x7F, 0x76, 0xC3, 0xFB, 0x88, 0xE6, 0xF8, 0x60, 0xD3, 0x35, 0x3C, 0xA3, 0x4E, 0xF3 }; + private static readonly byte[] key_457B0CF0 = { 0xAC, 0x34, 0xBA, 0xB1, 0x97, 0x8D, 0xAE, 0x6F, 0xBA, 0xE8, 0xB1, 0xD6, 0xDF, 0xDF, 0xF1, 0xA2 }; + private static readonly byte[] key_457B0BF0 = { 0x7B, 0x94, 0x72, 0x27, 0x4C, 0xCC, 0x54, 0x3B, 0xAE, 0xDF, 0x46, 0x37, 0xAC, 0x01, 0x4D, 0x87 }; + private static readonly byte[] key_457B0AF0 = { 0xE8, 0xBE, 0x2F, 0x06, 0xB1, 0x05, 0x2A, 0xB9, 0x18, 0x18, 0x03, 0xE3, 0xEB, 0x64, 0x7D, 0x26 }; + private static readonly byte[] key_457B08F0 = { 0xA4, 0x60, 0x8F, 0xAB, 0xAB, 0xDE, 0xA5, 0x65, 0x5D, 0x43, 0x3A, 0xD1, 0x5E, 0xC3, 0xFF, 0xEA }; + private static readonly byte[] key_457B06F0 = { 0x15, 0x07, 0x63, 0x26, 0xDB, 0xE2, 0x69, 0x34, 0x56, 0x08, 0x2A, 0x93, 0x4E, 0x4B, 0x8A, 0xB2 }; + private static readonly byte[] key_457B05F0 = { 0x40, 0x9B, 0xC6, 0x9B, 0xA9, 0xFB, 0x84, 0x7F, 0x72, 0x21, 0xD2, 0x36, 0x96, 0x55, 0x09, 0x74 }; + private static readonly byte[] key_76202403 = { 0xF3, 0xAC, 0x6E, 0x7C, 0x04, 0x0A, 0x23, 0xE7, 0x0D, 0x33, 0xD8, 0x24, 0x73, 0x39, 0x2B, 0x4A }; + private static readonly byte[] key_3ACE4DCE = + { + 0x2F, 0x66, 0xAE, 0x00, 0x01, 0x02, 0x66, 0xEE, 0xA7, 0xC6, 0x58, 0x0C, 0x01, 0x12, 0xB2, 0x88, + 0xE9, 0x9C, 0x04, 0x92, 0x4D, 0xD1, 0xB8, 0x3D, 0x7E, 0x4C, 0x73, 0xDD, 0xF9, 0x20, 0x1F, 0x05, + 0x67, 0x01, 0x54, 0x4F, 0xB1, 0x41, 0x34, 0xEF, 0xC2, 0x4D, 0x9A, 0x5A, 0x6B, 0x21, 0xAA, 0xF6, + 0x6E, 0x03, 0xD5, 0xDE, 0x3E, 0x24, 0xE4, 0x27, 0x1A, 0x19, 0x5E, 0x9C, 0x78, 0x1F, 0x5C, 0x88, + 0x27, 0x8F, 0x47, 0xCD, 0x95, 0x12, 0x88, 0x70, 0x32, 0xFB, 0x5F, 0x1F, 0x21, 0xB1, 0x39, 0x14, + 0x93, 0x46, 0x3D, 0x07, 0xB5, 0x83, 0xD2, 0x7D, 0xFF, 0x25, 0x75, 0xD2, 0x33, 0x4B, 0xFD, 0xDB, + 0x7C, 0x88, 0xFF, 0x89, 0xB3, 0x74, 0x01, 0x8D, 0xAA, 0xFC, 0xE4, 0x2E, 0x52, 0x6E, 0xB6, 0x1F, + 0x98, 0x74, 0x62, 0xD9, 0xB4, 0xFA, 0x81, 0x4F, 0xE9, 0xCC, 0xDB, 0xA7, 0x1C, 0x4E, 0x84, 0x6F, + 0xB0, 0x8B, 0xA4, 0x0E, 0x8B, 0x41, 0x72, 0x30, 0xDA, 0xBB, 0x4C, 0x03, 0x87, 0x83, 0x42, 0xD9 + }; + private static readonly byte[] key_03000000 = + { + 0x22, 0x4E, 0x3B, 0x01, 0xDE, 0xC8, 0x3F, 0x2C, 0x25, 0x00, 0x07, 0x9E, 0x16, 0x48, 0xBC, 0xCB, + 0xAE, 0x1D, 0x13, 0x4B, 0x34, 0xBB, 0x73, 0x83, 0xFA, 0x6A, 0xF9, 0xA1, 0xF3, 0xAE, 0x8E, 0xB7, + 0x6A, 0x25, 0x73, 0x6B, 0x0A, 0xB7, 0x7A, 0x1D, 0xCA, 0x3A, 0x75, 0x34, 0x46, 0x69, 0xD5, 0x52, + 0x6D, 0x62, 0xEC, 0x80, 0x5E, 0xB1, 0xD0, 0x64, 0xE4, 0x1C, 0x1E, 0x29, 0x65, 0x9F, 0x7D, 0xC5, + 0x4D, 0x71, 0x4F, 0xA9, 0xB8, 0xBE, 0xF9, 0xB4, 0x9E, 0xA8, 0x99, 0x63, 0x2C, 0x26, 0x8A, 0x68, + 0x77, 0xF5, 0x6B, 0x8E, 0xAC, 0xAC, 0x15, 0x8A, 0x1E, 0xD6, 0x40, 0xE0, 0x11, 0xE0, 0xB7, 0x8D, + 0x30, 0x04, 0x37, 0x73, 0x3A, 0x26, 0x5E, 0xCE, 0x66, 0x31, 0x73, 0x3C, 0xAB, 0x5A, 0xFF, 0xD0, + 0x87, 0xF8, 0x38, 0x4E, 0x88, 0x0F, 0x45, 0x65, 0x26, 0x5D, 0xDF, 0xD7, 0x49, 0x76, 0xCC, 0xB8, + 0xC5, 0x21, 0x9F, 0xCB, 0x85, 0x6F, 0x19, 0xAF, 0x39, 0x4F, 0x72, 0x9F, 0x79, 0x07, 0xFD, 0x07 + }; + + // sceKernelWaitSema + public static int sceMesgLed_driver_2CB700EC(Span modData, int size, out int newSize) + { + var ret = Decrypt(0x457B9AF0, key_457B9AF0, 0x5B, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B93F0, key_457B93F0, 0x5B, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B92F0, key_457B92F0, 0x5B, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B91F0, key_457B91F0, 0x5B, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B90F0, key_457B90F0, 0x5B, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B8AF0, key_457B8AF0, 0x5B, modData, size, out newSize, 0, null, 6, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B80F0, key_457B80F0, 0x5B, modData, size, out newSize, 0, null, 6, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B28F0, key_457B28F0, 0x5B, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B1EF0, key_457B1EF0, 0x5B, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B10F0, key_457B10F0, 0x5B, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B0CF0, key_457B0CF0, 0x5B, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B0BF0, key_457B0BF0, 0x5B, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B0AF0, key_457B0AF0, 0x5B, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B08F0, key_457B08F0, 0x5B, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B06F0, key_457B06F0, 0x5B, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x457B05F0, key_457B05F0, 0x5B, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x76202403, key_76202403, 0x5B, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x3ACE4DCE, key_3ACE4DCE, 0x5B, modData, size, out newSize, 0, null, 1, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x03000000, key_03000000, 0x46, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + return ret; + } + + // sceKernelPollSema + static int sceMesgLed_driver_308D37FF(Span modData, int size, out int newSize) => sceMesgLed_driver_2CB700EC(modData, size, out newSize); + + private static readonly byte[] key_B2B91F0 = { 0x46, 0x1D, 0xC9, 0xC2, 0x1D, 0x44, 0xA6, 0x68, 0xF2, 0x06, 0x37, 0xBF, 0x62, 0xCD, 0x11, 0x9E }; + + // sceKernelWaitSema + public static int sceResmgr_9DC14891(Span modData, int size, out int newSize) + { + return Decrypt(0xB2B91F0, key_B2B91F0, 0x5C, modData, size, out newSize, 0, null, 9, null, null); + } + + private static readonly byte[] key_D91605F0 = { 0xB8, 0x8C, 0x45, 0x8B, 0xB6, 0xE7, 0x6E, 0xB8, 0x51, 0x59, 0xA6, 0x53, 0x7C, 0x5E, 0x86, 0x31 }; + private static readonly byte[] key_D91606F0 = { 0xED, 0x10, 0xE0, 0x36, 0xC4, 0xFE, 0x83, 0xF3, 0x75, 0x70, 0x5E, 0xF6, 0xA4, 0x40, 0x05, 0xF7 }; + private static readonly byte[] key_D9160AF0 = { 0x10, 0xA9, 0xAC, 0x16, 0xAE, 0x19, 0xC0, 0x7E, 0x3B, 0x60, 0x77, 0x86, 0x01, 0x6F, 0xF2, 0x63 }; + private static readonly byte[] key_D9160BF0 = { 0x83, 0x83, 0xF1, 0x37, 0x53, 0xD0, 0xBE, 0xFC, 0x8D, 0xA7, 0x32, 0x52, 0x46, 0x0A, 0xC2, 0xC2 }; + private static readonly byte[] key_D91610F0 = { 0x89, 0x07, 0x73, 0xB4, 0x09, 0x08, 0x3F, 0x54, 0x31, 0x87, 0x00, 0xF3, 0x35, 0x14, 0x55, 0xCC }; + private static readonly byte[] key_D91611F0 = { 0x61, 0xB0, 0xC0, 0x58, 0x71, 0x57, 0xD9, 0xFA, 0x74, 0x67, 0x0E, 0x5C, 0x7E, 0x6E, 0x95, 0xB9 }; + private static readonly byte[] key_D91612F0 = { 0x9E, 0x20, 0xE1, 0xCD, 0xD7, 0x88, 0xDE, 0xC0, 0x31, 0x9B, 0x10, 0xAF, 0xC5, 0xB8, 0x73, 0x23 }; + private static readonly byte[] key_D91613F0 = { 0xEB, 0xFF, 0x40, 0xD8, 0xB4, 0x1A, 0xE1, 0x66, 0x91, 0x3B, 0x8F, 0x64, 0xB6, 0xFC, 0xB7, 0x12 }; + private static readonly byte[] key_D91614F0 = { 0xFD, 0xF7, 0xB7, 0x3C, 0x9F, 0xD1, 0x33, 0x95, 0x11, 0xB8, 0xB5, 0xBB, 0x54, 0x23, 0x73, 0x85 }; + private static readonly byte[] key_D91617F0 = { 0x02, 0xFA, 0x48, 0x73, 0x75, 0xAF, 0xAE, 0x0A, 0x67, 0x89, 0x2B, 0x95, 0x4B, 0x09, 0x87, 0xA3 }; + private static readonly byte[] key_D91618F0 = { 0x96, 0x96, 0x7C, 0xC3, 0xF7, 0x12, 0xDA, 0x62, 0x1B, 0xF6, 0x9A, 0x9A, 0x44, 0x44, 0xBC, 0x48 }; + private static readonly byte[] key_D9161AF0 = { 0x27, 0xE5, 0xA7, 0x49, 0x52, 0xE1, 0x94, 0x67, 0x35, 0x66, 0x91, 0x0C, 0xE8, 0x9A, 0x25, 0x24 }; + private static readonly byte[] key_D9161EF0 = { 0x5B, 0x4A, 0xD2, 0xF6, 0x49, 0xD4, 0xEB, 0x0D, 0xC0, 0x0F, 0xCB, 0xA8, 0x15, 0x2F, 0x55, 0x08 }; + private static readonly byte[] key_D91628F0 = { 0x49, 0xA4, 0xFC, 0x66, 0xDC, 0xE7, 0x62, 0x21, 0xDB, 0x18, 0xA7, 0x50, 0xD6, 0xA8, 0xC1, 0xB6 }; + private static readonly byte[] key_D91680F0 = { 0x2C, 0x22, 0x9B, 0x12, 0x36, 0x74, 0x11, 0x67, 0x49, 0xD1, 0xD1, 0x88, 0x92, 0xF6, 0xA1, 0xD8 }; + private static readonly byte[] key_D91681F0 = { 0x52, 0xB6, 0x36, 0x6C, 0x8C, 0x46, 0x7F, 0x7A, 0xCC, 0x11, 0x62, 0x99, 0xC1, 0x99, 0xBE, 0x98 }; + private static readonly byte[] key_D91690F0 = { 0x42, 0x61, 0xE2, 0x57, 0x94, 0x49, 0x42, 0xB5, 0xAA, 0x6D, 0x0D, 0x08, 0x3D, 0x24, 0xF7, 0x4B }; + private static readonly byte[] key_8004FD03 = { 0xF4, 0xAE, 0xF4, 0xE1, 0x86, 0xDD, 0xD2, 0x9C, 0x7C, 0xC5, 0x42, 0xA6, 0x95, 0xA0, 0x83, 0x88 }; + private static readonly byte[] key_C0CB167C = + { + 0x8F, 0xAA, 0x27, 0x39, 0x65, 0x94, 0xA2, 0x17, 0x41, 0xBF, 0x28, 0xF2, 0x58, 0xAA, 0x77, 0x0F, + 0xBA, 0xD2, 0x89, 0x91, 0xC3, 0xD4, 0x79, 0xB5, 0xD1, 0xA6, 0xB9, 0xFB, 0xD4, 0x40, 0x19, 0xA0, + 0x11, 0x1A, 0x11, 0x1E, 0x26, 0x8D, 0x20, 0x82, 0xEB, 0x31, 0x39, 0xA7, 0xE4, 0x69, 0xDC, 0xFF, + 0x4F, 0x04, 0xE2, 0xCF, 0x22, 0x41, 0x9A, 0xE4, 0x48, 0xDC, 0xE4, 0x81, 0x84, 0xAA, 0x20, 0x5D, + 0x55, 0x7B, 0xB3, 0xE3, 0xCE, 0xB4, 0xEB, 0x18, 0x73, 0x52, 0xF4, 0x4E, 0xD4, 0x52, 0x88, 0x24, + 0x37, 0x32, 0x1D, 0xFF, 0xCC, 0xCD, 0x41, 0x91, 0xC3, 0xF6, 0x72, 0x94, 0xFB, 0x25, 0x01, 0xEB, + 0x6A, 0x94, 0x98, 0x14, 0x3C, 0xC1, 0x46, 0xF2, 0xD2, 0xDC, 0xF6, 0xDF, 0x77, 0x6C, 0x8A, 0xBC, + 0xE2, 0xDD, 0xCC, 0xDA, 0xD4, 0x6F, 0xB4, 0x33, 0x0F, 0xE2, 0xDC, 0xA2, 0x69, 0x97, 0x33, 0x08, + 0x41, 0xFD, 0x86, 0x4E, 0xF6, 0x01, 0x81, 0x0B, 0x45, 0x38, 0x20, 0xB6, 0xC0, 0x36, 0x9B, 0xF3 + }; + private static readonly byte[] key_08000000 = + { + 0x5B, 0x16, 0x91, 0x75, 0x44, 0xC5, 0xC5, 0x02, 0x6C, 0x76, 0x94, 0xC0, 0x55, 0xF1, 0x12, 0x95, + 0x71, 0x93, 0x91, 0x7E, 0x81, 0xD2, 0x77, 0x31, 0xF1, 0x28, 0x30, 0x70, 0x9B, 0x73, 0x77, 0x4A, + 0x11, 0xD7, 0x56, 0xF1, 0x0E, 0x4C, 0xC1, 0xB0, 0x92, 0x04, 0xE4, 0xE2, 0xAC, 0xA8, 0x46, 0x07, + 0x85, 0xEA, 0x69, 0x9A, 0xD7, 0xD2, 0xEC, 0xF1, 0xA0, 0x43, 0x42, 0x1C, 0xC6, 0xAF, 0xC6, 0x21, + 0xE8, 0x24, 0x06, 0x29, 0x01, 0xBC, 0xB6, 0x59, 0x4D, 0x78, 0x0D, 0x00, 0xD3, 0xFD, 0x95, 0xE7, + 0x3F, 0xD1, 0x45, 0x16, 0xDB, 0x0A, 0x01, 0x18, 0x0B, 0x70, 0xE4, 0x8D, 0x8B, 0xF9, 0xC4, 0x5A, + 0x85, 0x10, 0xDB, 0x78, 0x05, 0xDF, 0xFB, 0x4A, 0xA9, 0xDD, 0x31, 0xC6, 0x6A, 0xC1, 0x98, 0xB4, + 0x65, 0x90, 0x58, 0xF5, 0x65, 0x3C, 0xCD, 0xB0, 0x6A, 0x2F, 0xF6, 0xFD, 0xA4, 0xC7, 0x86, 0x62, + 0xE6, 0xF8, 0x5E, 0xE8, 0x66, 0x16, 0x20, 0x92, 0xF0, 0x8E, 0xEA, 0x17, 0x9F, 0x1A, 0xF3, 0xDD + }; + + // sceKernelWaitSema + public static int sceMesgLed_driver_337D0DD3(Span modData, int size, out int newSize) + { + var ret = Decrypt(0xD91690F0, key_D91690F0, 0x5d, modData, size, out newSize, 0, null, 9, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91681F0, key_D91681F0, 0x5d, modData, size, out newSize, 0, null, 6, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91680F0, key_D91680F0, 0x5d, modData, size, out newSize, 0, null, 6, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD9161AF0, key_D9161AF0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91618F0, key_D91618F0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91617F0, key_D91617F0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91614F0, key_D91614F0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91613F0, key_D91613F0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91612F0, key_D91612F0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91628F0, key_D91628F0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD9161EF0, key_D9161EF0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91610F0, key_D91610F0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91611F0, key_D91611F0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD9160BF0, key_D9160BF0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD9160AF0, key_D9160AF0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91606F0, key_D91606F0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD91605F0, key_D91605F0, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x8004FD03, key_8004FD03, 0x5d, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xC0CB167C, key_C0CB167C, 0x5d, modData, size, out newSize, 0, null, 1, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x08000000, key_08000000, 0x4B, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + return ret; + } + + // sceKernelPollSema + static int sceMesgLed_driver_792A6126(Span modData, int size, out int newSize) => sceMesgLed_driver_337D0DD3(modData, size, out newSize); + + private static readonly byte[] key_7B0528F0 = { 0xCE, 0x40, 0xE0, 0x47, 0xA9, 0x97, 0xCA, 0x68, 0xAD, 0x40, 0x1C, 0x68, 0xC3, 0xFF, 0xC2, 0x7A }; + private static readonly byte[] key_7B051EF0 = { 0xDC, 0xAE, 0xCE, 0xD7, 0x3C, 0xA4, 0x43, 0x44, 0xB6, 0x57, 0x70, 0x90, 0x00, 0x78, 0x56, 0xC4 }; + private static readonly byte[] key_7B0510F0 = { 0x1C, 0x0D, 0x41, 0x05, 0xE9, 0x4B, 0x1E, 0x31, 0x5C, 0xC8, 0xD7, 0x33, 0xE3, 0xC4, 0xC2, 0xBE }; + private static readonly byte[] key_7B0508F0 = { 0xC9, 0x7D, 0x3E, 0x0A, 0x54, 0x81, 0x6E, 0xC7, 0x13, 0x74, 0x99, 0x74, 0x62, 0x18, 0xE7, 0xDD }; + private static readonly byte[] key_7B0506F0 = { 0x78, 0x1A, 0xD2, 0x87, 0x24, 0xBD, 0xA2, 0x96, 0x18, 0x3F, 0x89, 0x36, 0x72, 0x90, 0x92, 0x85 }; + private static readonly byte[] key_7B0505F0 = { 0x2D, 0x86, 0x77, 0x3A, 0x56, 0xA4, 0x4F, 0xDD, 0x3C, 0x16, 0x71, 0x93, 0xAA, 0x8E, 0x11, 0x43 }; + private static readonly byte[] key_0A35EA03 = { 0xF9, 0x48, 0x38, 0x0C, 0x96, 0x88, 0xA7, 0x74, 0x4F, 0x65, 0xA0, 0x54, 0xC2, 0x76, 0xD9, 0xB8 }; + private static readonly byte[] key_BB67C59F = + { + 0x82, 0x78, 0x73, 0x69, 0x0D, 0x87, 0x1F, 0xE2, 0x49, 0xD6, 0x1F, 0xA0, 0x58, 0xDA, 0xF8, 0x47, + 0x7E, 0x67, 0x2A, 0xE9, 0xE1, 0x01, 0xBE, 0xC0, 0x6F, 0x54, 0x8D, 0x35, 0x9D, 0xA3, 0x73, 0x0E, + 0xF9, 0x20, 0x47, 0x84, 0xD3, 0xDA, 0xD3, 0x40, 0xF6, 0x1A, 0x37, 0x71, 0x9C, 0xB6, 0x71, 0xBD, + 0x38, 0x15, 0x8D, 0x19, 0x50, 0xE0, 0x35, 0x51, 0xC8, 0xDD, 0x4D, 0x3F, 0xFE, 0xFE, 0x48, 0xDF, + 0xB0, 0xC2, 0xCA, 0x0A, 0x47, 0x2A, 0x1D, 0x6E, 0xFA, 0x64, 0x14, 0x98, 0xED, 0x38, 0xDC, 0x4F, + 0x2D, 0x52, 0x60, 0x44, 0x79, 0x99, 0x79, 0x63, 0xB6, 0x76, 0x90, 0x69, 0x6A, 0x95, 0x42, 0x20, + 0x8B, 0x12, 0x7D, 0xBA, 0x32, 0xAB, 0x36, 0x81, 0x1F, 0x3F, 0xA3, 0xEB, 0x2F, 0x5A, 0x7A, 0x06, + 0x42, 0xC5, 0x24, 0x0B, 0x2C, 0xE2, 0x9D, 0x6F, 0x6B, 0x3B, 0x32, 0x59, 0x90, 0x42, 0x75, 0xE6, + 0xF9, 0x96, 0x16, 0x51, 0x68, 0x7A, 0x45, 0xDE, 0xE8, 0x41, 0x5A, 0xEC, 0x35, 0x7B, 0x6F, 0x05 + }; + private static readonly byte[] key_09000000 = + { + 0x88, 0xD7, 0x76, 0xF5, 0xB7, 0x6D, 0xEC, 0x0E, 0x00, 0x0B, 0x85, 0xE6, 0x4A, 0x37, 0x9B, 0xC9, + 0x00, 0x95, 0xEA, 0x7A, 0xAD, 0x66, 0x67, 0x09, 0x05, 0xF2, 0x09, 0x52, 0x47, 0x27, 0x8E, 0x4E, + 0x57, 0x83, 0xF7, 0x5D, 0x1F, 0x90, 0x11, 0x0E, 0xEF, 0xF6, 0x97, 0x39, 0x83, 0xA1, 0x65, 0xD0, + 0x11, 0xCA, 0x64, 0x96, 0x7A, 0xEF, 0xC9, 0x18, 0x6B, 0x7D, 0x97, 0x7A, 0xF0, 0x32, 0x28, 0xA6, + 0xE2, 0xE3, 0x86, 0x64, 0xDF, 0xAE, 0x03, 0xD2, 0xAD, 0x7E, 0x7F, 0x46, 0x2E, 0x5F, 0x02, 0x95, + 0xE9, 0x35, 0x5C, 0x17, 0xAD, 0x42, 0x54, 0x62, 0x84, 0x66, 0xC9, 0x35, 0x9C, 0x7B, 0x2A, 0xFA, + 0xD7, 0xDC, 0xD0, 0x2B, 0xDA, 0x89, 0x32, 0x7C, 0xD0, 0x77, 0xE6, 0xEE, 0xFE, 0xCD, 0x2B, 0xE0, + 0x87, 0xBB, 0xE1, 0xB5, 0xCE, 0x29, 0x11, 0x9A, 0x79, 0xF1, 0xA8, 0x71, 0xC0, 0x5E, 0x65, 0x39, + 0xFB, 0x6D, 0xB9, 0x37, 0xD4, 0x52, 0x74, 0x44, 0xE1, 0xC2, 0xBA, 0xBA, 0x3D, 0x2D, 0x4A, 0x35 + }; + + // sceKernelWaitSema + public static int sceMesgLed_driver_4EAB9850(Span modData, int size, out int newSize) + { + var ret = Decrypt(0x7B0528F0, key_7B0528F0, 0x5E, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x7B051EF0, key_7B051EF0, 0x5E, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x7B0510F0, key_7B0510F0, 0x5E, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x7B0508F0, key_7B0508F0, 0x5E, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x7B0506F0, key_7B0506F0, 0x5E, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x7B0505F0, key_7B0505F0, 0x5E, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x0A35EA03, key_0A35EA03, 0x5E, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xBB67C59F, key_BB67C59F, 0x5E, modData, size, out newSize, 0, null, 1, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x09000000, key_09000000, 0x4C, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + } + } + } + } + } + return ret; + } + + // sceKernelPollSema + static int sceMesgLed_driver_4BE02A12(Span modData, int size, out int newSize) => sceMesgLed_driver_4EAB9850(modData, size, out newSize); + + private static readonly byte[] key_ADF328F0 = { 0xE3, 0xB1, 0xC9, 0xB3, 0x4E, 0x07, 0x60, 0x49, 0xA7, 0x47, 0xFF, 0x7D, 0x19, 0xFA, 0x56, 0xA1 }; + private static readonly byte[] key_ADF31EF0 = { 0xF1, 0x5F, 0xE7, 0x23, 0xDB, 0x34, 0xE9, 0x65, 0xBC, 0x50, 0x93, 0x85, 0xDA, 0x7D, 0xC2, 0x1F }; + private static readonly byte[] key_ADF310F0 = { 0x23, 0x12, 0x46, 0x61, 0x9B, 0xE8, 0x3D, 0x3C, 0x4D, 0xD8, 0x58, 0xDE, 0xFA, 0x46, 0xC2, 0xDB }; + private static readonly byte[] key_ADF308F0 = { 0xF6, 0x62, 0x39, 0x6E, 0x26, 0x22, 0x4D, 0xCA, 0x02, 0x64, 0x16, 0x99, 0x7B, 0x9A, 0xE7, 0xB8 }; + private static readonly byte[] key_ADF306F0 = { 0x47, 0x05, 0xD5, 0xE3, 0x56, 0x1E, 0x81, 0x9B, 0x09, 0x2F, 0x06, 0xDB, 0x6B, 0x12, 0x92, 0xE0 }; + private static readonly byte[] key_ADF305F0 = { 0x12, 0x99, 0x70, 0x5E, 0x24, 0x07, 0x6C, 0xD0, 0x2D, 0x06, 0xFE, 0x7E, 0xB3, 0x0C, 0x11, 0x26 }; + private static readonly byte[] key_D67B3303 = { 0xC9, 0x03, 0x4F, 0x3C, 0xDD, 0x4F, 0xE8, 0xD0, 0x9A, 0xDD, 0xED, 0x74, 0x64, 0xDC, 0x5C, 0x35 }; + private static readonly byte[] key_7F24BDCD = + { + 0xB2, 0x97, 0x43, 0x75, 0x5E, 0x0C, 0xA7, 0x5E, 0x38, 0x53, 0x7D, 0x80, 0xD1, 0x6B, 0xEA, 0x68, + 0x86, 0x8D, 0x2B, 0xAD, 0x3B, 0x2D, 0x46, 0x47, 0x84, 0xF3, 0x1E, 0x56, 0xBB, 0xEE, 0x3A, 0x3C, + 0xE3, 0x7A, 0xF3, 0x6E, 0xAE, 0x77, 0xF6, 0x23, 0x16, 0xF3, 0x25, 0xCD, 0xFB, 0x8A, 0x01, 0x6F, + 0xB0, 0xDD, 0x3C, 0x44, 0x2F, 0x01, 0xE1, 0x00, 0xA1, 0x5F, 0xB8, 0x86, 0x86, 0x20, 0xB9, 0xD1, + 0xCE, 0x3D, 0xC5, 0x6E, 0x41, 0xB9, 0x11, 0x10, 0x57, 0x2F, 0x29, 0xE2, 0xC9, 0x4C, 0xFD, 0x08, + 0x3D, 0xC2, 0x18, 0x7E, 0x5C, 0xE2, 0xA2, 0x24, 0xD9, 0x01, 0x4B, 0xA1, 0x28, 0x4C, 0xC4, 0xAC, + 0xE2, 0x0E, 0x0A, 0xC4, 0xD2, 0x7F, 0xAA, 0x3A, 0x08, 0x62, 0x45, 0xF7, 0xCA, 0x8D, 0xC6, 0x18, + 0xF0, 0xDE, 0x12, 0x17, 0xAD, 0xCB, 0xB7, 0xF2, 0xCA, 0xC5, 0xA8, 0x56, 0xC1, 0xB3, 0x20, 0xB6, + 0x02, 0xE9, 0x31, 0x08, 0x3B, 0x44, 0x7C, 0xDE, 0x56, 0xB4, 0x3F, 0x12, 0x5D, 0xF0, 0x4F, 0x97 + }; + + private static readonly byte[] key_0C000000 = + { + 0x82, 0x4C, 0xA5, 0x18, 0xD3, 0xC8, 0x6E, 0xEA, 0x17, 0x41, 0x04, 0xDC, 0xEA, 0xC5, 0x01, 0xFC, + 0x97, 0xB1, 0x94, 0x54, 0x71, 0x19, 0x22, 0xEE, 0xE0, 0x2D, 0xE9, 0x83, 0x3D, 0x64, 0x30, 0xE6, + 0x42, 0x5C, 0x30, 0x5F, 0xEB, 0x41, 0xA0, 0xE0, 0x62, 0xC6, 0x63, 0xEE, 0x5D, 0xA5, 0x0D, 0x1E, + 0xC2, 0x10, 0x14, 0x49, 0x06, 0xC6, 0x93, 0x84, 0x71, 0xA5, 0x42, 0x63, 0x13, 0xF0, 0xB6, 0xD5, + 0x43, 0x51, 0x9E, 0xFA, 0x91, 0x0A, 0x7C, 0xE1, 0x58, 0x1B, 0x95, 0x25, 0x40, 0x11, 0xF1, 0x8D, + 0xB1, 0x01, 0x8D, 0x04, 0x09, 0x54, 0x5C, 0x54, 0xF5, 0x53, 0x08, 0xB0, 0x53, 0x85, 0xB4, 0xCE, + 0x0B, 0xF5, 0xC3, 0xFB, 0xC6, 0x55, 0x24, 0x0B, 0xF2, 0xC6, 0x2C, 0xE4, 0x0C, 0xF0, 0x05, 0x3C, + 0xD7, 0x6C, 0x39, 0xD5, 0x87, 0x22, 0x09, 0xF7, 0x3D, 0xC5, 0xA2, 0xFD, 0x55, 0x92, 0x3F, 0xB1, + 0xF6, 0xFE, 0xC8, 0x18, 0x1D, 0x6B, 0x04, 0x52, 0x5F, 0x8C, 0xE8, 0xE7, 0x26, 0x5A, 0x6E, 0x5A + }; + + // sceKernelWaitSema + public static int sceMesgLed_driver_21AFFAAC(Span modData, int size, out int newSize) + { + var ret = Decrypt(0xADF328F0, key_ADF328F0, 0x60, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xADF31EF0, key_ADF31EF0, 0x60, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xADF310F0, key_ADF310F0, 0x60, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xADF308F0, key_ADF308F0, 0x60, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xADF306F0, key_ADF306F0, 0x60, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xADF305F0, key_ADF305F0, 0x60, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD67B3303, key_D67B3303, 0x60, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x7F24BDCD, key_7F24BDCD, 0x60, modData, size, out newSize, 0, null, 1, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x0C000000, key_0C000000, 0x4F, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + } + } + } + } + } + + return ret; + } + + // sceKernelPollSema + static int sceMesgLed_driver_52B6E552(Span modData, int size, out int newSize) => sceMesgLed_driver_21AFFAAC(modData, size, out newSize); + + private static readonly byte[] key_279D28F0 = { 0xD2, 0xF4, 0x82, 0x58, 0xC3, 0x82, 0xDA, 0x73, 0xE9, 0xE2, 0x6F, 0x28, 0x81, 0x1F, 0xA6, 0xD3 }; + private static readonly byte[] key_279D1EF0 = { 0xC0, 0x1A, 0xAC, 0xC8, 0x56, 0xB1, 0x53, 0x5F, 0xF2, 0xF5, 0x03, 0xD0, 0x42, 0x98, 0x32, 0x6D }; + private static readonly byte[] key_279D10F0 = { 0x12, 0x57, 0x0D, 0x8A, 0x16, 0x6D, 0x87, 0x06, 0x03, 0x7D, 0xC8, 0x8B, 0x62, 0xA3, 0x32, 0xA9 }; + private static readonly byte[] key_279D08F0 = { 0xC7, 0x27, 0x72, 0x85, 0xAB, 0xA7, 0xF7, 0xF0, 0x4C, 0xC1, 0x86, 0xCC, 0xE3, 0x7F, 0x17, 0xCA }; + private static readonly byte[] key_279D06F0 = { 0x76, 0x40, 0x9E, 0x08, 0xDB, 0x9B, 0x3B, 0xA1, 0x47, 0x8A, 0x96, 0x8E, 0xF3, 0xF7, 0x62, 0x92 }; + private static readonly byte[] key_279D05F0 = { 0x23, 0xDC, 0x3B, 0xB5, 0xA9, 0x82, 0xD6, 0xEA, 0x63, 0xA3, 0x6E, 0x2B, 0x2B, 0xE9, 0xE1, 0x54 }; + private static readonly byte[] key_D66DF703 = { 0x22, 0x43, 0x57, 0x68, 0x2F, 0x41, 0xCE, 0x65, 0x4C, 0xA3, 0x7C, 0xC6, 0xC4, 0xAC, 0xF3, 0x60 }; + private static readonly byte[] key_1BC8D12B = + { + 0xAE, 0x11, 0x18, 0xE6, 0xED, 0xB2, 0xF1, 0xB2, 0xA8, 0xCC, 0xCA, 0xBF, 0xA9, 0x14, 0x80, 0x87, + 0x66, 0xF1, 0x2D, 0x87, 0xDA, 0xD3, 0x5E, 0xD3, 0xBF, 0xAF, 0xDF, 0xB5, 0x11, 0xC2, 0xDA, 0x4E, + 0x85, 0x09, 0x7C, 0x19, 0xA9, 0xB1, 0xF4, 0x80, 0x35, 0x10, 0xF7, 0x27, 0xA4, 0xB1, 0x52, 0x66, + 0x96, 0xA2, 0x68, 0x77, 0xDB, 0x9C, 0x76, 0x04, 0x09, 0x44, 0x87, 0x91, 0x06, 0xBA, 0xA4, 0x24, + 0x68, 0xA5, 0xBE, 0xD7, 0x4F, 0x73, 0x83, 0x7F, 0x0E, 0x60, 0x13, 0xAD, 0x60, 0xAA, 0xA5, 0xD7, + 0x80, 0x44, 0x3A, 0x3F, 0x5D, 0xE1, 0x6B, 0xD3, 0xD9, 0xE8, 0x4A, 0xF6, 0x57, 0xEB, 0x95, 0x5A, + 0x10, 0xA9, 0x9F, 0x4D, 0xDE, 0x2F, 0xE5, 0xCE, 0xE4, 0xDD, 0x82, 0x5D, 0x05, 0x57, 0x22, 0xCA, + 0xA6, 0xE3, 0xA2, 0xCD, 0x81, 0x16, 0xE4, 0x5A, 0x7D, 0x0E, 0x9B, 0xC0, 0x26, 0x0D, 0xC6, 0x82, + 0x02, 0xC0, 0x9B, 0x0C, 0xE3, 0x7C, 0xD3, 0xCD, 0xF4, 0x33, 0x72, 0x4D, 0xFC, 0x2C, 0xAA, 0x48 + }; + + private static readonly byte[] key_0D000000 = + { + 0xF5, 0x07, 0xA4, 0x47, 0xD7, 0xE0, 0x29, 0x25, 0xB2, 0xC8, 0xE3, 0x95, 0x3E, 0x5E, 0x69, 0xE0, + 0x6F, 0xA5, 0x0D, 0xCF, 0x2D, 0x6A, 0xB5, 0x6C, 0xF1, 0x7D, 0x65, 0xD2, 0x81, 0xD5, 0xBE, 0xDA, + 0xFC, 0xE9, 0xBE, 0x4F, 0xCE, 0x25, 0x95, 0x84, 0xE7, 0x94, 0x23, 0x4A, 0x99, 0x26, 0x48, 0x6F, + 0xFC, 0xCB, 0xC7, 0xDB, 0x99, 0x7A, 0x54, 0x5D, 0x06, 0x07, 0xDF, 0xD8, 0x50, 0x97, 0x48, 0x19, + 0x49, 0x72, 0x0F, 0x16, 0x0F, 0xE6, 0x94, 0x41, 0x70, 0x64, 0xC2, 0x69, 0xCD, 0x22, 0x97, 0xA4, + 0xB7, 0xBD, 0x3F, 0xF8, 0xD9, 0x60, 0xBA, 0x3E, 0x7C, 0xCE, 0x5E, 0x98, 0xBF, 0xAC, 0x5B, 0x91, + 0x01, 0xF3, 0xF1, 0x42, 0xB0, 0xE9, 0xDA, 0x2C, 0xE1, 0x62, 0x75, 0xA1, 0x35, 0x3C, 0xCE, 0x57, + 0x1D, 0xB0, 0xC1, 0x4A, 0xD5, 0xC2, 0xD0, 0x98, 0xAF, 0x64, 0x78, 0x84, 0xB7, 0xDF, 0x5B, 0x57, + 0x67, 0x74, 0xF1, 0x20, 0x57, 0x7A, 0x5F, 0xFF, 0x20, 0x8A, 0xE4, 0x29, 0xEB, 0x12, 0x5E, 0xF4 + }; + + // sceKernelWaitSema + public static int sceMesgLed_driver_C00DAD75(Span modData, int size, out int newSize) + { + var ret = Decrypt(0x279D28F0, key_279D28F0, 0x61, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x279D1EF0, key_279D1EF0, 0x61, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x279D10F0, key_279D10F0, 0x61, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x279D08F0, key_279D08F0, 0x61, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x279D06F0, key_279D06F0, 0x61, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x279D05F0, key_279D05F0, 0x61, modData, size, out newSize, 0, null, 4, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD66DF703, key_D66DF703, 0x61, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x1BC8D12B, key_1BC8D12B, 0x61, modData, size, out newSize, 0, null, 1, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x0D000000, key_0D000000, 0x50, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + } + } + } + } + } + return ret; + } + + // sceKernelPollSema + static int sceMesgLed_driver_F8485C9C(Span modData, int size, out int newSize) => sceMesgLed_driver_C00DAD75(modData, size, out newSize); + + private static readonly byte[] key_E92428F0 = { 0xAA, 0x14, 0x26, 0xB4, 0x4C, 0xB9, 0xF4, 0x58, 0xC1, 0x6F, 0xCD, 0x42, 0x70, 0x2E, 0x12, 0x6A }; + private static readonly byte[] key_E92428F0_xor = { 0xCB, 0x81, 0xEE, 0x3B, 0xDC, 0x87, 0x1E, 0xA1, 0xC8, 0x14, 0xB8, 0xFF, 0x92, 0x3F, 0xB7, 0xC0 }; + private static readonly byte[] key_E9241EF0 = { 0xEF, 0x4A, 0x8E, 0x6B, 0x24, 0x1A, 0xD5, 0xDC, 0xE0, 0xE5, 0x9D, 0xAD, 0xE6, 0x7F, 0xBD, 0x0E }; + private static readonly byte[] key_E9241EF0_xor = { 0x02, 0x99, 0xCE, 0xA6, 0x38, 0x38, 0x32, 0x84, 0x0E, 0xCF, 0x86, 0x6B, 0xB4, 0xEE, 0x3C, 0x77 }; + private static readonly byte[] key_E92410F0 = { 0x71, 0xBE, 0x93, 0xCD, 0x96, 0x65, 0xBC, 0x57, 0xF6, 0xE5, 0xE9, 0xD7, 0x1C, 0x6A, 0xD5, 0xAA }; + private static readonly byte[] key_E92410F0_xor = { 0x36, 0xEF, 0x82, 0x4E, 0x74, 0xFB, 0x17, 0x5B, 0x14, 0x14, 0x05, 0xF3, 0xB3, 0x8A, 0x76, 0x18 }; + private static readonly byte[] key_E92408F0 = { 0x24, 0x84, 0xBE, 0x35, 0xF0, 0xC5, 0x91, 0xA3, 0x3D, 0xA5, 0x94, 0x12, 0x8F, 0xD0, 0x4C, 0x01 }; + private static readonly byte[] key_E92408F0_xor = { 0x2A, 0x1B, 0xF2, 0xD5, 0x11, 0xF8, 0x93, 0x04, 0x9B, 0xF7, 0xB1, 0x7F, 0xC7, 0x8F, 0x6A, 0x11 }; + private static readonly byte[] key_89742B04 = { 0xD7, 0xEB, 0xC9, 0x24, 0x7E, 0x23, 0x3D, 0x89, 0x46, 0xE7, 0x2E, 0x47, 0xAD, 0xDB, 0x0D, 0x09 }; + private static readonly byte[] key_89742B04_xor = { 0xFF, 0x5E, 0xF1, 0xE9, 0xB1, 0xC9, 0x3E, 0xC5, 0xDB, 0xE0, 0x67, 0x82, 0x95, 0x3A, 0x8E, 0xA5 }; + + public static int sceMesgLed_driver_CED2C075(Span modData, int size, out int newSize, ReadOnlySpan versionKey) + { + var ret = Decrypt(0xE92428F0, key_E92428F0, 0x65, modData, size, out newSize, 0, null, 3, key_E92428F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0xE9241EF0, key_E9241EF0, 0x65, modData, size, out newSize, 0, null, 3, key_E9241EF0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0xE92410F0, key_E92410F0, 0x65, modData, size, out newSize, 0, null, 3, key_E92410F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0xE92408F0, key_E92408F0, 0x65, modData, size, out newSize, 0, null, 3, key_E92408F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x89742B04, key_89742B04, 0x65, modData, size, out newSize, 0, null, 3, key_89742B04_xor, versionKey); + } + } + } + } + return ret; + } + + private static readonly byte[] key_0DAA28F0 = { 0x81, 0x79, 0xDB, 0x6B, 0xC1, 0x04, 0x71, 0xE7, 0x64, 0x90, 0xAA, 0x71, 0xC2, 0x94, 0x92, 0x76 }; + private static readonly byte[] key_0DAA28F0_xor = { 0x3C, 0x8B, 0xAB, 0xB0, 0x07, 0x92, 0xAC, 0x1B, 0x2B, 0xCF, 0x10, 0xAA, 0xBD, 0x9F, 0x5B, 0xD8 }; + private static readonly byte[] key_0DAA1EF0 = { 0x1C, 0x3B, 0xD7, 0xA4, 0xA6, 0x41, 0x62, 0x98, 0xA7, 0xDF, 0x5B, 0x16, 0xDA, 0x53, 0x62, 0xF1 }; + private static readonly byte[] key_0DAA1EF0_xor = { 0x87, 0x66, 0x42, 0x6E, 0x6D, 0xB8, 0xC6, 0x28, 0x10, 0x7F, 0xFD, 0xBD, 0x10, 0x7E, 0x7E, 0x31 }; + private static readonly byte[] key_0DAA10F0 = { 0xA9, 0x81, 0x71, 0x9D, 0x92, 0x2D, 0xCC, 0xEE, 0x44, 0x1C, 0x0E, 0x37, 0x7A, 0xF6, 0xE2, 0x3E }; + private static readonly byte[] key_0DAA10F0_xor = { 0xD3, 0x43, 0xA8, 0x49, 0x79, 0x61, 0x82, 0x63, 0x40, 0xBF, 0xA3, 0xEF, 0xB0, 0x99, 0xED, 0x48 }; + private static readonly byte[] key_0DAA06F0 = { 0xCA, 0x26, 0x7D, 0xA2, 0xB9, 0xCE, 0x24, 0x6E, 0xFD, 0x32, 0xA8, 0x97, 0xF4, 0x7C, 0x19, 0x19 }; + private static readonly byte[] key_0DAA06F0_xor = { 0x77, 0x32, 0x20, 0x31, 0xDF, 0x7F, 0x4B, 0x1C, 0x8D, 0xD7, 0xD2, 0xC3, 0x23, 0xA9, 0xF8, 0xA9 }; + + public static int sceMesgLed_driver_EBB4613D(Span modData, int size, out int newSize, ReadOnlySpan versionKey) + { + var ret = Decrypt(0x0DAA28F0, key_0DAA28F0, 0x65, modData, size, out newSize, 0, null, 5, key_0DAA28F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x0DAA1EF0, key_0DAA1EF0, 0x65, modData, size, out newSize, 0, null, 5, key_0DAA1EF0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x0DAA10F0, key_0DAA10F0, 0x65, modData, size, out newSize, 0, null, 5, key_0DAA10F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x0DAA06F0, key_0DAA06F0, 0x65, modData, size, out newSize, 0, null, 5, key_0DAA06F0_xor, versionKey); + } + } + } + + return ret; + } + + private static readonly byte[] key_692828F0 = { 0x49, 0x85, 0x86, 0x1E, 0xB9, 0x99, 0xBD, 0xA5, 0x92, 0xE9, 0xF9, 0xD1, 0x26, 0x43, 0x7E, 0xB5 }; + private static readonly byte[] key_692828F0_xor = { 0x88, 0xD5, 0x04, 0xD5, 0xF8, 0x27, 0x24, 0x13, 0x62, 0x4B, 0xBB, 0x16, 0x44, 0x1E, 0x43, 0x50 }; + private static readonly byte[] key_69281EF0 = { 0x05, 0x94, 0x7F, 0xE2, 0x80, 0x5C, 0x7E, 0xAB, 0x03, 0x66, 0x40, 0x85, 0x3C, 0xD1, 0x2C, 0xFA }; + private static readonly byte[] key_69281EF0_xor = { 0x10, 0xCD, 0x0D, 0xD5, 0x25, 0xC6, 0x28, 0x87, 0x34, 0xC6, 0x0E, 0xBE, 0x6D, 0xE7, 0x19, 0x7D }; + private static readonly byte[] key_692810F0 = { 0xB8, 0xE7, 0xAC, 0xEE, 0x3F, 0x50, 0xB9, 0xA0, 0x66, 0xC8, 0xBD, 0x5E, 0x21, 0x53, 0xF1, 0xD5 }; + private static readonly byte[] key_692810F0_xor = { 0x21, 0x52, 0x5D, 0x76, 0xF6, 0x81, 0x0F, 0x15, 0x2F, 0x4A, 0x40, 0x89, 0x63, 0xA0, 0x10, 0x55 }; + private static readonly byte[] key_692808F0 = { 0x77, 0x66, 0xAD, 0xF8, 0x69, 0x1D, 0x04, 0x6A, 0x37, 0xFE, 0x46, 0x4C, 0xEB, 0xE2, 0x4C, 0xDC }; + private static readonly byte[] key_692808F0_xor = { 0xB6, 0x67, 0x15, 0x92, 0x49, 0x3D, 0x4D, 0x8A, 0x21, 0xE2, 0xF9, 0x0B, 0x7E, 0x24, 0x64, 0xF3 }; + private static readonly byte[] key_F5F12304 = { 0xC0, 0xF0, 0x2D, 0x65, 0xC6, 0xA6, 0x56, 0x9B, 0xB8, 0xE8, 0x0E, 0x82, 0x3B, 0x56, 0xE2, 0xA9 }; + private static readonly byte[] key_F5F12304_xor = { 0x21, 0xEA, 0xBE, 0x48, 0x63, 0xDE, 0x22, 0x4B, 0x3A, 0xDB, 0x81, 0x53, 0x30, 0x03, 0x54, 0x92 }; + + public static int sceMesgLed_driver_C7D1C16B(Span modData, int size, out int newSize, ReadOnlySpan versionKey) + { + var ret = Decrypt(0x692828F0, key_692828F0, 0x66, modData, size, out newSize, 0, null, 3, key_692828F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x69281EF0, key_69281EF0, 0x66, modData, size, out newSize, 0, null, 3, key_69281EF0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x692810F0, key_692810F0, 0x66, modData, size, out newSize, 0, null, 3, key_692810F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x692808F0, key_692808F0, 0x66, modData, size, out newSize, 0, null, 3, key_692808F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0xF5F12304, key_F5F12304, 0x66, modData, size, out newSize, 0, null, 3, key_F5F12304_xor, versionKey); + } + } + } + } + return ret; + } + + private static readonly byte[] key_E1ED28F0 = { 0xF2, 0x1A, 0x92, 0x0C, 0x33, 0xC2, 0x5C, 0xFF, 0x30, 0x73, 0xF6, 0x94, 0x50, 0xAD, 0x33, 0x34 }; + private static readonly byte[] key_E1ED28F0_xor = { 0xE2, 0x04, 0x7A, 0xE7, 0x51, 0x69, 0xE2, 0xF5, 0xC5, 0x94, 0xDF, 0xC9, 0x18, 0x90, 0x43, 0xC8 }; + private static readonly byte[] key_E1ED1EF0 = { 0x50, 0xAC, 0x80, 0x31, 0x36, 0x27, 0xCE, 0x39, 0x43, 0xDA, 0xC7, 0x77, 0x6A, 0x1F, 0x8B, 0x1D }; + private static readonly byte[] key_E1ED1EF0_xor = { 0x0A, 0x97, 0x2A, 0x3C, 0xAD, 0x20, 0x09, 0xAC, 0xB0, 0x72, 0xB8, 0xBF, 0x1A, 0x01, 0x42, 0x8B }; + private static readonly byte[] key_E1ED10F0 = { 0x2A, 0xCE, 0x63, 0xF9, 0xA7, 0x93, 0x2A, 0x6B, 0xF1, 0xDB, 0x41, 0x70, 0x21, 0xB7, 0x21, 0x77 }; + private static readonly byte[] key_E1ED10F0_xor = { 0xE8, 0x21, 0xA6, 0x81, 0xBC, 0xC8, 0x4A, 0x09, 0x88, 0x92, 0x78, 0x65, 0x3A, 0x3B, 0x3C, 0x4E }; + private static readonly byte[] key_E1ED06F0 = { 0x2D, 0xB6, 0x4D, 0x66, 0xCB, 0xA3, 0x8E, 0x4D, 0x13, 0x6F, 0xB1, 0x63, 0x4C, 0xCC, 0x21, 0xF2 }; + private static readonly byte[] key_E1ED06F0_xor = { 0xA5, 0xAC, 0x61, 0x8A, 0x6B, 0xD2, 0x4A, 0xC4, 0x96, 0x75, 0x3B, 0x5A, 0x8C, 0xF6, 0x46, 0x2F }; + + public static int sceMesgLed_driver_66B348B2(Span modData, int size, out int newSize, ReadOnlySpan versionKey) + { + var ret = Decrypt(0xE1ED28F0, key_E1ED28F0, 0x66, modData, size, out newSize, 0, null, 5, key_E1ED28F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0xE1ED1EF0, key_E1ED1EF0, 0x66, modData, size, out newSize, 0, null, 5, key_E1ED1EF0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0xE1ED10F0, key_E1ED10F0, 0x66, modData, size, out newSize, 0, null, 5, key_E1ED10F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0xE1ED06F0, key_E1ED06F0, 0x66, modData, size, out newSize, 0, null, 5, key_E1ED06F0_xor, versionKey); + } + } + } + + return ret; + } + + private static readonly byte[] key_3C2A28F0 = { 0x0B, 0xFD, 0xC8, 0x94, 0xB2, 0xF1, 0x3B, 0x8B, 0x82, 0x0D, 0x1A, 0x58, 0x55, 0x15, 0x31, 0x8A }; + private static readonly byte[] key_3C2A1EF0 = { 0x19, 0x13, 0xE6, 0x04, 0x27, 0xC2, 0xB2, 0xA7, 0x99, 0x1A, 0x76, 0xA0, 0x96, 0x92, 0xA5, 0x34 }; + private static readonly byte[] key_3C2A10F0 = { 0xCB, 0x5E, 0x47, 0x46, 0x67, 0x1E, 0x66, 0xFE, 0x68, 0x92, 0xBD, 0xFB, 0xB6, 0xA9, 0xA5, 0xF0 }; + private static readonly byte[] key_3C2A08F0 = { 0x1E, 0x2E, 0x38, 0x49, 0xDA, 0xD4, 0x16, 0x08, 0x27, 0x2E, 0xF3, 0xBC, 0x37, 0x75, 0x80, 0x93 }; + + public static int sceMesgLed_driver_B2D95FDF(Span modData, int size, out int newSize) + { + var ret = Decrypt(0x3C2A28F0, key_3C2A28F0, 0x67, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x3C2A1EF0, key_3C2A1EF0, 0x67, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x3C2A10F0, key_3C2A10F0, 0x67, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x3C2A08F0, key_3C2A08F0, 0x67, modData, size, out newSize, 0, null, 2, null, null); + } + } + } + + return ret; + } + + static int sceMesgLed_driver_C9ABD2F2(Span modData, int size, out int newSize) => sceMesgLed_driver_B2D95FDF(modData, size, out newSize); + + private static readonly byte[] key_407810F0 = { 0xAF, 0xAD, 0xCA, 0xF1, 0x95, 0x59, 0x91, 0xEC, 0x1B, 0x27, 0xD0, 0x4E, 0x8A, 0xF3, 0x3D, 0xE7 }; + private static readonly byte[] key_407810F0_xor = { 0x84, 0x7B, 0xF5, 0xFE, 0xE8, 0x4D, 0xAD, 0x7A, 0xB5, 0x06, 0x28, 0x0E, 0x09, 0xFA, 0x81, 0xE1 }; + + public static int sceMesgLed_driver_91E0A9AD(Span modData, int size, out int newSize, ReadOnlySpan versionKey) + { + return Decrypt(0x407810F0, key_407810F0, 0x6A, modData, size, out newSize, 0, null, 5, key_407810F0_xor, versionKey); + } + + #endregion + + #region sceResmap_driver + + private static readonly byte[] key_628928F0 = { 0x7F, 0x97, 0xE8, 0x15, 0xFB, 0x5D, 0x9A, 0xAE, 0x06, 0x2D, 0xB1, 0xD4, 0xF6, 0x28, 0x53, 0xBC }; + private static readonly byte[] key_62891EF0 = { 0x6D, 0x79, 0xC6, 0x85, 0x6E, 0x6E, 0x13, 0x82, 0x1D, 0x3A, 0xDD, 0x2C, 0x35, 0xAF, 0xC7, 0x02 }; + private static readonly byte[] key_628910F0 = { 0xBF, 0x34, 0x67, 0xC7, 0x2E, 0xB2, 0xC7, 0xDB, 0xEC, 0xB2, 0x16, 0x77, 0x15, 0x94, 0xC7, 0xC6 }; + + private static readonly byte[] key_04000000 = + { + 0xA3, 0xA0, 0x8E, 0x41, 0x82, 0xE0, 0xBC, 0xC9, 0x9D, 0x22, 0x7F, 0xC5, 0x9C, 0x3C, 0x9C, 0xBE, + 0xC3, 0x72, 0x4F, 0x60, 0x69, 0x48, 0xD2, 0x8C, 0xAD, 0x3A, 0x4A, 0xCF, 0xAF, 0x3F, 0x80, 0x31, + 0x3C, 0x8D, 0x55, 0x2A, 0xD4, 0xBF, 0x3B, 0x3A, 0x5C, 0x2F, 0xF3, 0x57, 0x20, 0xAD, 0xFF, 0x35, + 0x71, 0x4F, 0xD2, 0xD4, 0xE8, 0xC9, 0x52, 0x81, 0xA5, 0x14, 0x0E, 0xB9, 0x8E, 0xED, 0x07, 0x2F, + 0xAE, 0x7F, 0x6B, 0x54, 0x0C, 0xCD, 0x86, 0x91, 0x87, 0x84, 0x48, 0xDA, 0xED, 0xA4, 0x6B, 0xA5, + 0xB5, 0x44, 0x5A, 0x4E, 0xD5, 0x44, 0x00, 0x58, 0x4D, 0xE5, 0xE8, 0xC8, 0x62, 0x68, 0xD2, 0x39, + 0xC7, 0x25, 0x86, 0x81, 0x27, 0xFF, 0x4C, 0x5D, 0xFE, 0x50, 0xBB, 0x2D, 0xB7, 0x08, 0x5C, 0x4F, + 0x7E, 0x85, 0x14, 0x03, 0x91, 0x5A, 0x26, 0x84, 0xF5, 0xE3, 0xA2, 0x02, 0x44, 0x49, 0x96, 0x4F, + 0x66, 0x7E, 0xCF, 0xDB, 0xFE, 0xCB, 0xB4, 0x02, 0xED, 0x66, 0x6F, 0x92, 0x7F, 0x4E, 0x80, 0x63 + }; + + // sceKernelWaitSema + public static int sceResmap_driver_E5659590(Span modData, int size, out int newSize) + { + var ret = Decrypt(0x628928F0, key_628928F0, 0x47, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x62891EF0, key_62891EF0, 0x47, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x628910F0, key_628910F0, 0x47, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x04000000, key_04000000, 0x47, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + return ret; + } + + // sceKernelPollSema + static int sceResmap_driver_4434E59F(Span modData, int size, out int newSize) => sceResmap_driver_E5659590(modData, size, out newSize); + #endregion + + #region scePauth_driver + + private static readonly byte[] key_2FD312F0 = { 0xC5, 0xFB, 0x69, 0x03, 0x20, 0x7A, 0xCF, 0xBA, 0x2C, 0x90, 0xF8, 0xB8, 0x4D, 0xD2, 0xF1, 0xDE }; + private static readonly byte[] key_2FD312F0_xor = { 0xA9, 0x1E, 0xDD, 0x7B, 0x09, 0xBB, 0x22, 0xB5, 0x9D, 0xA3, 0x30, 0x69, 0x13, 0x6E, 0x0E, 0xD8 }; + private static readonly byte[] key_2FD311F0 = { 0x3A, 0x6B, 0x48, 0x96, 0x86, 0xA5, 0xC8, 0x80, 0x69, 0x6C, 0xE6, 0x4B, 0xF6, 0x04, 0x17, 0x44 }; + private static readonly byte[] key_2FD311F0_xor = { 0xA9, 0x1E, 0xDD, 0x7B, 0x09, 0xBB, 0x22, 0xB5, 0x9D, 0xA3, 0x30, 0x69, 0x13, 0x6E, 0x0E, 0xD8 }; + + public static int scePauth_driver_F7AA47F6(Span modData, int size, out int newSize, ReadOnlySpan versionKey) + { + var ret = Decrypt(0x2FD312F0, key_2FD312F0, 0x47, modData, size, out newSize, 0, null, 5, key_2FD312F0_xor, versionKey); + if (ret == -0x12d) + { + ret = Decrypt(0x2FD311F0, key_2FD311F0, 0x47, modData, size, out newSize, 0, null, 5, key_2FD311F0_xor, versionKey); + } + + return ret; + } + + private static readonly byte[] key_2FD313F0 = { 0xB0, 0x24, 0xC8, 0x16, 0x43, 0xE8, 0xF0, 0x1C, 0x8C, 0x30, 0x67, 0x73, 0x3E, 0x96, 0x35, 0xEF }; + private static readonly byte[] key_2FD313F0_xor = { 0xA9, 0x1E, 0xDD, 0x7B, 0x09, 0xBB, 0x22, 0xB5, 0x9D, 0xA3, 0x30, 0x69, 0x13, 0x6E, 0x0E, 0xD8 }; + + static int scePauth_driver_98B83B5D(Span modData, int size, out int newSize, ReadOnlySpan versionKey) + { + return Decrypt(0x2FD313F0, key_2FD313F0, 0x47, modData, size, out newSize, 0, null, 5, key_2FD313F0_xor, versionKey); + } + #endregion + + #region sceDbman_driver + + private static readonly byte[] key_8B9B28F0 = { 0x1A, 0x16, 0xB2, 0x22, 0x5A, 0xA4, 0xF9, 0xB3, 0x55, 0x09, 0xDA, 0xA9, 0xF0, 0x4C, 0x35, 0x28 }; + private static readonly byte[] key_8B9B1EF0 = { 0x08, 0xF8, 0x9C, 0xB2, 0xCF, 0x97, 0x70, 0x9F, 0x4E, 0x1E, 0xB6, 0x51, 0x33, 0xCB, 0xA1, 0x96 }; + private static readonly byte[] key_8B9B10F0 = { 0xDA, 0xB5, 0x3D, 0xF0, 0x8F, 0x4B, 0xA4, 0xC6, 0xBF, 0x96, 0x7D, 0x0A, 0x13, 0xF0, 0xA1, 0x52 }; + private static readonly byte[] key_05000000 = + { + 0xF3, 0x43, 0x5E, 0xDD, 0x3A, 0x41, 0xCA, 0x41, 0xC6, 0x22, 0xBD, 0x56, 0xA5, 0x42, 0x18, 0xB3, + 0x8C, 0xDB, 0xA7, 0x6F, 0x87, 0x41, 0xB2, 0x83, 0x84, 0xAB, 0x07, 0xB0, 0x3D, 0x40, 0x1B, 0xBE, + 0x06, 0x24, 0x6C, 0xD6, 0xAD, 0xEA, 0x47, 0xB6, 0xD0, 0xEE, 0x63, 0xD9, 0x75, 0x0E, 0x3A, 0x1E, + 0x80, 0xAA, 0x4E, 0x5A, 0xD9, 0xED, 0x40, 0x98, 0xD4, 0x14, 0x2D, 0xBF, 0xC5, 0xE7, 0x46, 0xA2, + 0xCD, 0xCD, 0xF2, 0x19, 0x38, 0xDC, 0x74, 0xE4, 0xC5, 0x5D, 0x51, 0xC9, 0xA5, 0xA6, 0x8C, 0x26, + 0x49, 0x36, 0x7A, 0x85, 0x05, 0x7D, 0x5B, 0x4C, 0x24, 0x9F, 0x84, 0x67, 0x23, 0x83, 0xC3, 0xEF, + 0x6C, 0x6A, 0x3C, 0xF9, 0x9F, 0x6E, 0xCA, 0x83, 0xAC, 0x98, 0xC1, 0xDD, 0xE6, 0xD4, 0x91, 0xEA, + 0x77, 0xAA, 0x95, 0xC9, 0x02, 0x03, 0x40, 0xDA, 0x40, 0xF9, 0xC7, 0x8B, 0x95, 0x60, 0xCA, 0x34, + 0x03, 0x17, 0x19, 0x0C, 0xFC, 0xE6, 0x51, 0x3D, 0xC5, 0xF3, 0xC3, 0x72, 0x2D, 0x6B, 0xC4, 0xD5 + }; + + // sceKernelWaitSema sceDbmanSelect + public static int sceDbman_driver_B2B8C3F9(Span modData, int size, out int newSize) + { + var ret = Decrypt(0x8B9B28F0, key_8B9B28F0, 0x48, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x8B9B1EF0, key_8B9B1EF0, 0x48, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x8B9B10F0, key_8B9B10F0, 0x48, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x05000000, key_05000000, 0x48, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + return ret; + } + + // sceKernelPollSema + static int sceDbman_driver_34B53D46(Span modData, int size, out int newSize) => sceDbman_driver_B2B8C3F9(modData, size, out newSize); + #endregion + + #region sceNwman_driver + + private static readonly byte[] key_5A5C28F0 = { 0x66, 0xC5, 0x9C, 0x07, 0x50, 0x73, 0xE4, 0x54, 0xE9, 0x13, 0x42, 0x47, 0xEF, 0xD1, 0x2D, 0x2A }; + private static readonly byte[] key_5A5C1EF0 = { 0x74, 0x2B, 0xB2, 0x97, 0xC5, 0x40, 0x6D, 0x78, 0xF2, 0x04, 0x2E, 0xBF, 0x2C, 0x56, 0xB9, 0x94 }; + private static readonly byte[] key_5A5C10F0 = { 0xA6, 0x66, 0x13, 0xD5, 0x85, 0x9C, 0xB9, 0x21, 0x03, 0x8C, 0xE5, 0xE4, 0x0C, 0x6D, 0xB9, 0x50 }; + private static readonly byte[] key_E42C2303 = { 0x6D, 0x79, 0xF2, 0xF6, 0x37, 0x3D, 0xB7, 0xBE, 0xA2, 0x73, 0xA1, 0xAE, 0x88, 0x70, 0xC9, 0xA3 }; + private static readonly byte[] key_06000000 = + { + 0x84, 0x15, 0x12, 0x8C, 0xA8, 0x83, 0xD7, 0x80, 0xEF, 0x1E, 0x88, 0xDB, 0xBC, 0x61, 0x96, 0x23, + 0x2B, 0xF3, 0x88, 0xFC, 0xE5, 0x3F, 0xB5, 0xDE, 0x98, 0x5A, 0xA0, 0x6B, 0xDE, 0x0A, 0x55, 0xDB, + 0xF2, 0xF8, 0x44, 0x36, 0xEB, 0xD1, 0x94, 0x55, 0x4A, 0x39, 0x3E, 0x93, 0x7C, 0x3D, 0xE3, 0x02, + 0x12, 0x88, 0xE7, 0xF5, 0xF8, 0xF0, 0xC1, 0xEB, 0x25, 0x1B, 0x8D, 0xC6, 0xB8, 0x1E, 0x2B, 0x44, + 0xA5, 0xB7, 0x6A, 0x7E, 0xD0, 0x39, 0x46, 0x92, 0x6D, 0x71, 0xDE, 0x07, 0x97, 0xB8, 0x2F, 0x10, + 0x18, 0xBA, 0xDD, 0x53, 0xC6, 0x07, 0x2B, 0x98, 0x24, 0x8A, 0x74, 0x0D, 0x5C, 0x64, 0x5D, 0xFE, + 0x8E, 0xE7, 0x67, 0x43, 0x93, 0x96, 0xB3, 0xA1, 0xA1, 0xA8, 0xEC, 0x12, 0xC4, 0xFB, 0x58, 0x44, + 0xFC, 0x55, 0x0A, 0x9C, 0x1E, 0x30, 0x37, 0xFA, 0x54, 0x24, 0xD3, 0x03, 0xE2, 0x92, 0xBD, 0x31, + 0x23, 0x03, 0xEA, 0xF7, 0xE7, 0x73, 0xDE, 0x09, 0x3B, 0xB3, 0x83, 0x79, 0xDA, 0x17, 0x85, 0x0E + }; + + // sceKernelWaitSema + public static int sceNwman_driver_9555D68D(Span modData, int size, out int newSize) + { + var ret = Decrypt(0x5A5C28F0, key_5A5C28F0, 0x49, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x5A5C1EF0, key_5A5C1EF0, 0x49, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x5A5C10F0, key_5A5C10F0, 0x49, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xE42C2303, key_E42C2303, 0x49, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x06000000, key_06000000, 0x49, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + } + return ret; + } + #endregion + + #region sceMesgd_driver + + private static readonly byte[] key_D82328F0 = { 0x5D, 0xAA, 0x72, 0xF2, 0x26, 0x60, 0x4D, 0x1C, 0xE7, 0x2D, 0xC8, 0xA3, 0x2F, 0x79, 0xC5, 0x54 }; + private static readonly byte[] key_D8231EF0 = { 0x4F, 0x44, 0x5C, 0x62, 0xB3, 0x53, 0xC4, 0x30, 0xFC, 0x3A, 0xA4, 0x5B, 0xEC, 0xFE, 0x51, 0xEA }; + private static readonly byte[] key_D82310F0 = { 0x9D, 0x09, 0xFD, 0x20, 0xF3, 0x8F, 0x10, 0x69, 0x0D, 0xB2, 0x6F, 0x00, 0xCC, 0xC5, 0x51, 0x2E }; + private static readonly byte[] key_63BAB403 = { 0x02, 0x2B, 0x67, 0x21, 0xE7, 0x86, 0xAD, 0x91, 0x73, 0xBC, 0xC9, 0xDE, 0xC5, 0x7A, 0x13, 0xA4 }; + private static readonly byte[] key_0E000000 = + { + 0xDE, 0x57, 0xB7, 0x77, 0x17, 0xDD, 0x62, 0xEE, 0x7B, 0x78, 0x03, 0x5D, 0x44, 0x86, 0xCA, 0x59, + 0x20, 0x8D, 0xF6, 0x93, 0x28, 0x93, 0x81, 0x21, 0x71, 0x4E, 0xA7, 0x86, 0xCA, 0x82, 0x24, 0x1B, + 0x58, 0xAE, 0x74, 0x5F, 0x6C, 0x01, 0x8D, 0x56, 0x32, 0x88, 0x4D, 0x9A, 0x72, 0x43, 0xA2, 0x2E, + 0x84, 0xF4, 0x0C, 0x82, 0xB9, 0x06, 0xFC, 0xFC, 0x6A, 0xFB, 0x5B, 0x8A, 0xD7, 0x9C, 0x9F, 0xBF, + 0x01, 0x0D, 0x85, 0x15, 0xBA, 0x5F, 0xED, 0x39, 0x93, 0x83, 0xC3, 0x4C, 0xAF, 0xDE, 0x3A, 0xED, + 0xBF, 0x68, 0xA7, 0x1A, 0x77, 0x8A, 0xBD, 0x89, 0x65, 0x41, 0x56, 0x46, 0xD9, 0xDB, 0x33, 0x73, + 0x81, 0x6C, 0xE8, 0x62, 0x96, 0x9B, 0x29, 0x03, 0x5A, 0xAE, 0xAF, 0x73, 0x20, 0x53, 0xA0, 0x40, + 0xE8, 0x4B, 0x66, 0x10, 0x99, 0x6A, 0xB7, 0xE5, 0x70, 0xDD, 0xE0, 0x29, 0x28, 0x24, 0x60, 0xEA, + 0x30, 0xAE, 0x42, 0x20, 0x32, 0x8D, 0x6F, 0x94, 0x71, 0x5F, 0x9E, 0xA2, 0xD5, 0x7F, 0x0C, 0x7C + }; + + // sceKernelWaitSema + public static int sceMesgd_driver_102DC8AF(Span modData, int size, out int newSize) + { + var ret = Decrypt(0xD82328F0, key_D82328F0, 0x51, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD8231EF0, key_D8231EF0, 0x51, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD82310F0, key_D82310F0, 0x51, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x63BAB403, key_63BAB403, 0x51, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x0E000000, key_0E000000, 0x51, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + } + return ret; + } + + // sceKernelPollSema + static int sceMesgd_driver_ADD0CB66(Span modData, int size, out int newSize) => sceMesgd_driver_102DC8AF(modData, size, out newSize); + #endregion + + #region sceWmd_driver + + private static readonly byte[] key_D13B28F0 = { 0x16, 0x6F, 0x8A, 0x89, 0x93, 0x67, 0xF2, 0x47, 0xEB, 0x3D, 0xE5, 0x05, 0xB9, 0x96, 0xEA, 0xEA }; + private static readonly byte[] key_D13B1EF0 = { 0x04, 0x81, 0xA4, 0x19, 0x06, 0x54, 0x7B, 0x6B, 0xF0, 0x2A, 0x89, 0xFD, 0x7A, 0x11, 0x7E, 0x54 }; + private static readonly byte[] key_D13B10F0 = { 0xD6, 0xCC, 0x05, 0x5B, 0x46, 0x88, 0xAF, 0x32, 0x01, 0xA2, 0x42, 0xA6, 0x5A, 0x2A, 0x7E, 0x90 }; + private static readonly byte[] key_D13B08F0 = { 0x03, 0xBC, 0x7A, 0x54, 0xFB, 0x42, 0xDF, 0xC4, 0x4E, 0x1E, 0x0C, 0xE1, 0xDB, 0xF6, 0x5B, 0xF3 }; + private static readonly byte[] key_D13B06F0 = { 0xB2, 0xDB, 0x96, 0xD9, 0x8B, 0x7E, 0x13, 0x95, 0x45, 0x55, 0x1C, 0xA3, 0xCB, 0x7E, 0x2E, 0xAB }; + private static readonly byte[] key_D13B05F0 = { 0xE7, 0x47, 0x33, 0x64, 0xF9, 0x67, 0xFE, 0xDE, 0x61, 0x7C, 0xE4, 0x06, 0x13, 0x60, 0xAD, 0x6D }; + private static readonly byte[] key_1B11FD03 = { 0x71, 0x39, 0xAD, 0x80, 0xA1, 0x07, 0xDC, 0xA1, 0xE4, 0xE5, 0x59, 0x97, 0xEB, 0xB3, 0xFF, 0x48 }; + private static readonly byte[] key_862648D1 = + { + 0x35, 0x2E, 0x7E, 0x08, 0xD6, 0x0A, 0xA8, 0xD0, 0xC2, 0xCF, 0xAB, 0x01, 0x46, 0x6C, 0x5C, 0x81, + 0xF9, 0xE5, 0xA0, 0xAD, 0x38, 0x06, 0x49, 0x19, 0x10, 0xAE, 0x2F, 0xDB, 0xE2, 0x3B, 0xAB, 0x97, + 0xD1, 0x56, 0x70, 0x9F, 0x54, 0x22, 0x07, 0x40, 0xAA, 0x37, 0x11, 0x1F, 0x78, 0x39, 0x42, 0xF2, + 0x1C, 0x44, 0xE5, 0x12, 0xA3, 0x31, 0xE9, 0xEB, 0xFC, 0xE8, 0x5E, 0x8A, 0xE7, 0xC3, 0x18, 0x7B, + 0xEC, 0xA0, 0xBB, 0xD8, 0x11, 0xFB, 0x9C, 0xFD, 0xB8, 0x17, 0xC0, 0xB6, 0x3B, 0x54, 0xAD, 0x2E, + 0xEC, 0xFA, 0x13, 0xF2, 0xFC, 0x8B, 0x91, 0x27, 0xB1, 0x43, 0x93, 0xF0, 0x72, 0x80, 0xE2, 0x50, + 0x18, 0x69, 0xF9, 0x23, 0x69, 0xDA, 0xF8, 0xC0, 0x54, 0xAA, 0x56, 0x80, 0xEE, 0x03, 0x41, 0xD0, + 0xE7, 0xF9, 0x9D, 0xDD, 0x76, 0x09, 0xBC, 0xBF, 0x96, 0xAC, 0x3E, 0x5E, 0x83, 0xA3, 0xEC, 0xCB, + 0x0F, 0xAB, 0x86, 0x9B, 0x02, 0xFC, 0x34, 0x1A, 0x06, 0x3F, 0xC8, 0xD9, 0xF0, 0x00, 0x4C, 0x17 + }; + private static readonly byte[] key_0F000000 = + { + 0x60, 0x73, 0xFD, 0xA2, 0x2D, 0xCE, 0xF1, 0x11, 0xE3, 0x82, 0x78, 0xF5, 0x34, 0xAA, 0x9D, 0xE6, + 0xD2, 0x2D, 0x34, 0xBE, 0x55, 0xBB, 0x57, 0x7F, 0x9B, 0x63, 0x70, 0x21, 0x94, 0x31, 0xEB, 0x4F, + 0xDB, 0x97, 0xB7, 0xA3, 0x1D, 0x64, 0xE4, 0x19, 0xF7, 0x13, 0x16, 0x5E, 0xB3, 0xC9, 0x0F, 0x3E, + 0xBE, 0xC6, 0x41, 0xB5, 0x13, 0xD0, 0x7F, 0xB4, 0x55, 0x16, 0x46, 0x95, 0x22, 0x9A, 0xE6, 0xF7, + 0xAA, 0x67, 0xCB, 0xC4, 0xDD, 0xB7, 0x70, 0x67, 0x52, 0x48, 0xB3, 0x26, 0x5E, 0xA9, 0x38, 0xFF, + 0x5F, 0x62, 0xEA, 0xD4, 0x47, 0xAC, 0xD0, 0x49, 0xAB, 0xC7, 0x7C, 0x48, 0x1B, 0x83, 0x02, 0x83, + 0x30, 0x1B, 0x33, 0xC1, 0x7D, 0x0B, 0x52, 0xD4, 0xBB, 0xEA, 0x10, 0x39, 0x59, 0x3D, 0xF6, 0x96, + 0x2F, 0xF0, 0x50, 0x42, 0xF4, 0x87, 0xC4, 0xEE, 0x29, 0x98, 0x4A, 0xA7, 0x77, 0x36, 0x11, 0xAF, + 0xE7, 0xF9, 0x9C, 0x42, 0xB6, 0x3A, 0x2A, 0x78, 0x0C, 0xFE, 0x8E, 0x55, 0x82, 0x66, 0x11, 0x4A + }; + + // sceKernelWaitSema + public static int sceWmd_driver_7A0E484C(Span modData, int size, out int newSize) + { + var ret = Decrypt(0xD13B28F0, key_D13B28F0, 0x52, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD13B1EF0, key_D13B1EF0, 0x52, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD13B10F0, key_D13B10F0, 0x52, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD13B08F0, key_D13B08F0, 0x52, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD13B06F0, key_D13B06F0, 0x52, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0xD13B05F0, key_D13B05F0, 0x52, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x1B11FD03, key_1B11FD03, 0x52, modData, size, out newSize, 0, null, 2, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x862648D1, key_862648D1, 0x52, modData, size, out newSize, 0, null, 1, null, null); + if (ret == -0x12d) + { + ret = Decrypt(0x0F000000, key_0F000000, 0x52, modData, size, out newSize, 0, null, 0, null, null); + } + } + } + } + } + } + } + } + return ret; + } + + // sceKernelPollSema + static int sceWmd_driver_B7CE9041(Span modData, int size, out int newSize) => sceWmd_driver_7A0E484C(modData, size, out newSize); + #endregion + + + static readonly Memory mem88134300 = new byte[0x1000]; + static readonly Memory mem881343a4 = mem88134300.Slice(0xa4, 0x78); + static readonly Memory mem881343b4 = mem88134300.Slice(0xb4, 0x30); + static readonly Memory mem881343e4 = mem88134300.Slice(0xe4); + static readonly Memory mem881343f4 = mem88134300.Slice(0xf4); + static readonly Memory mem881345c0 = mem88134300.Slice(0x2c0); + static readonly Memory mem881345c4 = mem88134300.Slice(0x2c4); + static readonly Memory mem881345d4 = mem88134300.Slice(0x2d4); + static readonly Memory mem881345d8 = mem88134300.Slice(0x2d8); + static readonly Memory mem881345fc = mem88134300.Slice(0x2fc); + static readonly Memory mem881345e8 = mem88134300.Slice(0x2e8); + static readonly Memory mem88134604 = mem88134300.Slice(0x304); + static readonly Memory mem88134740 = mem88134300.Slice(0x440); + static readonly byte[] key7D20 = { 0xAC, 0x84, 0x69, 0xEB, 0x19, 0x51, 0xEE, 0xE3, 0xFD, 0x5D, 0x93, 0xF8, 0xAB, 0x97, 0x47, 0x56 }; + static readonly byte[] key7D30 = { 0x00, 0x77, 0x3A, 0x39, 0x2A, 0xFC, 0x47, 0x6D, 0x16, 0x3D, 0x43, 0x7E, 0xEF, 0xEF, 0xC3, 0x50 }; + static readonly byte[] key7D40 = + { + 0x2E, 0x2C, 0x67, 0x81, 0xB2, 0x0D, 0xB6, 0x80, 0x7D, 0x99, 0xEB, 0x04, 0x5F, 0xC3, 0x37, 0xB0, + 0xF5, 0x44, 0x2F, 0xEF, 0xDE, 0x1F, 0x9A, 0x4A, 0x01, 0x8A, 0x2E, 0xBF, 0x82, 0x4A, 0x74, 0x95, + 0x71, 0x1F, 0xF2, 0x29, 0xCB, 0x23, 0xC2, 0x6D + }; + + public static int sceResmgr_8E6C62C8(ReadOnlySpan keyBuf) + { + keyBuf.CopyTo(mem881343a4.Span); + mem881343a4[..0x40].CopyTo(mem881345c4); + int len = 0x50; + MemoryMarshal.Write(mem881345c0.Span, ref len); + key7D20.CopyTo(mem88134604); + KIRKEngine.sceUtilsBufferCopyWithRange(mem881345c0.Span, 0x54, mem881345c0.Span, 0x54, KIRKEngine.KIRK_CMD_SHA1_HASH); + mem881345c0[..0x14].CopyTo(mem88134740); + mem881343e4[..0x10].CopyTo(mem881345d4); + Kirk7(mem881345c0.Span, 0x10, 0x56, 0); + if (!mem881345c0.Span.Slice(0, 0x10).SequenceEqual(mem88134740.Span.Slice(0, 0x10))) + { + return -0x12e; + } + key7D40.CopyTo(mem881345c0); + mem88134740[..0x14].CopyTo(mem881345e8); + mem881343f4[..0x28].CopyTo(mem881345fc); + var ret = KIRKEngine.sceUtilsBufferCopyWithRange(null, 0, mem881345c0.Span, 100, KIRKEngine.KIRK_CMD_ECDSA_VERIFY); + if (ret != 0) + { + return -0x12f; + } + mem881343b4.CopyTo(mem881345d4); + for (int i = 0; i < 0x30; i++) + { + mem881345d4.Span[i] ^= key7D30[i & 0xF]; + } + ret = Kirk7(mem881345c0.Span, 0x30, 0x56, 0); + if (ret != 0) + { + return -0x67; + } + for (int i = 0; i < 0x30; i++) + { + mem881345c0.Span[i] ^= key7D30[i & 0xF]; + } + int type = 2; + uint oldTag1, oldTag2, keyTag1, keyTag2; + Memory key1, key2; + if (mem881345c0.Span[0] == 0xF0 && mem881345c0.Span[1] > 0x8f) + { + // type4 + type = 4; + // D91690F0 + oldTag1 = 0xD91690F0; + keyTag1 = MemoryMarshal.Read(mem881345c0.Span); + key1 = mem881345c4.Slice(0, 0x10); + // 2E5E90F0 + oldTag2 = 0x2E5E90F0; + keyTag2 = MemoryMarshal.Read(mem881345d4.Span); + key2 = mem881345d8.Slice(0, 0x10); + } + else if (mem881345c0.Span[0] == 0xF0 && (sbyte)mem881345c0.Span[1] < 0) + { + // type3 + type = 3; + // D91680F0 + oldTag1 = 0xD91680F0; + keyTag1 = MemoryMarshal.Read(mem881345c0.Span); + key1 = mem881345c4.Slice(0, 0x10); + // 2E5E80F0 + oldTag2 = 0x2E5E80F0; + keyTag2 = MemoryMarshal.Read(mem881345d4.Span); + key2 = mem881345d8.Slice(0, 0x10); + } + else + { + // type1 + type = 1; + // D91611F0 + oldTag1 = 0xD91611F0; + keyTag1 = MemoryMarshal.Read(mem881345c0.Span); + key1 = mem881345c4.Slice(0, 0x10); + // 2E5E11F0 + oldTag2 = 0x2E5E11F0; + keyTag2 = MemoryMarshal.Read(mem881345d4.Span); + key2 = mem881345d8.Slice(0, 0x10); + } + Console.WriteLine($"Type: {type}"); + Console.WriteLine($"Old Tag: 0x{oldTag1:X8}, New Tag: 0x{keyTag1:X8}"); + Console.WriteLine($"Key {string.Join(", ", key1.ToArray().Select(b => $"0x{b:X2}"))}"); + Console.WriteLine($"Old Tag: 0x{oldTag2:X8}, New Tag: 0x{keyTag2:X8}"); + Console.WriteLine($"Key {string.Join(", ", key2.ToArray().Select(b => $"0x{b:X2}"))}"); + + return 0; + } + + static int Kirk4(Span data, int size, int seed, int use_polling) + { + KIRKEngine.KIRK_AES128CBC_HEADER hdr = new KIRKEngine.KIRK_AES128CBC_HEADER + { + mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC, + keyseed = seed, + data_size = size + }; + MemoryMarshal.Write(data, ref hdr); + //using (var ms = new MemoryStream(data)) + //{ + // ms.Seek(offset, SeekOrigin.Begin); + // using var bw = new BinaryWriter(ms); + // bw.Write(KIRKEngine.KIRK_MODE_DECRYPT_CBC); + // bw.Write(0); + // bw.Write(0); + // bw.Write(seed); + // bw.Write(size); + //} + if (use_polling == 0) + { + KIRKEngine.sceUtilsBufferCopyWithRange(data, size + 20, data, size + 20, + KIRKEngine.KIRK_CMD_ENCRYPT_IV_0); + } + return 0; + } + + static int Kirk7(Span data, int size, int seed, int use_polling) + { + KIRKEngine.KIRK_AES128CBC_HEADER hdr = new KIRKEngine.KIRK_AES128CBC_HEADER + { + mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC, + keyseed = seed, + data_size = size + }; + MemoryMarshal.Write(data, ref hdr); + //using (var ms = new MemoryStream(data)) + //{ + // ms.Seek(offset, SeekOrigin.Begin); + // using var bw = new BinaryWriter(ms); + // bw.Write(KIRKEngine.KIRK_MODE_DECRYPT_CBC); + // bw.Write(0); + // bw.Write(0); + // bw.Write(seed); + // bw.Write(size); + //} + if (use_polling == 0) + { + KIRKEngine.sceUtilsBufferCopyWithRange(data, size + 20, data, size + 20, + KIRKEngine.KIRK_CMD_DECRYPT_IV_0); + } + return 0; + } + + + static int BuildKeyData(int keySeed, int use_polling, int type, ReadOnlySpan key, + ReadOnlySpan versionKey) + { + //Span kirkBuf = stackalloc byte[20 + 0x90]; + if ((1 < type && type < 8) || type == 9 || type == 10) + { + for (byte i = 0; i < 9; i++) + { + key[..16].CopyTo(KirkMemory[(20 + i * 16)..].Span); + KirkMemory.Span[20 + i * 16] = i; + } + } + else + { + key[..144].CopyTo(KirkMemory[20..].Span); + } + + var ret = Kirk7(KirkMemory.Span, 0x90, keySeed, use_polling); + if (ret != 0) + { + ret = -0x68; + return ret; + } + + if ((type == 3 || type == 5 || type == 7 || type == 10) && versionKey != null) + { + XorKey(KirkMemory.Span, 0x90, versionKey); + } + KirkMemory[..0x90].CopyTo(KeyData); + return ret; + } + static int CheckBlackList(PSPHeader2 prxHdr, ReadOnlySpan blacklist) + { + return 0; + } + static void XorKeyLarge(Span buffer, int size, ReadOnlySpan key) + { + for (int i = 0; i < size; i++) + { + buffer[i] ^= key[i]; + } + } + + static void XorKey(Span buffer, int size, ReadOnlySpan key) + { + XorKey(buffer, size, key, null); + } + + static void XorKey(Span buffer, int size, ReadOnlySpan key1, ReadOnlySpan key2) + { + for (int i = 0; i < size; i++) + { + if (key2 != null) + { + buffer[i] ^= key2[i & 0xf]; + } + + buffer[i] ^= key1[i & 0xf]; + } + } + + static void XorKeyInto(Span dst, int size, ReadOnlySpan src, ReadOnlySpan key) + { + for (int i = 0; i < size; i++) + { + dst[i] = (byte)(src[i] ^ key[i]); + } + } + + private static readonly Memory KirkMemory = new byte[0x150]; // DAT_00009dc0 + private static readonly Memory KeyData = new byte[0x90]; // DAT_00009d00 + private static readonly Memory KirkCmd1Memory = new byte[0xb4]; // DAT_00009f40 + private static readonly Memory KirkEcdsaMemory = new byte[0x48]; // DAT_0000a040 DAT_0000a060 + + private static readonly byte[] key7AE0 = + { + 0xE3, 0x5E, 0x4E, 0x7E, 0x2F, 0xA3, 0x20, 0x96, 0x75, 0x43, 0x94, 0xA9, 0x92, 0x01, 0x83, 0xA7, + 0x85, 0xBD, 0xF6, 0x19, 0x1F, 0x44, 0x8F, 0x95, 0xE0, 0x43, 0x35, 0xA3, 0xF5, 0xE5, 0x05, 0x65, + 0x5E, 0xD7, 0x59, 0x3F, 0xC6, 0xDB, 0xAF, 0x39 + }; + + private static readonly byte[] key7AB8 = + { + 0x25, 0xDC, 0xFD, 0xE2, 0x12, 0x79, 0x89, 0x54, 0x79, 0x37, 0x13, 0x24, 0xEC, 0x25, 0x08, 0x81, + 0x57, 0xAA, 0xF1, 0xD0, 0xA4, 0x64, 0x8C, 0x15, 0x42, 0x25, 0xF6, 0x90, 0x3F, 0x44, 0xE3, 0x6A, + 0xE6, 0x64, 0x12, 0xFC, 0x80, 0x68, 0xBD, 0xC1 + }; + + private static readonly byte[] key7A90 = + { + 0x77, 0x3F, 0x4B, 0xE1, 0x4C, 0x0A, 0xB4, 0x52, 0x67, 0x2B, 0x67, 0x56, 0x82, 0x4C, 0xCF, 0x42, + 0xAA, 0x37, 0xFF, 0xC0, 0x89, 0x41, 0xE5, 0x63, 0x5E, 0x84, 0xE9, 0xFB, 0x53, 0xDA, 0x94, 0x9E, + 0x9B, 0xB7, 0xC2, 0xA4, 0x22, 0x9F, 0xDF, 0x1F + }; + + public static int Decrypt(Span modData, out int newSize, int use_polling, ReadOnlySpan xorKey2) + { + var hdr = MemoryMarshal.AsRef(modData); + if (!Ciphers.ContainsKey(hdr.tag)) + { + newSize = 0; + return -1; + } + var cipher = Ciphers[hdr.tag]; + return Decrypt(hdr.tag, cipher.Key, cipher.Seed, modData, hdr.pspSize, out newSize, use_polling, null, cipher.Type, cipher.XorKey, xorKey2); + } + + static int Decrypt(uint tag, ReadOnlySpan key, int keySeed, Span modData, int size, out int newSize, int use_polling, ReadOnlySpan blacklist, int type, ReadOnlySpan xorKey, ReadOnlySpan xorKey2) + { + newSize = 0; + int ret = -201; + + PSPHeader2 hdr; // DAT_00009bb0 + // Span buf2 = stackalloc byte[0x150]; // DAT_00009dc0 + // Span buf3 = stackalloc byte[0x90]; // DAT_00009d00 + // Span buf4 = stackalloc byte[0xb4]; // DAT_00009f40 + // Span buf5 = stackalloc byte[0x20]; // DAT_0000a040 + // Span buf6 = stackalloc byte[0x28]; // DAT_0000a060 + KirkMemory.Span.Clear(); + KirkCmd1Memory.Span.Clear(); + KirkEcdsaMemory.Span.Clear(); + byte b_0xd4 = 0; + if (modData == null || size == 0) + { + return ret; // 0xffffff37 + } + ret = -202; // 0xffffff36 + if (size < 0x160) + { + return ret; + } + + hdr = MemoryMarshal.Read(modData); + // DAT_00009c80 + var encTag = hdr.tag; + if (tag != encTag) + { + ret = -0x12d; + return ret; + } + + if (type - 9 < 2 && size < 0x160) + { + ret = 0; + return ret; + } + + if ((type == 9 || type == 10) && size < 0x160) + { + ret = -0xca; + return ret; + } + + switch (type) + { + case 3: + { + for (int i = 0; i < 0x18; i++) + { + if (hdr.sCheck[i] != 0) + { + return -0x12e; + } + } + + break; + } + case 2: + { + for (int i = 0; i < 0x58; i++) + { + if (hdr.sCheck[i] != 0) + { + return -0x12e; + } + } + break; + } + case 5: + { + for (int i = 1; i < 0x58; i++) + { + if (hdr.sCheck[i] != 0) + { + return -0x12e; + } + } + + b_0xd4 = hdr.sCheck[0]; // DAT_00009c84 + break; + } + case 6: + { + for (int i = 0; i < 0x38; i++) + { + if (hdr.sCheck[i] != 0) + { + return -0x12e; + } + } + + break; + } + case 7: + { + for (int i = 1; i < 0x38; i++) + { + if (hdr.sCheck[i] != 0) + { + return -0x12e; + } + } + b_0xd4 = hdr.sCheck[0]; // DAT_00009c84 + break; + } + case 9: + { + for (int i = 0; i < 0x30; i++) + { + if (hdr.sCheck[i] != 0) + { + return -0x12e; + } + } + + break; + } + case 10: + { + for (int i = 1; i < 0x30; i++) + { + if (hdr.sCheck[i] != 0) + { + return -0x12e; + } + } + b_0xd4 = hdr.sCheck[0]; // DAT_00009c84 + + break; + } + } + + if (blacklist != null && blacklist.Length > 0) + { + ret = CheckBlackList(hdr, blacklist); + if (ret == 1) + { + ret = -0x131; + return ret; + } + } + + var elfSize = hdr.dataSize; // DAT_00009c60 - 9bb0 + newSize = elfSize; + if (size - 0x150 < elfSize) + { + ret = -0xce; + return ret; + } + + ret = BuildKeyData(keySeed, use_polling, type, key, xorKey2); + if (ret != 0) + { + return ret; + } + + + if (type == 9 || type == 10) + { + Span sigSpan = stackalloc byte[48]; + Span sha1Span = stackalloc byte[32]; + modData.Slice(0x104, 0x28).CopyTo(KirkEcdsaMemory.Slice(0x20).Span); // DAT_0000a060 + modData.Slice(0x104, 0x28).Clear(); + KirkEcdsaMemory.Slice(0x20).Span.CopyTo(sigSpan); + var tmpSize = size - 4; + MemoryMarshal.Write(modData, ref tmpSize); + if (use_polling == 0) + { + ret = KIRKEngine.sceUtilsBufferCopyWithRange(modData, size, modData, size, + KIRKEngine.KIRK_CMD_SHA1_HASH); + } + else + { + ret = -13; + return ret; + } + + if (ret != 0) + { + ret = -13; + return ret; + } + modData[..0x14].CopyTo(sha1Span); + hdr.RawHdr.Slice(0, 0x20).CopyTo(modData); + var tagBytes = BitConverter.GetBytes(hdr.tag); + ref var ecdsaHdr = ref MemoryMarshal.AsRef(KirkCmd1Memory.Span); + if (tagBytes[2] == 0x16) + { + // key7AE0.CopyTo(buf4); // DAT_00007ae0 DAT_00009f40 + key7AE0.CopyTo(ecdsaHdr.public_key.point); // DAT_00007ae0 DAT_00009f40 + } + else if (tagBytes[2] == 0x5e) + { + // key7AB8.CopyTo(buf4); // DAT_00007ab DAT_00009f40 + key7AB8.CopyTo(ecdsaHdr.public_key.point); // DAT_00007ab DAT_00009f40 + } + else + { + // key7A90.CopyTo(buf4); // DAT_00007a90 DAT_00009f40 + key7A90.CopyTo(ecdsaHdr.public_key.point); + } + // sha1Span.Slice(0, 0x14).CopyTo(buf4.Slice(0x28)); // DAT_00009f68 - 9f40 + sha1Span[..0x14].CopyTo(ecdsaHdr.message_hash); // DAT_00009f68 - 9f40 + // sigSpan.Slice(0, 0x28).CopyTo(buf4.Slice(0x3c)); // DAT_00009f7c - 9f40 + sigSpan[..0x28].CopyTo(ecdsaHdr.signature.sig); // DAT_00009f68 - 9f40 + if (use_polling == 0) + { + ret = KIRKEngine.sceUtilsBufferCopyWithRange(null, 0, KirkCmd1Memory.Span, 0x64, + KIRKEngine.KIRK_CMD_ECDSA_VERIFY); + } + else + { + ret = -13; + return ret; + } + + if (ret != 0) + { + ret = -0x132; + return ret; + } + } + + if (type == 3) + { + hdr.sCheck.Slice(24, 0x40).CopyTo(KirkMemory.Span); // DAT_00009c9c - 9bb0 buf1 0xec + KirkMemory.Slice(0x40, 0x50).Span.Clear(); // DAT_00009e00 - 9dc0 0x40 + KirkMemory.Span[0x60] = 3; // DAT_00009e20 - 9dc0 0x60 + KirkMemory.Span[0x70] = 0x50; // DAT_00009e30 - 9dc0 0x70 + hdr.keyData.CopyTo(KirkMemory.Slice(0x90).Span); // DAT_00009c30 - 9bb0 0x80 DAT_00009e50 - 9dc0 0x90 + hdr.cmacDataHash.CopyTo(KirkMemory.Slice(0xc0).Span); // DAT_00009c70 - 9bb0 0xc0 DAT_00009e80 - 9dc0 0xc0 + hdr.sha1Hash.Slice(0, 0x10).CopyTo(KirkMemory.Slice(0xd0).Span); // DAT_00009cdc - 9bb0 0x12c DAT_00009e90 - 9dc0 0xd0 + + XorKey(KirkMemory.Slice(0x90).Span, 0x50, xorKey, xorKey2); // DAT_00009e50 - 9dc0 0x90 + ret = KIRKEngine.sceUtilsBufferCopyWithRange(KirkCmd1Memory.Span, 0xb4, KirkMemory.Span, 0x150, KIRKEngine.KIRK_CMD_3); + if (ret != 0) + { + ret = -14; + return ret; + } + + MemoryMarshal.Write(KirkMemory.Span, ref hdr.tag); + KirkMemory.Slice(0x04, 0x58).Span.Clear(); + hdr.keyData4.CopyTo(KirkMemory.Slice(0x5c).Span); + hdr.sha1Hash.CopyTo(KirkMemory.Slice(0x6c).Span); + KirkCmd1Memory[..0x10].CopyTo(KirkMemory[0x6c..]); + KirkCmd1Memory[..0x30].CopyTo(KirkMemory[0x80..]); + KirkCmd1Memory.Slice(0x30, 0x10).CopyTo(KirkMemory.Slice(0xb0)); + hdr.sizeInfo.CopyTo(KirkMemory.Slice(0xc0).Span); + var hdrSpan = MemoryMarshal.CreateSpan(ref hdr, 1); + MemoryMarshal.AsBytes(hdrSpan).Slice(0, 0x80).CopyTo(KirkMemory.Slice(0xd0).Span); + } + else if (type == 5 || type == 7 || type == 10) + { + hdr.keyData.CopyTo(KirkMemory.Slice(0x14).Span); // DAT_00009c30 - 9bb0 0x80 DAT_00009dd4 - 9dc0 0x14 + hdr.cmacDataHash.CopyTo(KirkMemory.Slice(0x44).Span); // DAT_00009c70 - 9bb0 0xC0 DAT_00009e04 - 9dc0 0x44 + hdr.sha1Hash.Slice(0, 0x10).CopyTo(KirkMemory.Slice(0x54).Span); // DAT_00009cdc - 9bb0 0x12C DAT_00009e14 - 9dc0 0x54 + XorKey(KirkMemory.Slice(0x14).Span, 0x50, xorKey, xorKey2); + ret = Kirk7(KirkMemory.Span, 0x50, keySeed, use_polling); + if (ret != 0) + { + return -13; + } + KirkMemory[..0x50].CopyTo(KirkCmd1Memory); // DAT_00009dc0 DAT_00009f40 + MemoryMarshal.Write(KirkMemory.Span, ref hdr.tag); // DAT_00009c80 - 9bb0 DAT_00009dc0 + KirkMemory.Slice(4, 0x58).Span.Fill(0); // DAT_00009dc4 - 9dc0 4 + if (type == 7) + { + hdr.sCheck.Slice(56, 0x20).CopyTo(KirkMemory.Slice(0x3c).Span); // DAT_00009cbc - 9bb0 0x10c DAT_00009dfc - 9dc0 0x3C + } + + hdr.keyData4.CopyTo(KirkMemory.Slice(0x5c).Span); // DAT_00009cf0 - 9bb0 0x140 DAT_00009e1c - 9dc0 0x5c + hdr.sha1Hash.CopyTo(KirkMemory.Slice(0x6c).Span); // DAT_00009cdc - 9bb0 0x12C DAT_00009e2c - 9dc0 0x6c + KirkCmd1Memory.Slice(0x40, 0x10).CopyTo(KirkMemory.Slice(0x6c)); // DAT_00009f80 - 9f40 0x40 DAT_00009e2c - 9dc0 0x6c + KirkCmd1Memory[..0x30].CopyTo(KirkMemory[0x80..]); + KirkCmd1Memory.Slice(0x30, 0x10).CopyTo(KirkMemory.Slice(0xb0)); + hdr.sizeInfo.CopyTo(KirkMemory.Slice(0xc0).Span); // DAT_00009c60 - 9bb0 0xB0 DAT_00009e80 - 9dc0 0xC0 + hdr.RawHdr.CopyTo(KirkMemory.Slice(0xd0).Span); // DAT_00009bb0 DAT_00009e90 - 9dc0 0xd0 + + if (type == 10) + { + KirkMemory.Slice(0x34, 0x28).Span.Fill(0); + } + } + else if (type == 2 || type == 4 || type == 6 || type == 9) + { + MemoryMarshal.Write(KirkMemory.Span, ref hdr.tag); + hdr.keyData4.CopyTo(KirkMemory.Slice(0x5c).Span); + hdr.sha1Hash.CopyTo(KirkMemory.Slice(0x6c).Span); + hdr.keyData.CopyTo(KirkMemory.Slice(0x80).Span); + hdr.cmacDataHash.CopyTo(KirkMemory.Slice(0xb0).Span); + hdr.sizeInfo.CopyTo(KirkMemory.Slice(0xc0).Span); + hdr.RawHdr.CopyTo(KirkMemory.Slice(0xd0).Span); + if (type == 9) + { + KirkMemory.Slice(0x34, 0x28).Span.Fill(0); // DAT_00009df4 - 9dc0 + } + } + else + { + hdr.CheckData.CopyTo(KirkMemory.Span); // DAT_00009c80 DAT_00009dc0 + hdr.keyData50.CopyTo(KirkMemory.Slice(0x80).Span); // DAT_00009c30 DAT_00009e40 + hdr.RawHdr.CopyTo(KirkMemory.Slice(0xd0).Span); // DAT_00009bb0 DAT_00009e90 + } + + if (type == 1) + { + KirkMemory.Slice(0x10, 0xa0).CopyTo(KirkCmd1Memory.Slice(0x14)); // DAT_00009dd0 DAT_00009f54 + ret = Kirk7(KirkCmd1Memory.Span, 0xa0, keySeed, use_polling); + if (ret != 0) + { + return -15; + } + KirkCmd1Memory[..0xa0].CopyTo(KirkMemory[0x10..]); // DAT_00009f40 DAT_00009dd0 + } + else if ((1 < type && type < 8) || type == 9 || type == 10) + { + KirkMemory.Slice(0x5c, 0x60).CopyTo(KirkCmd1Memory[0x14..]); // DAT_00009e1c DAT_00009f54 + + if (type == 3 || type == 5 || type == 7 || type == 10) + { + XorKey(KirkCmd1Memory.Span[0x14..], 0x60, xorKey); // DAT_00009f54 + } + + unsafe + { + fixed (byte* ptr = &MemoryMarshal.GetReference(KirkCmd1Memory.Span)) + { + + } + } + + + ret = Kirk7(KirkCmd1Memory.Span, 0x60, keySeed, use_polling); + if (ret != 0) + { + return -5; + } + KirkCmd1Memory[..0x60].CopyTo(KirkMemory[0x5c..]); // DAT_00009f40 DAT_00009e1c + } + + if ((1 < type && type < 8) || type == 9 || type == 10) + { + KirkMemory.Slice(0x6c, 0x14).CopyTo(KirkCmd1Memory); + if (type == 4) + { + KirkMemory[..0x67].CopyTo(KirkMemory[0x18..]); // DAT_00009dc4 DAT_00009dd8 + } + else + { + KirkMemory.Slice(0x5c, 0x10).CopyTo(KirkMemory[0x70..]); // DAT_00009e1c DAT_00009e30 + if (type == 6 || type == 7) + { + KirkMemory.Slice(0x3c, 0x20).CopyTo(KirkEcdsaMemory); // DAT_00009dfc DAT_0000a040 + KirkEcdsaMemory[..0x20].CopyTo(KirkMemory[0x50..]); // DAT_0000a040 DAT_00009e10 + KirkMemory.Slice(0x18, 0x38).Span.Fill(0); // DAT_00009dd8 + } + else + { + KirkMemory.Span.Slice(0x18, 0x58).Fill(0); // DAT_00009dd8 + } + + if (b_0xd4 == 0x80) + { + KirkMemory.Span[0x18] = 0x80; // DAT_00009dd8 + } + + KirkMemory[..0x4].CopyTo(KirkMemory[0x04..]); // DAT_00009dc0 + var value = 0x14c; // sha1 hdr size 0x150 - 4 + MemoryMarshal.Write(KirkMemory.Span, ref value); + + KeyData[..0x10].CopyTo(KirkMemory[8..]); // DAT_00009d00 DAT_00009dc8 + } + } + else + { + KirkMemory.Slice(0x04, 0x14).CopyTo(KirkCmd1Memory); // DAT_00009dc4 DAT_00009f40 + var value = 0x14c; // sha1 hdr size 0x150 - 4 + MemoryMarshal.Write(KirkMemory.Span, ref value); + + KeyData[..0x14].CopyTo(KirkMemory[0x4..]); // DAT_00009d00 DAT_00009dc4 + } + + if (use_polling == 0) + { + ret = KIRKEngine.sceUtilsBufferCopyWithRange(KirkMemory.Span, 0x150, KirkMemory.Span, 0x150, + KIRKEngine.KIRK_CMD_SHA1_HASH); + } + else + { + ret = -1; + // ignore + } + if (ret != 0) + { + ret = -6; + return ret; + } + + if (!KirkMemory.Slice(0, 0x14).Span.SequenceEqual(KirkCmd1Memory.Slice(0, 0x14).Span)) + { + ret = 0x12e; + return ret; + } + + ref var cmd1Hdr = ref MemoryMarshal.AsRef(modData.Slice(0x40)); + ref var cmd1ecdsaHdr = ref MemoryMarshal.AsRef(modData.Slice(0x40)); + + if ((1 < type && type < 8) || type == 9 || type == 10) + { + XorKeyLarge(KirkMemory[0x80..].Span, 0x40, KeyData[16..].Span); // DAT_00009e40 - 9dc0 0x80 DAT_00009d10 - 9d00 0x10 + var k4 = KirkMemory.Slice(0x70, 0x10).Span; + unsafe + { + fixed (byte* ptr = &MemoryMarshal.GetReference(KirkMemory[0x6c..].Span)) + { + + } + } + ret = Kirk7(KirkMemory[0x6c..].Span, 0x40, keySeed, use_polling); + if (ret != 0) + { + ret = -7; + return ret; + } + unsafe + { + fixed (byte* ptr = &MemoryMarshal.GetReference(modData[0x40..])) + { + + } + } + XorKeyInto(modData[0x40..], 0x40, KirkMemory[108..].Span, KeyData[80..].Span); + + + if (type == 6 || type == 7) + { + KirkEcdsaMemory[..0x20].Span.CopyTo(modData[0x80..]); // DAT_0000a040 + modData.Slice(0xa0, 0x10).Clear(); + // modData[0xa4] = 1; // cmd1 ecdsa_hash + cmd1ecdsaHdr.ecdsa_hash = 1; + // modData[0xa0] = 1; // cmd1 mode + cmd1ecdsaHdr.mode = 1; + KirkMemory.Slice(0xc0, 0x10).Span.CopyTo(modData.Slice(0xb0)); + modData.Slice(0xc0, 0x10).Clear(); // DAT_00009e80 + KirkMemory.Slice(0xd0, 0x80).Span.CopyTo(modData.Slice(0xd0)); // DAT_00009e90 + } + else + { + // modData.Slice(0x80, 0x30).Fill(0); + cmd1Hdr.content.Slice(0, 0x30).Clear(); + // modData[0xa0] = 1; // cmd1 mode + cmd1Hdr.mode = 1; // cmd1 mode + // KirkMemory.Slice(0xc0, 0x10).Span.CopyTo(modData.Slice(0xb0)); // DAT_00009e80 + KirkMemory.Slice(0xc0, 0x10).Span.CopyTo(cmd1Hdr.off70); // DAT_00009e80 + modData.Slice(0xc0, 0x10).Clear(); + KirkMemory.Slice(0xd0, 0x80).Span.CopyTo(modData.Slice(0xd0)); // psp hdr size 0x80 + } + } + else + { + XorKeyLarge(KirkMemory.Slice(0x40).Span, 0x70, KeyData.Slice(0x14).Span); // DAT_00009e00 DAT_00009d14 + ret = Kirk7(KirkMemory.Slice(0x2c).Span, 0x70, keySeed, use_polling); // DAT_00009dec + if (ret != 0) + { + ret = -16; + return ret; + } + XorKeyInto(modData.Slice(0x40), 0x70, KirkMemory.Slice(0x2c).Span, KeyData.Slice(0x20).Span); // DAT_00009dec DAT_00009d20 + KirkMemory.Slice(0xb0, 0xa0).Span.CopyTo(modData.Slice(0xb0)); // DAT_00009e70 + if (type == 8 && cmd1ecdsaHdr.ecdsa_hash != 1) + { + ret = -0x12f; + return ret; + } + } + + if (b_0xd4 == 0x80) + { + if (modData[0x590] != 0) + { + ret = -0x12e; + return ret; + } + modData[0x590] = 0x80; + } + + if (use_polling == 0) + { + ret = KIRKEngine.sceUtilsBufferCopyWithRange(modData, size, modData[0x40..], + size - 0x40, KIRKEngine.KIRK_CMD_DECRYPT_PRIVATE); + } + else + { + //ignore + ret = -5; + return ret; + } + + return ret; + } + + + + private const int EI_NIDENT = 16; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + unsafe struct Elf32_Ehdr + { + public fixed byte e_ident[EI_NIDENT]; + public Elf32_Half e_type; + public Elf32_Half e_machine; + public Elf32_Word e_version; + public Elf32_Addr e_entry; /* Entry point */ + public Elf32_Off e_phoff; + public Elf32_Off e_shoff; + public Elf32_Word e_flags; + public Elf32_Half e_ehsize; + public Elf32_Half e_phentsize; + public Elf32_Half e_phnum; + public Elf32_Half e_shentsize; + public Elf32_Half e_shnum; + public Elf32_Half e_shstrndx; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Elf32_Shdr + { + public Elf32_Word sh_name; + public Elf32_Word sh_type; + public Elf32_Word sh_flags; + public Elf32_Addr sh_addr; + public Elf32_Off sh_offset; + public Elf32_Word sh_size; + public Elf32_Word sh_link; + public Elf32_Word sh_info; + public Elf32_Word sh_addralign; + public Elf32_Word sh_entsize; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Elf32_Phdr + { + public Elf32_Word p_type; + public Elf32_Off p_offset; + public Elf32_Addr p_vaddr; + public Elf32_Addr p_paddr; + public Elf32_Word p_filesz; + public Elf32_Word p_memsz; + public Elf32_Word p_flags; + public Elf32_Word p_align; + } + + private const int SCE_MODULE_NAME_LEN = 27; + private const int SCE_MODULE_MAX_SEGMENTS = 4; + private const uint PT_LOAD = 1; + + [StructLayout(LayoutKind.Sequential)] + unsafe struct SceModuleInfo + { + public ushort modattribute; + private fixed byte _modversion[2]; + + public Span modversion + { + get + { + fixed (byte* ptr = _modversion) + { + return new Span(ptr, 2); + } + } + } + private fixed byte _modname[SCE_MODULE_NAME_LEN]; + + public Span modname + { + get + { + fixed (byte* ptr = _modname) + { + return new Span(ptr, SCE_MODULE_NAME_LEN); + } + } + } + public byte terminal; + public uint gp_value; + public uint ent_top; + public uint ent_end; + public uint stub_top; + public uint stub_end; + } + + [StructLayout(LayoutKind.Sequential)] + struct PspModuleExport + { + public uint name; + public uint flags; + public byte entry_len; + public byte var_count; + public ushort func_count; + public uint exports; + } + + private static Elf32_Shdr? FindSection(ReadOnlySpan selections, ReadOnlySpan strTable, string name) + { + var nameSpan = Encoding.UTF8.GetBytes(name).AsSpan(); + foreach (var selection in selections) + { + if (nameSpan.SequenceEqual(strTable.Slice((int)selection.sh_name, name.Length))) + { + return selection; + } + } + + return null; + } + + private static void GenDecrypt(Span buff) + { + var hdr = MemoryMarshal.AsRef(buff); + switch (hdr.decryptMode) + { + case SceExecFileDecryptMode.DECRYPT_MODE_NO_EXEC: + break; + case SceExecFileDecryptMode.DECRYPT_MODE_DEMO_EXEC: + case SceExecFileDecryptMode.DECRYPT_MODE_KERNEL_MODULE: + break; + } + } + + struct Cipher + { + public byte[] Key; + public int Seed; + public int Type; + public byte[] XorKey; + } + + + private static readonly Dictionary Ciphers = new Dictionary + { + {0x00000000, new Cipher {Key = SceMemlmd.key_00000000, Seed = 0x42, Type = 0} }, + {0x01000000, new Cipher {Key = SceMemlmd.key_01000000, Seed = 0x43, Type = 0} }, + {0x4C940AF0, new Cipher {Key = SceMemlmd.key_4C940AF0, Seed = 0x43, Type = 2} }, + {0x4C940BF0, new Cipher {Key = SceMemlmd.key_4C940BF0, Seed = 0x43, Type = 2} }, + {0x4C9410F0, new Cipher {Key = SceMemlmd.key_4C9410F0, Seed = 0x43, Type = 2} }, + {0x4C9412F0, new Cipher {Key = SceMemlmd.key_4C9412F0, Seed = 0x43, Type = 2} }, + {0x4C9413F0, new Cipher {Key = SceMemlmd.key_4C9413F0, Seed = 0x43, Type = 2} }, + {0x4C9414F0, new Cipher {Key = SceMemlmd.key_4C9414F0, Seed = 0x43, Type = 2} }, + {0x4C9415F0, new Cipher {Key = SceMemlmd.key_4C9415F0, Seed = 0x43, Type = 2} }, + {0x4C9490F0, new Cipher {Key = SceMemlmd.key_4C9490F0, Seed = 0x43, Type = 9} }, + {0x4C9491F0, new Cipher {Key = SceMemlmd.key_4C9491F0, Seed = 0x43, Type = 9} }, + {0x4C9494F0, new Cipher {Key = SceMemlmd.key_4C9494F0, Seed = 0x43, Type = 9} }, + {0x4C949AF0, new Cipher {Key = SceMemlmd.key_4C949AF0, Seed = 0x43, Type = 9} }, + {0x4C949BF0, new Cipher {Key = SceMemlmd.key_4C949BF0, Seed = 0x43, Type = 9} }, + {0x4C949CF0, new Cipher {Key = SceMemlmd.key_4C949CF0, Seed = 0x43, Type = 9} }, + {0x4C949DF0, new Cipher {Key = SceMemlmd.key_4C949DF0, Seed = 0x43, Type = 9} }, + {0x4C949EF0, new Cipher {Key = SceMemlmd.key_4C949EF0, Seed = 0x43, Type = 9} }, + {0x4C949FF0, new Cipher {Key = SceMemlmd.key_4C949FF0, Seed = 0x43, Type = 9} }, + {0x4C94A0F0, new Cipher {Key = SceMemlmd.key_4C94A0F0, Seed = 0x43, Type = 9} }, + {0x4C94A1F0, new Cipher {Key = SceMemlmd.key_4C94A1F0, Seed = 0x43, Type = 9} }, + + {0x04000000, new Cipher {Key = key_04000000, Seed = 0x47, Type = 0} }, + {0x628910F0, new Cipher {Key = key_628910F0, Seed = 0x47, Type = 2} }, + {0x62891EF0, new Cipher {Key = key_62891EF0, Seed = 0x47, Type = 2} }, + {0x628928F0, new Cipher {Key = key_628928F0, Seed = 0x47, Type = 2} }, + + {0x2FD311F0, new Cipher {Key = key_2FD311F0, Seed = 0x47, Type = 5, XorKey = key_2FD311F0_xor} }, + {0x2FD312F0, new Cipher {Key = key_2FD312F0, Seed = 0x47, Type = 5, XorKey = key_2FD312F0_xor} }, + {0x2FD313F0, new Cipher {Key = key_2FD313F0, Seed = 0x47, Type = 5, XorKey = key_2FD313F0_xor} }, + + {0x05000000, new Cipher {Key = key_05000000, Seed = 0x48, Type = 0} }, + {0x8B9B10F0, new Cipher {Key = key_8B9B10F0, Seed = 0x48, Type = 2} }, + {0x8B9B1EF0, new Cipher {Key = key_8B9B1EF0, Seed = 0x48, Type = 2} }, + {0x8B9B28F0, new Cipher {Key = key_8B9B28F0, Seed = 0x48, Type = 2} }, + + {0x2E5E10F0, new Cipher {Key = key_2E5E10F0, Seed = 0x48, Type = 5, XorKey = key_2E5E10F0_xor} }, + {0x2E5E11F0, new Cipher {Key = key_2E5E11F0, Seed = 0x48, Type = 5, XorKey = key_2E5E11F0_xor} }, + {0x2E5E12F0, new Cipher {Key = key_2E5E12F0, Seed = 0x48, Type = 5, XorKey = key_2E5E11F0_xor} }, + {0x2E5E13F0, new Cipher {Key = key_2E5E13F0, Seed = 0x48, Type = 5, XorKey = key_2E5E11F0_xor} }, + {0x2E5E80F0, new Cipher {Key = key_2E5E80F0, Seed = 0x48, Type = 7, XorKey = key_2E5E80F0_xor} }, + {0x2E5E90F0, new Cipher {Key = key_2E5E90F0, Seed = 0x48, Type = 10, XorKey = key_2E5E90F0_xor} }, + + {0x06000000, new Cipher {Key = key_06000000, Seed = 0x49, Type = 0} }, + {0xE42C2303, new Cipher {Key = key_E42C2303, Seed = 0x49, Type = 2} }, + {0x5A5C10F0, new Cipher {Key = key_5A5C10F0, Seed = 0x49, Type = 2} }, + {0x5A5C1EF0, new Cipher {Key = key_5A5C1EF0, Seed = 0x49, Type = 2} }, + {0x5A5C28F0, new Cipher {Key = key_5A5C28F0, Seed = 0x49, Type = 2} }, + + {0x0A000000, new Cipher {Key = key_0A000000, Seed = 0x4D, Type = 0} }, + {0xEFD210F0, new Cipher {Key = key_EFD210F0, Seed = 0x4D, Type = 2} }, + {0xEFD21EF0, new Cipher {Key = key_EFD21EF0, Seed = 0x4D, Type = 2} }, + {0xEFD228F0, new Cipher {Key = key_EFD228F0, Seed = 0x4D, Type = 2} }, + + {0x0B000000, new Cipher {Key = key_0B000000, Seed = 0x4E, Type = 8} }, + + {0x0E000000, new Cipher {Key = key_0E000000, Seed = 0x51, Type = 0} }, + {0x63BAB403, new Cipher {Key = key_63BAB403, Seed = 0x51, Type = 2} }, + {0xD82310F0, new Cipher {Key = key_D82310F0, Seed = 0x51, Type = 2} }, + {0xD8231EF0, new Cipher {Key = key_D8231EF0, Seed = 0x51, Type = 2} }, + {0xD82328F0, new Cipher {Key = key_D82328F0, Seed = 0x51, Type = 2} }, + + {0x0F000000, new Cipher {Key = key_0F000000, Seed = 0x52, Type = 0} }, + {0x862648D1, new Cipher {Key = key_862648D1, Seed = 0x52, Type = 1} }, + {0x1B11FD03, new Cipher {Key = key_1B11FD03, Seed = 0x52, Type = 2} }, + {0xD13B05F0, new Cipher {Key = key_D13B05F0, Seed = 0x52, Type = 2} }, + {0xD13B06F0, new Cipher {Key = key_D13B06F0, Seed = 0x52, Type = 2} }, + {0xD13B08F0, new Cipher {Key = key_D13B08F0, Seed = 0x52, Type = 2} }, + {0xD13B10F0, new Cipher {Key = key_D13B10F0, Seed = 0x52, Type = 2} }, + {0xD13B1EF0, new Cipher {Key = key_D13B1EF0, Seed = 0x52, Type = 2} }, + {0xD13B28F0, new Cipher {Key = key_D13B28F0, Seed = 0x52, Type = 2} }, + + {0x4467415D, new Cipher {Key = SceMemlmd.key_4467415D, Seed = 0x59, Type = 1} }, + + {0x02000000, new Cipher {Key = key_02000000, Seed = 0x45, Type = 0} }, + {0x380290F0, new Cipher {Key = key_380290F0, Seed = 0x5A, Type = 9} }, + {0x380291F0, new Cipher {Key = key_380291F0, Seed = 0x5A, Type = 9} }, + {0x380292F0, new Cipher {Key = key_380292F0, Seed = 0x5A, Type = 9} }, + {0x380293F0, new Cipher {Key = key_380293F0, Seed = 0x5A, Type = 9} }, + {0x38029AF0, new Cipher {Key = key_38029AF0, Seed = 0x5A, Type = 9} }, + + {0x03000000, new Cipher {Key = key_03000000, Seed = 0x46, Type = 0} }, + {0x3ACE4DCE, new Cipher {Key = key_3ACE4DCE, Seed = 0x5B, Type = 1} }, + {0x76202403, new Cipher {Key = key_76202403, Seed = 0x5B, Type = 2} }, + {0x457B05F0, new Cipher {Key = key_457B05F0, Seed = 0x5B, Type = 2} }, + {0x457B06F0, new Cipher {Key = key_457B06F0, Seed = 0x5B, Type = 2} }, + {0x457B08F0, new Cipher {Key = key_457B08F0, Seed = 0x5B, Type = 2} }, + {0x457B0AF0, new Cipher {Key = key_457B0AF0, Seed = 0x5B, Type = 2} }, + {0x457B0BF0, new Cipher {Key = key_457B0BF0, Seed = 0x5B, Type = 2} }, + {0x457B0CF0, new Cipher {Key = key_457B0CF0, Seed = 0x5B, Type = 2} }, + {0x457B10F0, new Cipher {Key = key_457B10F0, Seed = 0x5B, Type = 2} }, + {0x457B1EF0, new Cipher {Key = key_457B1EF0, Seed = 0x5B, Type = 2} }, + {0x457B28F0, new Cipher {Key = key_457B28F0, Seed = 0x5B, Type = 2} }, + {0x457B80F0, new Cipher {Key = key_457B80F0, Seed = 0x5B, Type = 6} }, + {0x457B8AF0, new Cipher {Key = key_457B8AF0, Seed = 0x5B, Type = 6} }, + {0x457B90F0, new Cipher {Key = key_457B90F0, Seed = 0x5B, Type = 9} }, + {0x457B91F0, new Cipher {Key = key_457B91F0, Seed = 0x5B, Type = 9} }, + {0x457B92F0, new Cipher {Key = key_457B92F0, Seed = 0x5B, Type = 9} }, + {0x457B93F0, new Cipher {Key = key_457B93F0, Seed = 0x5B, Type = 9} }, + {0x457B9AF0, new Cipher {Key = key_457B9AF0, Seed = 0x5B, Type = 9} }, + + {0x08000000, new Cipher {Key = key_08000000, Seed = 0x4B, Type = 0} }, + {0xC0CB167C, new Cipher {Key = key_C0CB167C, Seed = 0x5D, Type = 1} }, + {0x8004FD03, new Cipher {Key = key_8004FD03, Seed = 0x5D, Type = 2} }, + {0xD91605F0, new Cipher {Key = key_D91605F0, Seed = 0x5D, Type = 2} }, + {0xD91606F0, new Cipher {Key = key_D91606F0, Seed = 0x5D, Type = 2} }, + {0xD9160AF0, new Cipher {Key = key_D9160AF0, Seed = 0x5D, Type = 2} }, + {0xD9160BF0, new Cipher {Key = key_D9160BF0, Seed = 0x5D, Type = 2} }, + {0xD91610F0, new Cipher {Key = key_D91610F0, Seed = 0x5D, Type = 2} }, + {0xD91611F0, new Cipher {Key = key_D91611F0, Seed = 0x5D, Type = 2} }, + {0xD91612F0, new Cipher {Key = key_D91612F0, Seed = 0x5D, Type = 2} }, + {0xD91613F0, new Cipher {Key = key_D91613F0, Seed = 0x5D, Type = 2} }, + {0xD91614F0, new Cipher {Key = key_D91614F0, Seed = 0x5D, Type = 2} }, + {0xD91617F0, new Cipher {Key = key_D91617F0, Seed = 0x5D, Type = 2} }, + {0xD91618F0, new Cipher {Key = key_D91618F0, Seed = 0x5D, Type = 2} }, + {0xD9161AF0, new Cipher {Key = key_D9161AF0, Seed = 0x5D, Type = 2} }, + {0xD9161EF0, new Cipher {Key = key_D9161EF0, Seed = 0x5D, Type = 2} }, + {0xD91628F0, new Cipher {Key = key_D91628F0, Seed = 0x5D, Type = 2} }, + {0xD91680F0, new Cipher {Key = key_D91680F0, Seed = 0x5D, Type = 6} }, + {0xD91681F0, new Cipher {Key = key_D91681F0, Seed = 0x5D, Type = 6} }, + {0xD91690F0, new Cipher {Key = key_D91690F0, Seed = 0x5D, Type = 9} }, + + {0x09000000, new Cipher {Key = key_09000000, Seed = 0x4C, Type = 0} }, + {0xBB67C59F, new Cipher {Key = key_BB67C59F, Seed = 0x5E, Type = 1} }, + {0x0A35EA03, new Cipher {Key = key_0A35EA03, Seed = 0x5E, Type = 2} }, + {0x7B0505F0, new Cipher {Key = key_7B0505F0, Seed = 0x5E, Type = 2} }, + {0x7B0506F0, new Cipher {Key = key_7B0506F0, Seed = 0x5E, Type = 2} }, + {0x7B0508F0, new Cipher {Key = key_7B0508F0, Seed = 0x5E, Type = 2} }, + {0x7B0510F0, new Cipher {Key = key_7B0510F0, Seed = 0x5E, Type = 2} }, + {0x7B051EF0, new Cipher {Key = key_7B051EF0, Seed = 0x5E, Type = 2} }, + {0x7B0528F0, new Cipher {Key = key_7B0528F0, Seed = 0x5E, Type = 2} }, + + {0x0C000000, new Cipher {Key = key_0C000000, Seed = 0x4F, Type = 0} }, + {0x7F24BDCD, new Cipher {Key = key_7F24BDCD, Seed = 0x60, Type = 1} }, + {0xD67B3303, new Cipher {Key = key_D67B3303, Seed = 0x60, Type = 2} }, + {0xADF305F0, new Cipher {Key = key_ADF305F0, Seed = 0x60, Type = 4} }, + {0xADF306F0, new Cipher {Key = key_ADF306F0, Seed = 0x60, Type = 4} }, + {0xADF308F0, new Cipher {Key = key_ADF308F0, Seed = 0x60, Type = 4} }, + {0xADF310F0, new Cipher {Key = key_ADF310F0, Seed = 0x60, Type = 4} }, + {0xADF31EF0, new Cipher {Key = key_ADF31EF0, Seed = 0x60, Type = 4} }, + {0xADF328F0, new Cipher {Key = key_ADF328F0, Seed = 0x60, Type = 4} }, + + {0x0D000000, new Cipher {Key = key_0D000000, Seed = 0x50, Type = 0} }, + {0x1BC8D12B, new Cipher {Key = key_1BC8D12B, Seed = 0x61, Type = 1} }, + {0xD66DF703, new Cipher {Key = key_D66DF703, Seed = 0x61, Type = 2} }, + {0x279D05F0, new Cipher {Key = key_279D05F0, Seed = 0x61, Type = 4} }, + {0x279D06F0, new Cipher {Key = key_279D06F0, Seed = 0x61, Type = 4} }, + {0x279D08F0, new Cipher {Key = key_279D08F0, Seed = 0x61, Type = 4} }, + {0x279D10F0, new Cipher {Key = key_279D10F0, Seed = 0x61, Type = 4} }, + {0x279D1EF0, new Cipher {Key = key_279D1EF0, Seed = 0x61, Type = 4} }, + {0x279D28F0, new Cipher {Key = key_279D28F0, Seed = 0x61, Type = 4} }, + + {0x16D59E03, new Cipher {Key = SceMemlmd.key_16D59E03, Seed = 0x62, Type = 2} }, + {0xCFEF05F0, new Cipher {Key = SceMemlmd.key_CFEF05F0, Seed = 0x62, Type = 2} }, + {0xCFEF06F0, new Cipher {Key = SceMemlmd.key_CFEF06F0, Seed = 0x62, Type = 2} }, + {0xCFEF08F0, new Cipher {Key = SceMemlmd.key_CFEF08F0, Seed = 0x62, Type = 2} }, + + {0x0DAA06F0, new Cipher {Key = key_0DAA06F0, Seed = 0x65, Type = 5, XorKey = key_0DAA06F0_xor} }, + {0x0DAA10F0, new Cipher {Key = key_0DAA10F0, Seed = 0x65, Type = 5, XorKey = key_0DAA10F0_xor} }, + {0x0DAA1EF0, new Cipher {Key = key_0DAA1EF0, Seed = 0x65, Type = 5, XorKey = key_0DAA1EF0_xor} }, + {0x0DAA28F0, new Cipher {Key = key_0DAA28F0, Seed = 0x65, Type = 5, XorKey = key_0DAA28F0_xor} }, + + {0x89742B04, new Cipher {Key = key_89742B04, Seed = 0x65, Type = 3, XorKey = key_89742B04_xor} }, + {0xE92408F0, new Cipher {Key = key_E92408F0, Seed = 0x65, Type = 3, XorKey = key_E92408F0_xor} }, + {0xE92410F0, new Cipher {Key = key_E92410F0, Seed = 0x65, Type = 3, XorKey = key_E92410F0_xor} }, + {0xE9241EF0, new Cipher {Key = key_E9241EF0, Seed = 0x65, Type = 3, XorKey = key_E9241EF0_xor} }, + {0xE92428F0, new Cipher {Key = key_E92428F0, Seed = 0x65, Type = 3, XorKey = key_E92428F0_xor} }, + + {0xE1ED06F0, new Cipher {Key = key_E1ED06F0, Seed = 0x66, Type = 5, XorKey = key_E1ED06F0_xor} }, + {0xE1ED10F0, new Cipher {Key = key_E1ED10F0, Seed = 0x66, Type = 5, XorKey = key_E1ED10F0_xor} }, + {0xE1ED1EF0, new Cipher {Key = key_E1ED1EF0, Seed = 0x66, Type = 5, XorKey = key_E1ED1EF0_xor} }, + {0xE1ED28F0, new Cipher {Key = key_E1ED28F0, Seed = 0x66, Type = 5, XorKey = key_E1ED28F0_xor} }, + + {0xF5F12304, new Cipher {Key = key_F5F12304, Seed = 0x66, Type = 3, XorKey = key_F5F12304_xor} }, + {0x692808F0, new Cipher {Key = key_692808F0, Seed = 0x66, Type = 3, XorKey = key_692808F0_xor} }, + {0x692810F0, new Cipher {Key = key_692810F0, Seed = 0x66, Type = 3, XorKey = key_692810F0_xor} }, + {0x69281EF0, new Cipher {Key = key_69281EF0, Seed = 0x66, Type = 3, XorKey = key_69281EF0_xor} }, + {0x692828F0, new Cipher {Key = key_692828F0, Seed = 0x66, Type = 3, XorKey = key_692828F0_xor} }, + + {0x3C2A08F0, new Cipher {Key = key_3C2A08F0, Seed = 0x67, Type = 2} }, + {0x3C2A10F0, new Cipher {Key = key_3C2A10F0, Seed = 0x67, Type = 2} }, + {0x3C2A1EF0, new Cipher {Key = key_3C2A1EF0, Seed = 0x67, Type = 2} }, + {0x3C2A28F0, new Cipher {Key = key_3C2A28F0, Seed = 0x67, Type = 2} }, + + {0x407810F0, new Cipher {Key = key_407810F0, Seed = 0x6A, Type = 5, XorKey = key_407810F0_xor} }, + }; + + public static int Encrypt(Span encData, ReadOnlySpan modData, uint tag, SceExecFileDecryptMode cryptType, ReadOnlySpan versionKey, string contentId) => Encrypt(encData, modData, tag, cryptType, versionKey, contentId, Array.Empty()); + + public static int Encrypt(Span encData, ReadOnlySpan modData, uint tag, SceExecFileDecryptMode cryptType, ReadOnlySpan versionKey, string contentId, ReadOnlySpan config) + { + int ret = -1; + if (!Ciphers.ContainsKey(tag)) + { + return ret; + } + var elfHdr = MemoryMarshal.AsRef(modData); + //var pspHdrSize = Marshal.SizeOf(); + const int pspHdrSize = 0xD0; + var selection = + MemoryMarshal.Cast(modData.Slice((int)elfHdr.e_shoff, + elfHdr.e_shentsize * elfHdr.e_shnum)); + var programHeader = + MemoryMarshal.Cast(modData.Slice((int)elfHdr.e_phoff, + elfHdr.e_phentsize * elfHdr.e_phnum)); + ref var pspHdr = ref MemoryMarshal.AsRef(encData); + pspHdr.magic = 0x5053507E; + //pspHdr.modAttribute = 0x0200; + pspHdr.moduleVerLo = 1; + pspHdr.moduleVerHi = 1; + pspHdr.modVersion = 1; + // pspHdr.nSegments = 2; + pspHdr.elfSize = modData.Length; + pspHdr.bootEntry = elfHdr.e_entry; + // pspHdr.modInfoOffset = 0x2940; + pspHdr.decryptMode = cryptType; + + Elf32_Shdr? sh = null; + SceModuleInfo modInfo; + if (selection.Length > 0) + { + var strSec = selection[elfHdr.e_shstrndx]; + var strTable = modData.Slice((int)strSec.sh_offset, (int)strSec.sh_size); + sh = FindSection(selection, strTable, ".rodata.sceModuleInfo"); + } + if (sh.HasValue) + { + pspHdr.modInfoOffset = (int)sh.Value.sh_offset; + modInfo = MemoryMarshal.Read(modData.Slice((int)sh.Value.sh_offset)); + } + else + { + var ph = programHeader[0]; + pspHdr.modInfoOffset = (int)ph.p_paddr; + modInfo = MemoryMarshal.Read(modData.Slice((int)ph.p_paddr)); + } + var ph0 = programHeader[0]; + var exports = MemoryMarshal.Read(modData.Slice((int)(ph0.p_offset + modInfo.ent_top - ph0.p_vaddr))); + if (exports.var_count > 0) + { + var total = exports.var_count + exports.func_count; + var expNids = MemoryMarshal.Cast(modData.Slice((int)(ph0.p_offset + exports.exports - ph0.p_vaddr), total * 4)); + var expPtrs = MemoryMarshal.Cast(modData.Slice((int)(ph0.p_offset + exports.exports - ph0.p_vaddr + total * 4), total * 4)); + for (var i = exports.func_count; i < total; i++) + { + if (expNids[i] == 0x11B97506) + { + var devkitVersion = MemoryMarshal.Read(modData.Slice((int)(ph0.p_offset + expPtrs[i] - ph0.p_vaddr))); + if (devkitVersion != 0x0c000031) + { + pspHdr.devkitVersion = devkitVersion; + } + break; + } + } + } + + pspHdr.modAttribute = modInfo.modattribute; + + byte j = 0; + + + for (var i = 0; i < elfHdr.e_phnum; i++) + { + if (programHeader[i].p_type == PT_LOAD) + { + if (j > SCE_MODULE_MAX_SEGMENTS) + { + throw new Exception("ERROR: Too many EBOOT PH segments!"); + } + pspHdr.segAlign[j] = (ushort)programHeader[i].p_align; + pspHdr.segAddress[j] = programHeader[i].p_vaddr; + pspHdr.segSize[j] = programHeader[i].p_memsz; + pspHdr.bssSize = programHeader[i].p_memsz - programHeader[i].p_filesz; + j++; + } + } + + pspHdr.nSegments = j; + + bool compress = false; + switch (cryptType) + { + case SceExecFileDecryptMode.DECRYPT_MODE_UMD_GAME_EXEC: + modInfo.modname.CopyTo(pspHdr.modName); + pspHdr.compAttribute = 0; + pspHdr.dataOffset = 0x80; + break; + case SceExecFileDecryptMode.DECRYPT_MODE_POPS_EXEC: + compress = true; + pspHdr.modName[0] = 0x20; + pspHdr.modAttribute = 0x0200; + pspHdr.compAttribute = 1; + pspHdr.dataOffset = 0x890; + break; + } + + + if (compress) + { + using var ms = new MemoryStream(); + using (var gs = new Ionic.Zlib.GZipStream(ms, Ionic.Zlib.CompressionMode.Compress, true)) + { + gs.LastModified = new System.DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + gs.Write(modData); + } + var tmp = ms.ToArray(); + tmp[9] = 3; + modData = tmp.AsSpan(); + } + modData.CopyTo(encData.Slice(pspHdrSize + pspHdr.dataOffset)); + var chk_size = (modData.Length + 15) / 16 * 16; + pspHdr.dataSize = modData.Length; + pspHdr.pspSize = pspHdrSize + pspHdr.dataOffset + chk_size; + + // MemoryMarshal.Write(encData, ref pspHdr); + + //var pspHdrSpan = MemoryMarshal.CreateReadOnlySpan(ref pspHdr, 1); + //var pspHdrBuffer = MemoryMarshal.AsBytes(pspHdrSpan); + Span randomSpan = null; + + if (cryptType == SceExecFileDecryptMode.DECRYPT_MODE_POPS_EXEC) + { + //randomSpan = new byte[] + //{ + //0x01, 0x94, 0xB1, 0x16, 0x3D, 0x01, 0x42, 0x0F, 0xC7, 0x03, 0xDE, 0x10, 0x1C, 0x50, 0x91, 0x52, + //0x73, 0x31, 0x52, 0xD7, 0xAF, 0xB4, 0x0A, 0xBF, 0x1C, 0xA5, 0x39, 0xCA, 0x1F, 0xBF, 0xA1, 0x0C, + //0xF6, 0x1A, 0x52, 0x53, 0x7E, 0x68, 0x2F, 0xDE, 0x66, 0xC3, 0x82, 0x31, 0x08, 0x1A, 0x18, 0xC3, + //0xFC, 0xE5, 0x83, 0xD5, 0xA6, 0x8F, 0xBC, 0x36, 0xD9, 0x17, 0x8E, 0x00, 0xEC, 0x5A, 0x49, 0x63, + //0xEF, 0xA2, 0x7E, 0x89, 0x35, 0x10, 0x0D, 0x28, 0xFE, 0x67, 0xF1, 0xD9, 0xA5, 0x73, 0x17, 0x73, + //0x86, 0x5B, 0xF1, 0x86, 0x06, 0x73, 0xCB, 0x18, 0xB8, 0xF9, 0x0B, 0x61, 0xDD, 0xB0, 0xC0, 0x56, + //0x3A, 0x96, 0xED, 0x1E, 0xE6, 0x8C, 0x37, 0xBE, 0xA2, 0xA1, 0x61, 0xDE, 0x7D, 0x48, 0xA3, 0x21, + //0x3C, 0x06, 0xBF, 0xB0, 0xB2, 0x40, 0x8C, 0x46, 0xED, 0x7B, 0x52, 0x01, 0x4F, 0xDD, 0x85, 0x43, + //0x09, 0x61, 0x65, 0x8F, 0xCC, 0x53, 0x29, 0xCC, 0xDC, 0x48, 0x99, 0x8E, 0x73, 0x09, 0x67, 0x68, + //0x93, 0x0A, 0xF5, 0x04, 0xFC, 0x3E, 0x51, 0xBB, 0x04, 0xD3, 0x70, 0xF9, 0xD0, 0xB0, 0xEA, 0x6D, + //0xC8, 0xD7, 0xDE, 0x29, 0x91, 0xB0, 0xC9, 0xA0, 0xE9, 0x25, 0x17, 0x2A, 0x61, 0xF4, 0xC0, 0x9B, + //0xEE, 0xD4, 0xCF, 0x55, 0x9F, 0x0C, 0xA9, 0x06, 0xE3, 0x79, 0xF7, 0x80, 0x85, 0xB5, 0x3C, 0x0E, + //0x6D, 0xC1, 0x5D, 0x38, 0x2F, 0x99, 0x74, 0xCA, 0xC0, 0xAC, 0x7F, 0x3C, 0x7C, 0xF5, 0xB5, 0xA9, + //0x85, 0x27, 0xC8, 0xF2, 0xEE, 0x7D, 0xCF, 0xE6, 0x53, 0x99, 0xF4, 0x14, 0x28, 0x20, 0x42, 0x3E, + //0x13, 0x7F, 0xB9, 0x60, 0x9E, 0xC4, 0xAC, 0xE5, 0x02, 0x8B, 0x36, 0x9A, 0xB3, 0x89, 0x46, 0x33, + //0xBC, 0x4D, 0x79, 0xD5, 0x1F, 0x8D, 0x36, 0xB5, 0xAB, 0x01, 0x0F, 0xFE, 0xC2, 0x09, 0xFD, 0xD8, + //0x4B, 0x12, 0x9F, 0x05, 0xF0, 0x6B, 0x3C, 0xBD, 0x3F, 0x65, 0xF5, 0x5B, 0x86, 0x19, 0x11, 0x20, + //0x53, 0xB1, 0x80, 0x32, 0x62, 0x3E, 0x00, 0x11, 0x9E, 0x8D, 0x4B, 0x57, 0x56, 0x48, 0xBC, 0x5B, + //0x32, 0x90, 0xA1, 0x9E, 0x05, 0xD1, 0xEB, 0x8C, 0x12, 0xA7, 0x4D, 0x33, 0x15, 0xCB, 0xC0, 0xD2, + //0x8F, 0x44, 0x98, 0x6F, 0x4B, 0x81, 0x44, 0x58, 0xD0, 0x5F, 0x88, 0xA5, 0x22, 0x06, 0x76, 0x9F, + //0x15, 0xB2, 0x40, 0xF2, 0x3C, 0x2B, 0x55, 0x6E, 0x1B, 0x9B, 0xCE, 0x11, 0x37, 0x75, 0xA6, 0xBE, + //0xE3, 0xA7, 0xFF, 0x30, 0xE8, 0x5C, 0x7B, 0xAF, 0x1C, 0xFC, 0x63, 0x4A, 0x5C, 0xE4, 0xCF, 0xBD, + //0x68, 0x89, 0xC8, 0xDF, 0x89, 0x63, 0x61, 0x71, 0x8C, 0xCD, 0xB2, 0x21, 0x23, 0x55, 0x5E, 0x8E, + //0x6F, 0x04, 0x89, 0xC0, 0x4E, 0xF6, 0x3A, 0x74, 0x89, 0xBA, 0xF4, 0x51, 0x9A, 0x5D, 0x09, 0x2C, + //0x76, 0x48, 0x9F, 0x86, 0xCD, 0xF3, 0x66, 0xA6, 0xBF, 0x78, 0xC7, 0xD0, 0x95, 0x48, 0x4E, 0x31, + //0x2B, 0xBC, 0x73, 0x70, 0x95, 0x7C, 0xE9, 0x1E, 0x8F, 0x55, 0x35, 0x83, 0x37, 0x65, 0x9C, 0x34, + //0x98, 0x15, 0x6F, 0x70, 0x31, 0x7C, 0xED, 0x46, 0x2A, 0xC4, 0x3E, 0xAE, 0x55, 0x49, 0x74, 0x37, + //0x81, 0x02, 0x5C, 0x73, 0x79, 0xA3, 0x6E, 0xCF, 0x37, 0xFB, 0x0F, 0x9F, 0xCC, 0x1E, 0xC1, 0x73, + //0xF5, 0xE1, 0x8B, 0x84, 0x52, 0xF2, 0x6B, 0xD3, 0xE7, 0x29, 0x69, 0xB1, 0xD9, 0xE9, 0xEB, 0x95, + //0x6D, 0xD3, 0x00, 0xC2, 0x7C, 0x5D, 0xDF, 0x84, 0xA6, 0x8D, 0xB0, 0x2E, 0xC2, 0x41, 0xC1, 0x49, + //0x2A, 0x61, 0xAA, 0x3B, 0x40, 0x98, 0x6F, 0x36, 0x3D, 0xAB, 0x31, 0x08, 0x50, 0xD1, 0x5C, 0xCC, + //0x0E, 0x6F, 0x7C, 0xD4, 0x98, 0x96, 0x73, 0x13, 0x9D, 0xD8, 0xF5, 0x4E, 0x81, 0x08, 0xEA, 0x2A, + //0x7E, 0x1A, 0x8A, 0x86, 0xC5, 0x70, 0x14, 0x15, 0xC6, 0x3F, 0x00, 0x86, 0x8C, 0x9F, 0x20, 0x29, + //0x7B, 0xF4, 0xD2, 0xDE, 0xB1, 0x8A, 0x3F, 0xE9, 0x58, 0x00, 0x6B, 0x19, 0x0C, 0xC1, 0xF9, 0x56, + //0x95, 0x29, 0xCC, 0x95, 0x29, 0x56, 0x16, 0xE3, 0xBA, 0xCE, 0xCA, 0x5C, 0xD5, 0x92, 0xB0, 0x49, + //0xBA, 0xBD, 0x9B, 0xE1, 0x0E, 0x22, 0x9A, 0x2B, 0x3A, 0x94, 0x1F, 0xB4, 0x74, 0x24, 0x1B, 0xBE, + //0xF3, 0x07, 0x7A, 0xD0, 0xCF, 0x6F, 0x3C, 0xC2, 0x5B, 0xA1, 0x08, 0x3A, 0xA6, 0x9F, 0xE5, 0xB1, + //0x95, 0x82, 0x9F, 0x1D, 0xC3, 0xAA, 0xEA, 0x8B, 0x75, 0x1C, 0x63, 0xA5, 0x3D, 0xAF, 0x6B, 0x70, + //0x21, 0x59, 0x4E, 0x50, 0x83, 0xF0, 0xCD, 0x7D, 0x83, 0x34, 0x68, 0x78, 0x71, 0xB1, 0x47, 0x2E, + //0x48, 0xB5, 0xCC, 0xE1, 0xAF, 0x8A, 0x04, 0xBD, 0xF4, 0x4B, 0xB7, 0x1F, 0xB5, 0x46, 0x47, 0x02, + //0xD7, 0xE8, 0x97, 0xDE, 0x53, 0x94, 0x41, 0xE3, 0x6F, 0x26, 0x9B, 0x4F, 0x97, 0x60, 0xAA, 0xA1, + //0x2F, 0x1C, 0xD3, 0x27, 0x99, 0x92, 0x21, 0x08, 0x32, 0x4F, 0x44, 0x4C, 0xA7, 0x1C, 0x73, 0xC6, + //0x7A, 0xCF, 0xC4, 0xBD, 0x7B, 0xAB, 0x17, 0x37, 0x33, 0xF2, 0x76, 0x2C, 0x65, 0xD6, 0x85, 0xB8, + //0x15, 0xBA, 0xC7, 0x82, 0x05, 0x65, 0x60, 0x0C, 0xC8, 0x1D, 0x32, 0xF6, 0xAB, 0x12, 0xD6, 0x59, + //0xA7, 0xC7, 0x06, 0x5C, 0x2F, 0x2D, 0xEC, 0xE7, 0x82, 0xF5, 0x40, 0x7D, 0x58, 0x80, 0xB2, 0x61, + //0xA8, 0x95, 0x58, 0xF5, 0xEA, 0x93, 0x5F, 0xEA, 0xAD, 0x77, 0x1C, 0x8E, 0xC3, 0x7A, 0x1B, 0xCF, + //0x31, 0x53, 0x8D, 0xA9, 0x86, 0xC6, 0x03, 0x09, 0x5D, 0x23, 0xF2, 0x25, 0xE4, 0x62, 0xAB, 0xC4, + //0x71, 0xA6, 0x3D, 0x0B, 0xDA, 0x3A, 0x24, 0xF6, 0x85, 0x3E, 0xD1, 0x13, 0x28, 0xEC, 0x58, 0xA3, + //0xC6, 0x18, 0x91, 0x75, 0x0E, 0xD6, 0x06, 0x6C, 0x89, 0xA1, 0xA7, 0xDE, 0xBF, 0x59, 0xD4, 0x2C, + //0xE4, 0x8C, 0x08, 0x15, 0x13, 0xF5, 0xD2, 0xD6, 0x6D, 0xC8, 0xEB, 0xE9, 0x9F, 0x9E, 0x19, 0x39, + //0x81, 0x7B, 0xE2, 0x89, 0x07, 0x1B, 0x98, 0xE3, 0x20, 0x18, 0xFE, 0xEF, 0xFD, 0x75, 0xED, 0x6D, + //0x9E, 0x1B, 0x21, 0x97, 0x17, 0x19, 0x59, 0xD5, 0xCA, 0xD1, 0xA0, 0xED, 0x7F, 0xAE, 0xEF, 0x8E, + //0x38, 0x8E, 0xAC, 0x1A, 0xC4, 0x0E, 0x4D, 0xDE, 0x03, 0xF5, 0x93, 0x95, 0x9C, 0xC9, 0x5E, 0x00, + //0x3A, 0x4E, 0x46, 0x8F, 0xA3, 0xAB, 0x6D, 0x61, 0x49, 0x6E, 0xCC, 0x0E, 0x8E, 0x4B, 0xC6, 0x91, + //0xB2, 0x08, 0x79, 0x57, 0x2F, 0x29, 0x76, 0xFA, 0x09, 0x8A, 0x59, 0xF9, 0x2B, 0x6E, 0x48, 0xF4, + //0x06, 0xF6, 0x82, 0xE8, 0xFC, 0x3F, 0xFC, 0x5C, 0xD8, 0x3B, 0x02, 0xD3, 0xC5, 0x20, 0x0C, 0xBB, + //0x53, 0x63, 0x06, 0xEF, 0x67, 0x85, 0xE4, 0xAB, 0x1E, 0x62, 0xEB, 0x20, 0x31, 0xE0, 0x47, 0xCD, + //0x2A, 0xAE, 0xF1, 0x85, 0x55, 0x69, 0xE5, 0xE2, 0xC1, 0x9A, 0x3D, 0xF3, 0x74, 0x75, 0x4F, 0xCD, + //0x94, 0x2C, 0xFB, 0x9B, 0x29, 0x81, 0x82, 0x07, 0x79, 0xC4, 0xB2, 0xD7, 0x62, 0x43, 0x78, 0x7C, + //0xF2, 0xC1, 0xAF, 0x37, 0xAA, 0x9A, 0xDA, 0xDB, 0x7D, 0xCC, 0xA2, 0xC7, 0x54, 0x56, 0xB6, 0x76, + //0xCF, 0x57, 0xE5, 0x0E, 0x2E, 0xB9, 0xF4, 0x68, 0x99, 0x36, 0xEE, 0xAF, 0x90, 0x21, 0x8F, 0xC8, + //0x5C, 0x92, 0x0A, 0x99, 0xDD, 0x6A, 0x2A, 0xB5, 0x74, 0xB9, 0xAC, 0xCC, 0x64, 0xA3, 0xA4, 0xC7, + //0xBD, 0xEE, 0x9A, 0xCD, 0x60, 0x3B, 0xBB, 0xB8, 0xE2, 0xAF, 0xE0, 0x91, 0x69, 0x37, 0x61, 0x63, + //0x04, 0x97, 0x52, 0x49, 0x86, 0x89, 0xC5, 0x80, 0xAA, 0x72, 0xA9, 0xEA, 0x87, 0xD0, 0x3A, 0xDA, + //0x7E, 0xAE, 0x4A, 0x84, 0x83, 0xC7, 0x1F, 0x12, 0xB9, 0x2E, 0x6B, 0x8E, 0xAC, 0x62, 0x5A, 0xF8 + //}; + //randomSpan.CopyTo(encData.Slice(0x150)); + config.CopyTo(encData[0x150..]); + //RandomNumberGenerator.Fill(encData.Slice(0x150, 0x410)); + + // JP9000-NPJI90001_00-0000000000000001 + // JP0082-NPJJ00294_00-0000000000000001 + Encoding.ASCII.GetBytes(contentId, encData[(0x150 + 0x410)..]); + int tmp = 0x01000000; + MemoryMarshal.Write(encData[0x590..], ref tmp); + } + else if (pspHdr.dataOffset > 0x80) + { + RandomNumberGenerator.Fill(encData.Slice(0x150, pspHdr.dataOffset - 0x80)); + } + + var cipher = Ciphers[tag]; + + var type = cipher.Type; + var keySeed = cipher.Seed; + var xorKey = cipher.XorKey.AsSpan(); + + // ENCRYPT DATA + Span aesKeys = stackalloc byte[32]; + using (var aes = AesHelper.CreateAes()) + { + // aes.Key = new byte[] { 0x37, 0x49, 0x0A, 0x87, 0xA3, 0xB3, 0x7B, 0x50, 0x47, 0x4E, 0x21, 0x2B, 0x4A, 0x0F, 0xA6, 0xC8 }; + aes.Key.AsSpan().CopyTo(aesKeys); + AesHelper.AesEncrypt(aes, encData.Slice(pspHdrSize + pspHdr.dataOffset), encData.Slice(pspHdrSize + pspHdr.dataOffset, modData.Length)); + } + + // CMAC HASHES + ref var cmd1Hdr = ref MemoryMarshal.AsRef(encData.Slice(0x40)); + using (var aesCmac = AesHelper.CreateAes()) + { + cmd1Hdr.mode = KIRKEngine.KIRK_MODE_CMD1; + if (type == 6 || type == 7) + { + cmd1Hdr.ecdsa_hash = 1; + } + encData[..0x80].CopyTo(encData.Slice(0x40 + 0x90)); + + // aesCmac.Key = new byte[] { 0xBE, 0xAF, 0x2D, 0x80, 0xBF, 0xC1, 0xCC, 0x53, 0x3B, 0xCF, 0x18, 0x7B, 0x95, 0xFA, 0xC7, 0xCC }; + aesCmac.Key.AsSpan().CopyTo(aesKeys.Slice(16)); + AesHelper.Cmac(aesCmac, cmd1Hdr.CMAC_header_hash, encData.Slice(0xA0, 0x30)); + AesHelper.Cmac(aesCmac, cmd1Hdr.CMAC_data_hash, encData.Slice(0xA0, 0x30 + pspHdr.dataOffset + chk_size)); + //cmac_header_hash.CopyTo(pspHdr.cmacHeaderHash); + //cmac_data_hash.CopyTo(pspHdr.cmacDataHash); + } + + // ENCRYPT KEYS + using (var kirkAes = AesHelper.CreateKirkAes()) + { + AesHelper.AesEncrypt(kirkAes, cmd1Hdr.AESKeys, aesKeys); + } + + ret = BuildKeyData(keySeed, 0, type, cipher.Key, versionKey); + if (ret != 0) + { + return ret; + } + + KirkMemory.Span.Fill(0); + KirkCmd1Memory.Span.Fill(0); + KirkEcdsaMemory.Span.Fill(0); + + if ((1 < type && type < 8) || type == 9 || type == 10) + { + if (type == 6 || type == 7) + { + // modData.Slice(0x80).CopyTo(buf5.Slice(0, 0x20)); + encData.Slice(0xb0, 0x10).CopyTo(KirkMemory.Slice(0xc0).Span); + encData.Slice(0xd0, 0x80).CopyTo(KirkMemory.Slice(0xd0).Span); + encData.Slice(0xd0, 0x80).Fill(0); + } + else + { + encData.Slice(0xb0, 0x10).CopyTo(KirkMemory.Slice(0xc0).Span); + encData.Slice(0xd0, 0x80).CopyTo(KirkMemory.Slice(0xd0).Span); + encData.Slice(0xd0, 0x80).Fill(0); + } + + unsafe + { + fixed (byte* ptr = encData.Slice(0x40)) + { + + } + + fixed (byte* ptr1 = KirkMemory.Slice(0x6c).Span) + { + + } + } + + XorKeyInto(KirkMemory.Slice(0x80).Span, 0x40, encData.Slice(0x40), KeyData.Slice(80).Span); + ret = Kirk4(KirkMemory.Slice(0x6c).Span, 0x40, keySeed, 0); + if (ret != 0) + { + ret = -7; + return ret; + } + XorKeyLarge(KirkMemory.Slice(0x80).Span, 0x40, KeyData.Slice(16).Span); + Span k4 = stackalloc byte[] { 0x4A, 0xB8, 0x0B, 0x41, 0xA1, 0xDF, 0x55, 0x0D, 0xFC, 0xD1, 0xA6, 0xA6, 0x84, 0xFE, 0xCE, 0x6A }; + //if (randomSpan != null) + //{ + // using (var aes = AesHelper.CreateAes()) + // { + // aes.Key = k4.ToArray(); + // AesHelper.AesDecrypt(aes, randomSpan, randomSpan, 0x410); + // } + //} + RandomNumberGenerator.Fill(k4); + k4.CopyTo(KirkMemory.Slice(0x70).Span); + if (type == 4) + { + + } + else + { + + + if (type == 6 || type == 7) + { + // TODO + } + else + { + KirkMemory.Span.Slice(0x18, 0x58).Fill(0); + } + // if (b_0xd4 == 0x80) + // KirkMemory.Span[0x18] = 0x80; + + var value = 0x14c; + MemoryMarshal.Write(KirkMemory.Span, ref value); + MemoryMarshal.Write(KirkMemory.Slice(4).Span, ref tag); + KeyData[..0x10].CopyTo(KirkMemory[8..]); + } + } + else + { + // TODO + } + + ret = KIRKEngine.sceUtilsBufferCopyWithRange(KirkCmd1Memory.Span, 0x150, KirkMemory.Span, 0x150, + KIRKEngine.KIRK_CMD_SHA1_HASH); + if (ret != 0) + { + ret = -6; + return ret; + } + + + if ((1 < type && type < 8) || type == 9 || type == 10) + { + if (type == 4) + { + KirkMemory.Slice(0x18, 0x67).CopyTo(KirkMemory); + } + else + { + KirkMemory.Slice(0x70, 0x10).CopyTo(KirkMemory.Slice(0x5c)); + if (type == 6 || type == 7) + { + KirkMemory.Slice(0x50, 0x20).CopyTo(KirkEcdsaMemory); + KirkEcdsaMemory[..0x20].CopyTo(KirkMemory[0x3c..]); + } + } + KirkCmd1Memory[..0x14].CopyTo(KirkMemory[0x6c..]); + } + else + { + // TODO + } + + if (type == 1) + { + // TODO + } + else + { + unsafe + { + fixed (byte* ptr = &MemoryMarshal.GetReference(KirkCmd1Memory.Slice(0x14).Span)) + { + + } + } + + KirkMemory.Slice(0x5c, 0x60).CopyTo(KirkCmd1Memory.Slice(0x14)); + ret = Kirk4(KirkCmd1Memory.Span, 0x60, keySeed, 0); + if (ret != 0) + { + return -5; + } + + if (type == 3 || type == 5 || type == 7 || type == 10) + { + XorKey(KirkCmd1Memory.Span.Slice(0x14), 0x60, xorKey); + } + + if ((1 < type && type < 8) || type == 9 || type == 10) + { + KirkCmd1Memory.Slice(0x14, 0x60).CopyTo(KirkMemory.Slice(0x5c)); + } + } + + if (type == 3) + { + // TODO + } + else if (type == 5 || type == 7 || type == 10) + { + KirkMemory.Slice(0xd0, 0x80).Span.CopyTo(pspHdr.RawHdr); + KirkMemory.Slice(0xc0, 0x10).Span.CopyTo(pspHdr.sizeInfo); + KirkMemory.Slice(0xb0, 0x10).CopyTo(KirkCmd1Memory.Slice(0x30)); + KirkMemory.Slice(0x80, 0x30).CopyTo(KirkCmd1Memory); + KirkMemory.Slice(0x6c, 0x10).CopyTo(KirkCmd1Memory.Slice(0x40)); + KirkMemory.Slice(0x6c, 0x14).Span.CopyTo(pspHdr.sha1Hash); + KirkMemory.Slice(0x5c, 0x10).Span.CopyTo(pspHdr.keyData4); + + if (type == 7) + { + KirkMemory.Slice(0x3c).Span.CopyTo(pspHdr.sCheck.Slice(56, 0x20)); + } + + KirkCmd1Memory[..0x50].CopyTo(KirkMemory[0x14..]); + ret = Kirk4(KirkMemory.Span, 0x50, keySeed, 0); + if (ret != 0) + { + return -13; + } + XorKey(KirkMemory.Slice(0x14).Span, 0x50, xorKey, versionKey); + KirkMemory.Slice(0x14, 0x30).Span.CopyTo(pspHdr.keyData); + KirkMemory.Slice(0x44, 0x10).Span.CopyTo(pspHdr.cmacDataHash); + KirkMemory.Slice(0x54, 0x10).Span.CopyTo(pspHdr.sha1Hash); + pspHdr.tag = tag; + } + else if (type == 2 || type == 4 || type == 6 || type == 9) + { + KirkMemory.Slice(0x5c, 0x10).Span.CopyTo(pspHdr.keyData4); + KirkMemory.Slice(0x6c, 0x14).Span.CopyTo(pspHdr.sha1Hash); + KirkMemory.Slice(0x80, 0x30).Span.CopyTo(pspHdr.keyData); + KirkMemory.Slice(0xb0, 0x10).Span.CopyTo(pspHdr.cmacDataHash); + KirkMemory.Slice(0xc0, 0x10).Span.CopyTo(pspHdr.sizeInfo); + KirkMemory.Slice(0xd0, 0x80).Span.CopyTo(pspHdr.RawHdr); + pspHdr.tag = tag; + pspHdr.sCheck.Clear(); + } + else + { + KirkMemory[..0x80].Span.CopyTo(pspHdr.CheckData); + KirkMemory.Slice(0x80, 0x30).Span.CopyTo(pspHdr.keyData); + KirkMemory.Slice(0xd0, 0x80).Span.CopyTo(pspHdr.RawHdr); + } + + return ret; + } + } +} diff --git a/PspCrypto/SceNpDrm.cs b/PspCrypto/SceNpDrm.cs new file mode 100644 index 0000000..96db277 --- /dev/null +++ b/PspCrypto/SceNpDrm.cs @@ -0,0 +1,1338 @@ +using PspCrypto.Security.Cryptography; +using System; +using System.Buffers.Binary; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; + +namespace PspCrypto +{ + public static class SceNpDrm + { + unsafe struct SceEbootPbp + { + public ulong Magic; + public int KeyType; + public int Type; + private fixed byte _contentId[0x30]; + + public Span ContentId + { + get + { + fixed (byte* ptr = _contentId) + { + return new Span(ptr, 0x30); + } + } + } + + public ulong Aid; + public ulong SecureTick; + public long PbpSize; + public int SwVer; + public int DiscCount; + private fixed long _discOffsets[6]; + + public Span DiscOffsets + { + get + { + fixed (long* ptr = _discOffsets) + { + return new Span(ptr, 6); + } + } + } + private fixed byte _padding[0xC8]; + private fixed byte _pbpHdrSig[0x38]; + + public Span PbpHdrSig + { + get + { + fixed (byte* ptr = _pbpHdrSig) + { + return new Span(ptr, 0x38); + } + } + } + private fixed byte _npUmdImgSig[0x38]; + + public Span NpUmdImgSig + { + get + { + fixed (byte* ptr = _npUmdImgSig) + { + return new Span(ptr, 0x38); + } + } + } + private fixed byte _sig[0x38]; + + public Span Sig + { + get + { + fixed (byte* ptr = _sig) + { + return new Span(ptr, 0x38); + } + } + } + } + unsafe struct SceEbootPbp100 + { + public ulong Magic; + public int KeyType; + public int Type; + private fixed byte _contentId[0x30]; + + public Span ContentId + { + get + { + fixed (byte* ptr = _contentId) + { + return new Span(ptr, 0x30); + } + } + } + private fixed byte _padding[0x18]; + private fixed byte _pbpHdrSig[0x38]; + + public Span PbpHdrSig + { + get + { + fixed (byte* ptr = _pbpHdrSig) + { + return new Span(ptr, 0x38); + } + } + } + private fixed byte _npUmdImgSig[0x38]; + + public Span NpUmdImgSig + { + get + { + fixed (byte* ptr = _npUmdImgSig) + { + return new Span(ptr, 0x38); + } + } + } + private fixed byte _sig[0x38]; + + public Span Sig + { + get + { + fixed (byte* ptr = _sig) + { + return new Span(ptr, 0x38); + } + } + } + } + + unsafe struct SceDiscInfo + { + private fixed byte _id[0x30]; + + public Span Id + { + get + { + fixed (byte* ptr = _id) + { + return new Span(ptr, 0x30); + } + } + } + + public int Version; + public int DiscCount; + public long FileSize; + private fixed long _diskOffsets[6]; + + public Span Offsets + { + get + { + fixed (long* ptr = _diskOffsets) + { + return new Span(ptr, 6); + } + } + } + + private fixed byte _pad[0x20]; + private fixed byte _discsSig[0x38]; + + public Span DiscsSig + { + get + { + fixed (byte* ptr = _discsSig) + { + return new Span(ptr, 0x38); + } + } + } + private fixed byte _sig[0x38]; + + public Span Sig + { + get + { + fixed (byte* ptr = _sig) + { + return new Span(ptr, 0x38); + } + } + } + + } + + public static ulong Aid { get; set; } + + public static byte[] SceDiskInfo => Resource.__sce_discinfo; + + private const int BLK_SIZE = 0x7C0; + + private static readonly Memory _memory = new byte[0x1000]; + + private static byte[] _psId; + + private static long _fuseId; + + public static void SetPSID(byte[] psid) + { + _psId = psid; + } + + public static void SetFuseId(long fuseId) + { + _fuseId = fuseId; + } + + public static void SetFuseId(Span fuseId) + { + SetFuseId(MemoryMarshal.Read(fuseId)); + } + + public unsafe struct SceNpDrmKey + { + private fixed byte _KeyData[16]; + public Span KeyData + { + get + { + fixed (byte* ptr = _KeyData) + { + return new Span(ptr, 16); + } + } + } + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct Rif + { + private short _version; + private short _versionFlag; + private int _drmType; + private fixed byte _accountId[8]; + private fixed byte _contentId[0x30]; + private fixed byte _encKey1[0x10]; + private fixed byte _encKey2[0x10]; + private long _startTime; + private long _endTime; + private fixed byte _ecdsaSig[0x28]; + public short Version => _version; + public short VersionFlag => _versionFlag; + public int DrmType => _drmType; + public Span AccountId + { + get + { + fixed (byte* ptr = _accountId) + { + return new Span(ptr, 8); + } + } + } + public Span ContentId + { + get + { + fixed (byte* ptr = _contentId) + { + return new Span(ptr, 0x30); + } + } + } + public Span EncKey1 + { + get + { + fixed (byte* ptr = _encKey1) + { + return new Span(ptr, 0x10); + } + } + } + public Span EncKey2 + { + get + { + fixed (byte* ptr = _encKey2) + { + return new Span(ptr, 0x10); + } + } + } + public long StartTime => _startTime; + public long EndTime => _endTime; + + public Span EcdsaSig + { + get + { + fixed (byte* ptr = _ecdsaSig) + { + return new Span(ptr, 0x28); + } + } + } + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct Act + { + private short _actType; + private short _versionFlag; + private int _version; + private fixed byte _accountId[8]; + private fixed byte _primKeyTable[0x800]; + private fixed byte _unk1[0x40]; + private fixed byte _openPsId[0x10]; + private fixed byte _unk2[0x10]; + private fixed byte _unk4[0x10]; + private fixed byte _secondTable[0x650]; + private fixed byte _rsaSig[0x100]; + private fixed byte _unkSig[0x40]; + private fixed byte _ecdsaSig[0x28]; + public short ActType => _actType; + public short VersionFlag => _versionFlag; + public int Version => _version; + public Span AccountId + { + get + { + fixed (byte* ptr = _accountId) + { + return new Span(ptr, 8); + } + } + } + public Span PrimKeyTable + { + get + { + fixed (byte* ptr = _primKeyTable) + { + return new Span(ptr, 0x800); + } + } + } + public Span Unk1 + { + get + { + fixed (byte* ptr = _unk1) + { + return new Span(ptr, 0x40); + } + } + } + public Span OpenPsId + { + get + { + fixed (byte* ptr = _openPsId) + { + return new Span(ptr, 0x10); + } + } + } + public Span Unk2 + { + get + { + fixed (byte* ptr = _unk2) + { + return new Span(ptr, 0x10); + } + } + } + public Span Unk4 + { + get + { + fixed (byte* ptr = _unk4) + { + return new Span(ptr, 0x10); + } + } + } + public Span SecondTable + { + get + { + fixed (byte* ptr = _secondTable) + { + return new Span(ptr, 0x650); + } + } + } + public Span RsaSig + { + get + { + fixed (byte* ptr = _rsaSig) + { + return new Span(ptr, 0x100); + } + } + } + public Span UnkSig + { + get + { + fixed (byte* ptr = _unkSig) + { + return new Span(ptr, 0x40); + } + } + } + public Span EcdsaSig + { + get + { + fixed (byte* ptr = _ecdsaSig) + { + return new Span(ptr, 0x28); + } + } + } + + } + public static int sceNpDrmTransformVersionKey(Span versionKey, int srcKeyType, int dstKeyType) + { + // reverse the previous "GenVersionKey" step .. + int ret = ReverseGenVersionKey(versionKey, srcKeyType); + if (ret >= 0) + ret = GenVersionKey(versionKey, dstKeyType); // generate a new version key of this type + return ret; + } + + public static int sceNpDrmGetIDps(Span idps) + { + if (_psId != null && idps != null) + { + _psId.CopyTo(idps); + return 0; + } + return -0x7faaf6ff; + } + + public static int GetActKey(Span key, ReadOnlySpan keyTable, int count) + { + Span idps = stackalloc byte[16]; + Span decKey = stackalloc byte[16]; + int ret = sceNpDrmGetIDps(idps); + if (ret > -1) + { + ret = AesHelper.AesEncrypt(KeyVault.drmActdatKey, decKey, idps); + if (ret == 16) + { + for (int i = 0; i < count; i++) + { + ret = AesHelper.AesDecrypt(keyTable[(i * 0x10)..], key[(i * 0x10)..], decKey); + if (ret != 16) + { + ret = unchecked((int)0x80550902); + break; + } + } + ret = 0; + } + } + idps.Clear(); + decKey.Clear(); + return ret; + } + + private static int GetFreeVersionKey(Span versionKey, ReadOnlySpan rifBuf) + { + return -1; + } + + private static int GetLicenseVersionKey(Span versionKey, ReadOnlySpan actBuf, ReadOnlySpan rifBuf) + { + Span buf1 = stackalloc byte[16]; + Span buf2 = stackalloc byte[16]; + int ret = sceNpDrmVerifyAct(actBuf); + if (ret > -1) + { + ret = sceNpDrmVerifyRif(rifBuf); + if (ret > -1) + { + var act = MemoryMarshal.AsRef(actBuf); + var rif = MemoryMarshal.AsRef(rifBuf); + if (!act.AccountId.SequenceEqual(rif.AccountId)) + { + return -0x7faaf6fb; + } + if (((act.ActType & 0xff) << 8 | act.ActType >> 8) < ((rif.Version & 0xff) << 8 | rif.Version >> 9)) + { + return -0x7faaf6ef; + } + AesHelper.AesDecrypt(rif.EncKey1, buf1, KeyVault.drmRifKey); + int keyIdx = MemoryMarshal.Read(buf1[12..]); + keyIdx >>= 0x18; + if (keyIdx >= 0x80) + { + return -0x7faaf6fe; + } + ret = GetActKey(buf2, act.PrimKeyTable[(keyIdx * 0x10)..], 1); + if (ret > -1) + { + ret = AesHelper.AesDecrypt(rif.EncKey2, versionKey, buf2); + if (ret != 16) + { + ret = -0x7faaf6fe; + } + } + } + } + buf1.Clear(); + buf2.Clear(); + return ret; + } + + private static int CheckRifExpress(ReadOnlySpan rifBuf) + { + // TODO + return 0; + } + + + private static int ReverseGenVersionKey(Span versionkey, int type) + { + type &= 0xffffff; + int ret = 0; + if (type != 0) + { + ret = unchecked((int)0x80550901); + if (type < 4) + { + ret = AesHelper.AesDecrypt(versionkey, versionkey, KeyVault.drmVersionKeyKey.AsSpan().Slice(type * 0x10, 0x10)); + ret = ret == 16 ? 0 : unchecked((int)0x80550902); + } + } + return ret; + } + private static int GenVersionKey(Span versionKey, int type) + { + type &= 0xffffff; + int ret = 0; + if (type != 0) + { + ret = unchecked((int)0x80550901); + if (type < 4) + { + ret = AesHelper.AesEncrypt(versionKey, versionKey, KeyVault.drmVersionKeyKey.AsSpan().Slice(type * 0x10, 0x10)); + ret = ret == 16 ? 0 : unchecked((int)0x80550902); + } + } + return ret; + } + + public static int sceNpDrmGetVersionKey(Span versionKey, ReadOnlySpan actBuf, ReadOnlySpan rifBuf, int type) + { + int ret = -0x7faaf6ff; + if (versionKey != null && rifBuf != null) + { + var rif = MemoryMarshal.AsRef(rifBuf); + if (rif.DrmType == 0x300000) + { + ret = GetFreeVersionKey(versionKey, rifBuf); + } + else + { + if (actBuf == null) + { + return ret; + } + ret = GetLicenseVersionKey(versionKey, actBuf, rifBuf); + } + if (ret > -1) + { + ret = CheckRifExpress(rifBuf); + if (ret > -1) + { + ret = GenVersionKey(versionKey, type); + } + } + } + return ret; + } + + public static int sceNpDrmGetFixedKey(Span fixedKey, ReadOnlySpan contentId, int type) + { + Span buf = stackalloc byte[0x30]; + Span mkey = stackalloc byte[48]; + int ret = -0x7faaf6ff; + if ((type & 0x1000000) != 0) + { + contentId[..0x30].CopyTo(buf); + ret = AMCTRL.sceDrmBBMacInit(mkey, 1); + if (ret == 0) + { + ret = AMCTRL.sceDrmBBMacUpdate(mkey, buf, 0x30); + if (ret == 0) + { + ret = AMCTRL.sceDrmBBMacFinal(mkey, fixedKey, KeyVault.DrmFixedKey); + if (ret == 0) + { + ret = GenVersionKey(fixedKey, (int)(type & 0xfeffffff)); + } + else + { + ret = -0x7faaf6fe; + } + } + } + } + return ret; + } + + public static int sceNpDrmGetContentKey(Span contentKey, ReadOnlySpan actBuf, ReadOnlySpan rifBuf) => sceNpDrmGetVersionKey(contentKey, actBuf, rifBuf, 0); + + public static int sceNpDrmVerifyAct(ReadOnlySpan actBuf) + { + int ret = -0x7faaf6ff; + if (actBuf != null) + { + ret = -0x7faaf6fa; + var act = MemoryMarshal.AsRef(actBuf); + if (((act.VersionFlag & 0xFF) << 8 | act.VersionFlag >> 8) < 2) + { + if (((act.ActType & 0xFF) << 8 | act.ActType >> 8) < 2) + { + ret = VerifySig(act.EcdsaSig, KeyVault.drmActRifSig, actBuf, 0x1010); + } + } + } + return ret; + } + + private static int VerifySig(ReadOnlySpan sig, ReadOnlySpan pubKey, ReadOnlySpan data, int dataSize) + { + int ret; + Span digest = stackalloc byte[32]; + if (dataSize < 0x801) + { + ret = SceDdrdb.sceDdrdbHash(data, dataSize, digest); + } + else + { + ret = (SHA1.HashData(data[..dataSize], digest) > 0 ? 0 : -1); + } + if (ret > -1) + { + ret = SceDdrdb.sceDdrdbSigvry(pubKey, digest, sig); + } + return ret; + } + + private static int FillFuseId(Span fuseId) + { + if (_fuseId != 0) + { + uint heigh = (uint)((_fuseId >> 32) & 0xffffffff); + uint low = (uint)(_fuseId & 0xffffffff); + fuseId[0] = BinaryPrimitives.ReverseEndianness(heigh); + fuseId[1] = BinaryPrimitives.ReverseEndianness(low); + } + return -1; + } + + private static int VerifyRif(ReadOnlySpan rifBuf) + { + int ret = -0x7faaf6ff; + if (rifBuf != null) + { + ret = -0x7faaf6fa; + var rif = MemoryMarshal.AsRef(rifBuf); + if (((rif.VersionFlag & 0xff) << 8 | rif.VersionFlag >> 8) < 3) + { + if (((rif.Version & 0xff) << 8 | rif.Version >> 8) < 2) + { + int ret2; + if ((rif.DrmType & 0x10000) == 0) + { + ret = VerifySig(rif.EcdsaSig, KeyVault.drmActRifSig, rifBuf, 0x70); + ret2 = -0x7faaf6fc; + } + else + { + Span buffer = stackalloc byte[0x90]; + rifBuf[..0x70].CopyTo(buffer); + if (_psId == null) + { + return ret; + } + ret = sceNpDrmGetIDps(buffer[0x70..]); + if (ret < 0) + { + return ret; + } + Span fuseId = MemoryMarshal.Cast(buffer[0x80..]); + ret = FillFuseId(fuseId); + if (ret < 0) + { + return ret; + } + ret = VerifySig(rif.EcdsaSig, KeyVault.drmActRifSig, buffer, 0x90); + ret2 = -0x7faaf6e8; + } + if (ret != 0) + { + ret = ret2; + } + } + } + } + return ret; + } + + public static int sceNpDrmVerifyRif(ReadOnlySpan rifBuf) + { + int ret = VerifyRif(rifBuf); + if (ret > -1) + { + var rif = MemoryMarshal.AsRef(rifBuf); + if (rif.DrmType == 0x3000000) + { + ret = -1; // TODO + } + } + return ret; + } + + public static int KsceNpDrmEbootSigGenMultiDisc(string fileName, ReadOnlySpan sceDiscInfo, + Span ebootSig, int swVer) + { + return SceNpDrmEbootSigGenMultiDisc(fileName, sceDiscInfo, ebootSig, swVer, _memory.Span, BLK_SIZE); + } + public static int KsceNpDrmEbootSigGenPs1(Stream file, Span ebootSig, int swVer) + { + return SceNpDrmEbootSigGen(file, 3, ebootSig, swVer, _memory.Span, BLK_SIZE); + } + + public static int KsceNpDrmEbootSigGenPsp(Stream file, Span ebootSig, int swVer) + { + return SceNpDrmEbootSigGen(file, 2, ebootSig, swVer, _memory.Span, BLK_SIZE); + } + + public static int KsceNpDrmPspEbootSigGen(Stream file, Span ebootSig) + { + return SceNpDrmPspEbootSigGen(file, ebootSig, _memory.Span, BLK_SIZE); + } + + public static int KsceNpDrmEbootSigGenPs1(string fileName, Span ebootSig, int swVer) + { + return SceNpDrmEbootSigGen(fileName, 3, ebootSig, swVer, _memory.Span, BLK_SIZE); + } + + public static int KsceNpDrmEbootSigGenPsp(string fileName, Span ebootSig, int swVer) + { + return SceNpDrmEbootSigGen(fileName, 2, ebootSig, swVer, _memory.Span, BLK_SIZE); + } + + public static int KsceNpDrmPspEbootSigGen(string fileName, Span ebootSig) + { + return SceNpDrmPspEbootSigGen(fileName, ebootSig, _memory.Span, BLK_SIZE); + } + + private static int SceNpDrmEbootSigGenMultiDisc(string fileName, ReadOnlySpan sceDiskInfo, + Span ebootSig, int swVer, Span buffer, int blockSize) + { + Span pbpHdrDigest = stackalloc byte[32]; + Span discsDigest = stackalloc byte[32]; + Span ebootSigtmp = stackalloc byte[512]; + ref var sceEbootPbp = ref MemoryMarshal.AsRef(ebootSigtmp); + if ((blockSize & 0x3F) != 0) + { + blockSize &= unchecked((int)0xFFFFFFC0); + } + + if (sceDiskInfo == null || string.IsNullOrWhiteSpace(fileName) || buffer == null || ebootSig == null || + blockSize < 0x400) + { + return unchecked((int)0x80870001); + } + + Span secureTick = stackalloc byte[8] { 0xD4, 0x7A, 0x2C, 0x13, 0x64, 0x59, 0xE2, 0x00 }; + //RandomNumberGenerator.Fill(secureTick); + + ebootSig.Fill(0); + sceEbootPbp.SwVer = swVer; + sceEbootPbp.Aid = Aid; + sceEbootPbp.SecureTick = MemoryMarshal.AsRef(secureTick); + + var sha224 = SHA224.Create(); + var hash = sha224.ComputeHash(sceDiskInfo[..200].ToArray()); + var ret = SceSblGcAuthMgrDrmBBForDriver_4B506BE7(hash, sceDiskInfo[200..], 1000); + if (ret != 0) + { + return ret; + } + + var discInfo = MemoryMarshal.AsRef(sceDiskInfo); + ret = unchecked((int)0x80870005); + if (discInfo.DiscCount > 6) + { + return ret; + } + var fi = new FileInfo(fileName); + if (!fi.Exists) + { + return -1; + } + + if (fi.Length != discInfo.FileSize) + { + return ret; + } + + ret = unchecked((int)0x80870001); + if (discInfo.DiscCount < 7) + { + if (fi.Length < discInfo.Offsets[0]) + { + return ret; + } + if (discInfo.DiscCount > 1 && fi.Length < discInfo.Offsets[1]) + { + return ret; + } + if (discInfo.DiscCount > 2 && fi.Length < discInfo.Offsets[2]) + { + return ret; + } + if (discInfo.DiscCount > 3 && fi.Length < discInfo.Offsets[3]) + { + return ret; + } + if (discInfo.DiscCount > 4 && fi.Length < discInfo.Offsets[4]) + { + return ret; + } + if (discInfo.DiscCount > 5 && fi.Length < discInfo.Offsets[5]) + { + return ret; + } + + using var stream = fi.OpenRead(); + ret = SceMultiDiscDigest(stream, fi.Length, discInfo.DiscCount, discInfo.Offsets, pbpHdrDigest, discsDigest, buffer, blockSize); + if (discInfo.DiscCount >= 0) + { + stream.Close(); + ret = SceSblGcAuthMgrDrmBBForDriver_4B506BE7(discsDigest, discInfo.DiscsSig, 1000); + if (ret != 0) + { + return ret; + } + + sceEbootPbp.PbpSize = fi.Length; + sceEbootPbp.Magic = 0x47495349544C554D; + sceEbootPbp.KeyType = 1; + sceEbootPbp.Type = 4; + discInfo.Id.CopyTo(sceEbootPbp.ContentId); + sceEbootPbp.DiscCount = discInfo.DiscCount; + discInfo.Offsets.CopyTo(sceEbootPbp.DiscOffsets); + ret = SceSblGcAuthMgrDrmBBForDriver_050DC6DF(pbpHdrDigest, sceEbootPbp.PbpHdrSig, 1); + if (ret != 0) + { + return ret; + } + discInfo.DiscsSig.CopyTo(sceEbootPbp.NpUmdImgSig); + var ebootsigDigst = sha224.ComputeHash(ebootSigtmp[..0x1C8].ToArray()); + ret = SceSblGcAuthMgrDrmBBForDriver_050DC6DF(ebootsigDigst, sceEbootPbp.Sig, 1); + if (ret != 0) + { + return ret; + } + ebootSigtmp.CopyTo(ebootSig); + ret = 0; + } + } + return ret; + } + + private static int SceMultiDiscDigest(Stream stream, long fileSize, int diskCount, + ReadOnlySpan diskOffsets, Span pbpHdrDigest, Span dataDigest, Span buffer, + int blockSize) + { + var sha224 = SHA224.Create(); + var ret = unchecked((int)0x80870005); + stream.Seek(0, SeekOrigin.Begin); + buffer = buffer[..blockSize]; + var readSize = stream.Read(buffer); + if (readSize < 0x28) + { + return ret; + } + var pbpHeader = MemoryMarshal.AsRef(buffer); + if (pbpHeader.Sig != 0x50425000) + { + return ret; + } + + var tmp = readSize; + if (pbpHeader.DataPsarOff < readSize) + { + tmp = pbpHeader.DataPsarOff; + } + + var paramReadSize = pbpHeader.Icon0Off; + if (paramReadSize > 0x400) + { + paramReadSize = 0x400; + } + + if (tmp < paramReadSize) + { + return ret; + } + + sha224.TransformFinalBlock(buffer.ToArray(), 0, paramReadSize); + sha224.Hash.CopyTo(pbpHdrDigest); + + sha224.Initialize(); + sha224.TransformBlock(buffer.ToArray(), 0, paramReadSize, null, 0); + + long end = pbpHeader.DataPsarOff + 0xC0000; + if (diskOffsets[0] >= pbpHeader.DataPsarOff && diskOffsets[0] < end) + { + end = diskOffsets[0]; + } + + long start = pbpHeader.DataPsarOff; + stream.Seek(start, SeekOrigin.Begin); + for (; start < end; start += readSize) + { + var toRead = (int)(end - start); + if (toRead > blockSize) + { + toRead = blockSize; + } + + readSize = stream.Read(buffer[..toRead]); + if (readSize == 0) + { + return -1; + } + sha224.TransformBlock(buffer.ToArray(), 0, readSize, null, 0); + } + + if (diskCount != 0) + { + var start1 = diskOffsets[0]; + end = diskOffsets[0] + 0xC0000; + if (end >= 0) + { + var discNo = 0; + var idx = 5; + while (true) + { + if (fileSize < end) + { + end = fileSize; + } + + if (++discNo < diskCount) + { + start = diskOffsets[idx - 4]; + if (start >= start1 && start < end) + { + end = start; + } + } + + if (start1 < end) + { + stream.Seek(start1, SeekOrigin.Begin); + while (true) + { + var toRead = (int)(end - start1); + if (toRead > blockSize) + { + toRead = blockSize; + } + + readSize = stream.Read(buffer[..toRead]); + if (readSize == 0) + { + return -1; + } + sha224.TransformBlock(buffer.ToArray(), 0, readSize, null, 0); + start1 += toRead; + if (start1 >= end) + { + break; + } + } + } + + if (discNo == diskCount) + { + break; + } + start1 = diskOffsets[idx - 4]; + idx++; + end = start1 + 0xC0000; + + } + } + } + sha224.TransformFinalBlock(buffer.ToArray(), 0, 0); + sha224.Hash.CopyTo(dataDigest); + + stream.Seek(pbpHeader.DataPsarOff, SeekOrigin.Begin); + readSize = stream.Read(buffer[..0x100]); + if (readSize == 0x100) + { + ret = 0; + } + else + { + ret = unchecked((int)0x80870005); + } + + return ret; + } + + private static int SceNpDrmEbootSigGen(string fileName, int type, Span ebootSig, int swVer, Span buffer, int blockSize) + { + if (string.IsNullOrWhiteSpace(fileName)) return -0x7f78ffff; + var fi = new FileInfo(fileName); + if (!fi.Exists) + { + return -1; + } + using (FileStream fstream = fi.OpenRead()) + { + return SceNpDrmEbootSigGen(fstream, type, ebootSig, swVer, buffer, blockSize); + } + + } + private static int SceNpDrmEbootSigGen(Stream ebootStream, int type, Span ebootSig, int swVer, Span buffer, int blockSize) + { + Span pbpHdrDigest = stackalloc byte[32]; + Span npUmdImgDigest = stackalloc byte[32]; + Span ebootSigtmp = stackalloc byte[512]; + ref var sceEbootPbp = ref MemoryMarshal.AsRef(ebootSigtmp); + if ((blockSize & 0x3F) != 0) + { + blockSize &= unchecked((int)0xFFFFFFC0); + } + + if (ebootStream == null || buffer == null || ebootSig == null || blockSize < 0x400 || type > 3) + { + return -0x7f78ffff; + } + + Span secureTick = BitConverter.GetBytes(SceRtc.ksceRtcGetCurrentSecureTick()); + + ebootSig.Fill(0); + sceEbootPbp.SwVer = swVer; + sceEbootPbp.Aid = Aid; + sceEbootPbp.SecureTick = MemoryMarshal.AsRef(secureTick); + + long flen = ebootStream.Length; + int ret = SceEbootPbpDigest(ebootStream, flen, pbpHdrDigest, npUmdImgDigest, buffer, blockSize); + if (ret < 0) + { + return ret; + } + + sceEbootPbp.KeyType = 1; + sceEbootPbp.PbpSize = flen; + sceEbootPbp.Type = type; + var psarSig = Encoding.ASCII.GetString(buffer[..8]); + if (type == 3) + { + if (psarSig != "PSISOIMG" && psarSig != "PSTITLEI") + { + return -0x7f78fffb; + } + sceEbootPbp.Magic = 0x474953315350504E; + } + else + { + if (psarSig != "NPUMDIMG") + { + return -0x7f78fffb; + } + + sceEbootPbp.Magic = 0x474953444D55504E; + buffer.Slice(0x10, 0x30).CopyTo(sceEbootPbp.ContentId); + } + + ret = SceSblGcAuthMgrDrmBBForDriver_050DC6DF(pbpHdrDigest, sceEbootPbp.PbpHdrSig, 1); + if (ret < 0) + { + return ret; + } + + ret = SceSblGcAuthMgrDrmBBForDriver_050DC6DF(npUmdImgDigest, sceEbootPbp.NpUmdImgSig, 1); + if (ret < 0) + { + return ret; + } + + var sha224 = SHA224.Create(); + var ebootsigDigst = sha224.ComputeHash(ebootSigtmp[..0x1C8].ToArray()); + ret = SceSblGcAuthMgrDrmBBForDriver_050DC6DF(ebootsigDigst, sceEbootPbp.Sig, 1); + if (ret < 0) + { + return ret; + } + ebootSigtmp.CopyTo(ebootSig); + ret = 0; + return ret; + } + + private static int SceEbootPbpDigest(Stream stream, long fileSize, Span pbpHdrDigest, + Span npUmdImgDigest, Span buffer, int blockSize) + { + var sha224 = SHA224.Create(); + var ret = unchecked((int)0x80870005); + stream.Seek(0, SeekOrigin.Begin); + buffer = buffer[..blockSize]; + var readSize = stream.Read(buffer); + if (readSize < 0x28) + { + return ret; + } + + var pbpHeader = MemoryMarshal.AsRef(buffer); + if (fileSize < pbpHeader.DataPsarOff + 0xFF || pbpHeader.Sig != 0x50425000) + { + return ret; + } + + var tmp = readSize; + if (pbpHeader.DataPsarOff < readSize) + { + tmp = pbpHeader.DataPsarOff; + } + + var paramReadSize = pbpHeader.Icon0Off; + if (paramReadSize > 0x400) + { + paramReadSize = 0x400; + } + + if (tmp < paramReadSize) + { + return ret; + } + + sha224.TransformFinalBlock(buffer.ToArray(), 0, paramReadSize); + sha224.Hash.CopyTo(pbpHdrDigest); + + sha224.Initialize(); + + var alignedFileSize = (pbpHeader.DataPsarOff + 0x1C0000 + 64 - 1) & ~(64 - 1); + if (alignedFileSize < fileSize) + { + fileSize = alignedFileSize; + } + + var fixsize2 = fileSize; + if (pbpHeader.DataPsarOff + 0x1C0000 < fileSize) + { + fixsize2 = pbpHeader.DataPsarOff + 0x1C0000; + } + + if (pbpHeader.DataPsarOff < fixsize2) + { + var offset = pbpHeader.DataPsarOff; + stream.Seek(offset, SeekOrigin.Begin); + while (true) + { + readSize = stream.Read(buffer); + var bsize = readSize; + if (readSize <= 0) + { + ret = unchecked((int)0x80870002); + return ret; + } + + if (fixsize2 < offset + readSize) + { + bsize = (int)(fixsize2 - offset); + } + sha224.TransformBlock(buffer.ToArray(), 0, bsize, null, 0); + + offset += readSize; + if (offset >= fixsize2) + { + break; + } + } + sha224.TransformFinalBlock(buffer.ToArray(), 0, 0); + sha224.Hash.CopyTo(npUmdImgDigest); + stream.Seek(pbpHeader.DataPsarOff, SeekOrigin.Begin); + readSize = stream.Read(buffer[..0x100]); + if (readSize == 0x100) + { + ret = 0; + } + else + { + ret = unchecked((int)0x80870005); + } + } + + + return ret; + } + + private static int SceNpDrmPspEbootSigGen(string fileName, Span ebootSig, Span buffer, int blockSize) + { + if (string.IsNullOrWhiteSpace(fileName)) + return -0x7f78ffff; + + var fi = new FileInfo(fileName); + if (!fi.Exists) + { + return -1; + } + using (FileStream fs = fi.OpenRead()) + { + return SceNpDrmPspEbootSigGen(fs, ebootSig, buffer, blockSize); + } + } + + private static int SceNpDrmPspEbootSigGen(Stream ebootStream, Span ebootSig, Span buffer, int blockSize) + { + Span pbpHdrDigest = stackalloc byte[32]; + Span npUmdImgDigest = stackalloc byte[32]; + Span ebootSigtmp = stackalloc byte[0x100]; + ref var sceEbootPbp = ref MemoryMarshal.AsRef(ebootSigtmp); + if ((blockSize & 0x3F) != 0) + { + blockSize &= unchecked((int)0xFFFFFFC0); + } + + if (ebootStream == null || buffer == null || ebootSig == null || blockSize < 0x400) + { + return -0x7f78ffff; + } + + long fileSize = ebootStream.Length; + int ret = SceEbootPbpDigest(ebootStream, fileSize, pbpHdrDigest, npUmdImgDigest, buffer, blockSize); + if (ret < 0) + { + return ret; + } + + if (Encoding.ASCII.GetString(buffer[..8]) != "NPUMDIMG") + { + return -0x7f78fffb; + } + buffer[..0x40].CopyTo(ebootSigtmp); + sceEbootPbp.Type = 0; + sceEbootPbp.Magic = 0x474953444D55504E; + + ret = SceSblGcAuthMgrDrmBBForDriver_050DC6DF(pbpHdrDigest, sceEbootPbp.PbpHdrSig, 1); + if (ret < 0) + { + return ret; + } + + ret = SceSblGcAuthMgrDrmBBForDriver_050DC6DF(npUmdImgDigest, sceEbootPbp.NpUmdImgSig, 1); + if (ret < 0) + { + return ret; + } + + var sha224 = SHA224.Create(); + var ebootsigDigst = sha224.ComputeHash(ebootSigtmp[..0xC8].ToArray()); + ret = SceSblGcAuthMgrDrmBBForDriver_050DC6DF(ebootsigDigst, sceEbootPbp.Sig, 1); + if (ret < 0) + { + return ret; + } + ebootSigtmp.CopyTo(ebootSig); + ret = 0; + + return ret; + } + + private static int SceSblGcAuthMgrDrmBBForDriver_050DC6DF(ReadOnlySpan digest, Span sig, int type) + { + var curve = ECDsaHelper.SetCurve(KeyVault.Eboot_p, KeyVault.Eboot_a, KeyVault.Eboot_b, KeyVault.Eboot_N, KeyVault.Eboot_Gx, + KeyVault.Eboot_Gy); + using var ecdsa = ECDsaHelper.Create(curve, + KeyVault.Eboot_priv[type], + KeyVault.Eboot_pubx[type], + KeyVault.Eboot_puby[type], true); + var signature = ecdsa.SignHash(digest.ToArray()); + signature.CopyTo(sig); + return 0; + } + + private static int SceSblGcAuthMgrDrmBBForDriver_4B506BE7(ReadOnlySpan digest, ReadOnlySpan sig, int keyType) + { + byte[] pubx; + byte[] puby; + switch (keyType) + { + case 1: + pubx = KeyVault.VitaKirk18PubKey1x; + puby = KeyVault.VitaKirk18PubKey1y; + break; + case 0: + pubx = KeyVault.VitaKirk18PubKey0x; + puby = KeyVault.VitaKirk18PubKey0y; + break; + case 1000: + pubx = KeyVault.VitaKirk18PubKey1000x; + puby = KeyVault.VitaKirk18PubKey1000y; + break; + default: + return unchecked((int)0x808a040a); + } + var curve = ECDsaHelper.SetCurve(KeyVault.Eboot_p, KeyVault.Eboot_a, KeyVault.Eboot_b, KeyVault.Eboot_N, KeyVault.Eboot_Gx, + KeyVault.Eboot_Gy); + using var ecdsa = ECDsaHelper.Create(curve, pubx, puby); + var verify = ecdsa.VerifyHash(digest.ToArray(), sig.ToArray()); + + return verify ? 0 : -1; + } + } +} diff --git a/PspCrypto/SceRtc.cs b/PspCrypto/SceRtc.cs new file mode 100644 index 0000000..cbbd4a9 --- /dev/null +++ b/PspCrypto/SceRtc.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PspCrypto +{ + public class SceRtc + { + public static ulong ksceRtcGetCurrentTick() + { + return ksceRtcGetCurrentSecureTick(); + } + + public static ulong ksceRtcGetCurrentNetworkTick() + { + return ksceRtcGetCurrentSecureTick(); + } + public static ulong ksceRtcGetCurrentSecureTick() + { + DateTime epoch = new DateTime(1, 1, 1, 0, 0, 0); + DateTime now = DateTime.UtcNow; + TimeSpan ts = now.Subtract(epoch); + return Convert.ToUInt64(Math.Floor(ts.TotalMilliseconds)) * 1000; + } + } +} diff --git a/PspCrypto/Security/Cryptography/ECDsaManaged.cs b/PspCrypto/Security/Cryptography/ECDsaManaged.cs new file mode 100644 index 0000000..a8a2b6e --- /dev/null +++ b/PspCrypto/Security/Cryptography/ECDsaManaged.cs @@ -0,0 +1,170 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; +using System; + +namespace PspCrypto.Security.Cryptography +{ + internal class ECDsaManaged : System.Security.Cryptography.ECDsa + { + private ECKeyParameters _ecKeyParameters; + private readonly bool _ebootPbp; + private readonly int _type; + + public ECDsaManaged() + { + + } + + public ECDsaManaged(System.Security.Cryptography.ECParameters parameters, bool ebootPbp, int type) + { + _ebootPbp = ebootPbp; + _type = type; + var gx = new BigInteger(1, parameters.Curve.G.X); + var gy = new BigInteger(1, parameters.Curve.G.Y); + var curve = ConvertECCurve(parameters.Curve); + var g = curve.CreatePoint(gx, gy); + var domainParameters = new ECDomainParameters(curve, g, curve.Order); + if (parameters.D != null) + { + var privateKey = new BigInteger(1, parameters.D); + _ecKeyParameters = new ECPrivateKeyParameters(privateKey, domainParameters); + } + else if (parameters.Q.X != null && parameters.Q.Y != null) + { + var publicKey = curve.CreatePoint(new BigInteger(1, parameters.Q.X), new BigInteger(1, parameters.Q.Y)); + _ecKeyParameters = new ECPublicKeyParameters(publicKey, domainParameters); + } + else + { + throw new ArgumentException("invalid parameters", nameof(parameters)); + } + } + + public override byte[] SignHash(byte[] hash) + { + if (_ecKeyParameters is not ECPrivateKeyParameters) + { + throw new ArgumentException("key is not private Key"); + } + var signer = CreateSigner(); + signer.Init(true, _ecKeyParameters); + signer.BlockUpdate(hash); + return signer.GenerateSignature(); + } + + public override bool VerifyHash(byte[] hash, byte[] signature) + { + var signer = CreateSigner(); + if (_ecKeyParameters is ECPrivateKeyParameters ecPrivateKeyParameters) + { + var publicKey = new ECPublicKeyParameters( + ecPrivateKeyParameters.Parameters.G.Multiply(ecPrivateKeyParameters.D), + ecPrivateKeyParameters.Parameters); + signer.Init(false, publicKey); + } + else + { + signer.Init(false, _ecKeyParameters); + } + signer.BlockUpdate(hash); + return signer.VerifySignature(signature); + } + + protected override byte[] HashData(byte[] data, int offset, int count, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) + { + var dataSpan = new ReadOnlySpan(data, offset, count); + if (hashAlgorithm == System.Security.Cryptography.HashAlgorithmName.SHA256) + { + return System.Security.Cryptography.SHA256.HashData(dataSpan); + } + else if (hashAlgorithm == System.Security.Cryptography.HashAlgorithmName.SHA1) + { + return System.Security.Cryptography.SHA1.HashData(dataSpan); + } + else + { + throw new NotSupportedException($"{hashAlgorithm} not supported"); + } + } + + private ISigner CreateSigner() + { + IDigest digest = DigestUtilities.GetDigest("NONE"); + IDsa dsa = _ebootPbp ? new ECDsaSigner(new EbootPbpKCalculator(_type)) : new ECDsaSigner(); + var signer = new DsaDigestSigner(dsa, digest, PlainDsaEncoding.Instance); + return signer; + } + + private FpCurve _fpCurve; + + public override void GenerateKey(System.Security.Cryptography.ECCurve curve) + { + _fpCurve = ConvertECCurve(curve); + var gx = new BigInteger(1, curve.G.X); + var gy = new BigInteger(1, curve.G.Y); + var g = _fpCurve.CreatePoint(gx, gy); + var domainParameters = new ECDomainParameters(_fpCurve, g, _fpCurve.Order); + var gen = new ECKeyPairGenerator(); + gen.Init(new ECKeyGenerationParameters(domainParameters, new SecureRandom())); + var keyPair = gen.GenerateKeyPair(); + _ecKeyParameters = (ECKeyParameters)keyPair.Private; + } + + public override System.Security.Cryptography.ECParameters ExportExplicitParameters(bool includePrivateParameters) + { + var normalG = _ecKeyParameters.Parameters.G; + var curve = new System.Security.Cryptography.ECCurve + { + A = _fpCurve.A.ToBigInteger().ToByteArrayUnsigned(), + B = _fpCurve.B.ToBigInteger().ToByteArrayUnsigned(), + Prime = _fpCurve.Q.ToByteArrayUnsigned(), + Order = _fpCurve.Order.ToByteArrayUnsigned(), + Cofactor = _fpCurve.Cofactor.ToByteArrayUnsigned(), + G = new System.Security.Cryptography.ECPoint + { + X = normalG.AffineXCoord.ToBigInteger().ToByteArrayUnsigned(), + Y = normalG.AffineYCoord.ToBigInteger().ToByteArrayUnsigned() + } + }; + var parameters = new System.Security.Cryptography.ECParameters + { + Curve = curve + }; + if (includePrivateParameters && _ecKeyParameters is ECPrivateKeyParameters privateKeyParameters) + { + parameters.D = privateKeyParameters.D.ToByteArrayUnsigned(); + var publicKey = _ecKeyParameters.Parameters.G.Multiply(privateKeyParameters.D).Normalize(); + parameters.Q = new System.Security.Cryptography.ECPoint + { + X = publicKey.AffineXCoord.ToBigInteger().ToByteArrayUnsigned(), + Y = publicKey.AffineYCoord.ToBigInteger().ToByteArrayUnsigned() + }; + } + else if (_ecKeyParameters is ECPublicKeyParameters publicKeyParameters) + { + var publicKey = publicKeyParameters.Q.Normalize(); + parameters.Q = new System.Security.Cryptography.ECPoint + { + X = publicKey.AffineXCoord.ToBigInteger().ToByteArrayUnsigned(), + Y = publicKey.AffineYCoord.ToBigInteger().ToByteArrayUnsigned() + }; + } + return parameters; + } + + private static FpCurve ConvertECCurve(System.Security.Cryptography.ECCurve curve) + { + var p = new BigInteger(1, curve.Prime); + var a = new BigInteger(1, curve.A); + var b = new BigInteger(1, curve.B); + var n = new BigInteger(1, curve.Order); + var fpCurve = new FpCurve(p, a, b, n, BigInteger.One); + return fpCurve; + } + } +} diff --git a/PspCrypto/Security/Cryptography/EbootPbpKCalculator.cs b/PspCrypto/Security/Cryptography/EbootPbpKCalculator.cs new file mode 100644 index 0000000..e7918b3 --- /dev/null +++ b/PspCrypto/Security/Cryptography/EbootPbpKCalculator.cs @@ -0,0 +1,103 @@ +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using System; + +namespace PspCrypto.Security.Cryptography +{ + internal class EbootPbpKCalculator : IDsaKCalculator + { + private int _type; + + private BigInteger _n; + + public EbootPbpKCalculator(int type) + { + _type = type; + } + + public bool IsDeterministic => true; + + private readonly Memory _hash = new byte[0x40]; + + public void Init(BigInteger n, SecureRandom random) + { + throw new NotImplementedException(); + } + public void Init(BigInteger n, BigInteger d, byte[] message) + { + _n = n; + Span hmacIn = stackalloc byte[0x38]; + message[..0x1C].CopyTo(hmacIn); + KeyVault.Eboot_priv[_type].CopyTo(hmacIn[0x1C..]); + + var hmac = new HMac(new Sha256Digest()); + hmac.Init(new KeyParameter(KeyVault.Eboot_hmacKey)); + hmac.BlockUpdate(hmacIn); + var hmac_hash_iv = new byte[hmac.GetMacSize()]; + hmac.DoFinal(hmac_hash_iv); + + int ret; + do + { + ret = can_be_reversed_80C17A(message, 0x1c, hmac_hash_iv, _hash.Span); + if (ret != 0 || (ret = can_be_reversed_80C17A(message, 0x1c, hmac_hash_iv, _hash.Span[0x20..])) != 0) + { + throw new Exception(); + } + + } while (ret != 0); + } + + public BigInteger NextK() + { + var bn = new BigInteger(1, _hash.Span[..0x3c]); + var ret = bn.Mod(_n); + return ret; + } + + + private static int can_be_reversed_80C17A(Span src, int some_size, Span iv, + Span src_xored_digest) + { + Span src_xored = stackalloc byte[0x20]; + iv.CopyTo(src_xored); + + if (some_size > 0x20) + { + return 0x12; + } + + for (int i = 0; i < some_size; i++) + { + src_xored[i] ^= src[i]; + } + + using var sha256 = System.Security.Cryptography.SHA256.Create(); + var hash = sha256.ComputeHash(src_xored.ToArray()); + hash.CopyTo(src_xored_digest); + + for (int i = 0; i < 0x20; i++) + { + iv[i] ^= src_xored_digest[i]; + } + + for (int i = 0; i < 0x20; i++) + { + if (iv[i] != 0xFF) + { + iv[i] += 1; + break; + } + + iv[i] = 0; + } + + return 0; + } + + } +} diff --git a/PspCrypto/Security/Cryptography/HMACCommon.cs b/PspCrypto/Security/Cryptography/HMACCommon.cs new file mode 100644 index 0000000..6fb21e2 --- /dev/null +++ b/PspCrypto/Security/Cryptography/HMACCommon.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace PspCrypto.Security.Cryptography +{ + // + // This class provides the common functionality for HMACSHA1, HMACSHA256, HMACMD5, etc. + // Ideally, this would be encapsulated in a common base class but the preexisting contract + // locks these public classes into deriving directly from HMAC so we have to use encapsulation + // and delegation to HMACCommon instead. + // + // This wrapper adds the ability to change the Key on the fly for compat with the desktop. + // + internal sealed class HMACCommon + { + public HMACCommon(string hashAlgorithmId, byte[] key, int blockSize) : + this(hashAlgorithmId, (ReadOnlySpan)key, blockSize) + { + // If the key is smaller than the block size, the delegated ctor won't have initialized ActualKey, + // so set it here as would ChangeKey. + ActualKey ??= key; + } + + internal HMACCommon(string hashAlgorithmId, ReadOnlySpan key, int blockSize) + { + Debug.Assert(!string.IsNullOrEmpty(hashAlgorithmId)); + Debug.Assert(blockSize > 0 || blockSize == -1); + + _hashAlgorithmId = hashAlgorithmId; + _blockSize = blockSize; + + // note: will not set ActualKey if key size is smaller or equal than blockSize + // this is to avoid extra allocation. ActualKey can still be used if key is generated. + // Otherwise the ReadOnlySpan overload would actually be slower than byte array overload. + ActualKey = ChangeKeyImpl(key); + } + + public int HashSizeInBits => _hMacProvider.HashSizeInBytes * 8; + public int HashSizeInBytes => _hMacProvider.HashSizeInBytes; + + public void ChangeKey(byte[] key) + { + ActualKey = ChangeKeyImpl(key) ?? key; + } + + [MemberNotNull(nameof(_hMacProvider))] + private byte[] ChangeKeyImpl(ReadOnlySpan key) + { + byte[] modifiedKey = null; + + // If _blockSize is -1 the key isn't going to be extractable by the object holder, + // so there's no point in recalculating it in managed code. + if (key.Length > _blockSize && _blockSize > 0) + { + // Perform RFC 2104, section 2 key adjustment. + modifiedKey = _hashAlgorithmId switch + { + "SHA224" => SHA224.HashData(key), + _ => throw new CryptographicException(string.Format("'{0}' is not a known hash algorithm.", _hashAlgorithmId)), + }; + } + + HashProvider oldHashProvider = _hMacProvider; + _hMacProvider = null!; + oldHashProvider?.Dispose(true); + _hMacProvider = HashProviderDispenser.CreateMacProvider(_hashAlgorithmId, key); + + return modifiedKey; + } + + // The actual key used for hashing. This will not be the same as the original key passed to ChangeKey() if the original key exceeded the + // hash algorithm's block size. (See RFC 2104, section 2) + public byte[] ActualKey { get; private set; } + + // Adds new data to be hashed. This can be called repeatedly in order to hash data from noncontiguous sources. + public void AppendHashData(byte[] data, int offset, int count) => + _hMacProvider.AppendHashData(data, offset, count); + + public void AppendHashData(ReadOnlySpan source) => + _hMacProvider.AppendHashData(source); + + // Compute the hash based on the appended data and resets the HashProvider for more hashing. + public byte[] FinalizeHashAndReset() => + _hMacProvider.FinalizeHashAndReset(); + + public int FinalizeHashAndReset(Span destination) => + _hMacProvider.FinalizeHashAndReset(destination); + + public bool TryFinalizeHashAndReset(Span destination, out int bytesWritten) => + _hMacProvider.TryFinalizeHashAndReset(destination, out bytesWritten); + + public int GetCurrentHash(Span destination) => + _hMacProvider.GetCurrentHash(destination); + + public void Reset() => _hMacProvider.Reset(); + + public void Dispose(bool disposing) + { + if (disposing) + { + _hMacProvider?.Dispose(true); + _hMacProvider = null!; + } + } + + private readonly string _hashAlgorithmId; + private HashProvider _hMacProvider; + private readonly int _blockSize; + } +} diff --git a/PspCrypto/Security/Cryptography/HMACManagedHashProvider.cs b/PspCrypto/Security/Cryptography/HMACManagedHashProvider.cs new file mode 100644 index 0000000..79ed4bf --- /dev/null +++ b/PspCrypto/Security/Cryptography/HMACManagedHashProvider.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace PspCrypto.Security.Cryptography +{ + internal sealed class HMACManagedHashProvider : HashProvider + { + private bool _hashing; + private readonly int _blockSizeValue; + private readonly int _hashSizeValue; + + private readonly byte[] _key; + private readonly HashProvider _hash1; + private readonly HashProvider _hash2; + + public HMACManagedHashProvider(string hashAlgorithmId, ReadOnlySpan key) + { + _hash1 = HashProviderDispenser.CreateHashProvider(hashAlgorithmId); + _hash2 = HashProviderDispenser.CreateHashProvider(hashAlgorithmId); + + _blockSizeValue = 64; + _hashSizeValue = 224 / 8; + + _key = InitializeKey(key); + } + + private byte[] InitializeKey(ReadOnlySpan key) + { + if (key.Length > _blockSizeValue) + { + byte[] result = new byte[_hashSizeValue]; + _hash1.AppendHashData(key); + int written = _hash1.FinalizeHashAndReset(result); + Debug.Assert(written == result.Length); + + return result; + } + + return key.ToArray(); + } + + public override void AppendHashData(ReadOnlySpan data) + { + if (!_hashing) + { + AppendInnerBuffer(); + _hashing = true; + } + + _hash1.AppendHashData(data); + } + + public override int FinalizeHashAndReset(Span destination) + { + int written = GetCurrentHash(destination); + Reset(); + return written; + } + + public override int GetCurrentHash(Span destination) + { + if (!_hashing) + { + AppendInnerBuffer(); + _hashing = true; + } + + // finalize the original hash + Span hashValue1 = stackalloc byte[_hashSizeValue]; + int hash1Written = _hash1.GetCurrentHash(hashValue1); + Debug.Assert(hash1Written == hashValue1.Length); + + // write the outer array + AppendOuterBuffer(); + // write the inner hash and finalize the hash + _hash2.AppendHashData(hashValue1); + return _hash2.FinalizeHashAndReset(destination); + } + + private void AppendInnerBuffer() => AppendPaddingBuffer(0x36, _hash1); + private void AppendOuterBuffer() => AppendPaddingBuffer(0x5C, _hash2); + + private void AppendPaddingBuffer(byte paddingConstant, HashProvider hash) + { + Span paddingBuffer = stackalloc byte[_blockSizeValue]; + paddingBuffer.Fill(paddingConstant); + + for (int i = 0; i < _key.Length; i++) + { + paddingBuffer[i] ^= _key[i]; + } + + hash.AppendHashData(paddingBuffer); + CryptographicOperations.ZeroMemory(paddingBuffer); + } + + public override int HashSizeInBytes => _hashSizeValue; + + public override void Dispose(bool disposing) + { + if (disposing) + { + _hash1.Dispose(); + _hash2.Dispose(); + + CryptographicOperations.ZeroMemory(_key); + } + } + + public override void Reset() + { + if (_hashing) + { + _hash1.Reset(); + _hash2.Reset(); + _hashing = false; + } + } + } +} diff --git a/PspCrypto/Security/Cryptography/HMACSHA224.cs b/PspCrypto/Security/Cryptography/HMACSHA224.cs new file mode 100644 index 0000000..9db364e --- /dev/null +++ b/PspCrypto/Security/Cryptography/HMACSHA224.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace PspCrypto.Security.Cryptography +{ + public class HMACSHA224 : HMAC + { + /// + /// The hash size produced by the HMAC SHA224 algorithm, in bits. + /// + public const int HashSizeInBits = 224; + + /// + /// The hash size produced by the HMAC SHA24 algorithm, in bytes. + /// + public const int HashSizeInBytes = HashSizeInBits / 8; + + public HMACSHA224() + : this(RandomNumberGenerator.GetBytes(BlockSize)) + { } + + public HMACSHA224(byte[] key) + { + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + + HashName = HashAlgorithmNames.SHA224; + _hMacCommon = new HMACCommon(HashAlgorithmNames.SHA224, key, BlockSize); + base.Key = _hMacCommon.ActualKey!; + // this not really needed as it'll initialize BlockSizeValue with same value it has which is 64. + // we just want to be explicit in all HMAC extended classes + BlockSizeValue = BlockSize; + HashSizeValue = _hMacCommon.HashSizeInBits; + Debug.Assert(HashSizeValue == HashSizeInBits); + } + + public override byte[] Key + { + get + { + return base.Key; + } + set + { + ArgumentNullException.ThrowIfNull(value); + _hMacCommon.ChangeKey(value); + base.Key = _hMacCommon.ActualKey!; + } + } + + protected override void HashCore(byte[] rgb, int ib, int cb) => + _hMacCommon.AppendHashData(rgb, ib, cb); + + protected override void HashCore(ReadOnlySpan source) => + _hMacCommon.AppendHashData(source); + + protected override byte[] HashFinal() => + _hMacCommon.FinalizeHashAndReset(); + + protected override bool TryHashFinal(Span destination, out int bytesWritten) => + _hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten); + + public override void Initialize() => _hMacCommon.Reset(); + + /// + /// Computes the HMAC of data using the SHA224 algorithm. + /// + /// The HMAC key. + /// The data to HMAC. + /// The HMAC of the data. + /// + /// or is . + /// + public static byte[] HashData(byte[] key, byte[] source) + { + ArgumentNullException.ThrowIfNull(key); + ArgumentNullException.ThrowIfNull(source); + + return HashData(new ReadOnlySpan(key), new ReadOnlySpan(source)); + } + + /// + /// Computes the HMAC of data using the SHA224 algorithm. + /// + /// The HMAC key. + /// The data to HMAC. + /// The HMAC of the data. + public static byte[] HashData(ReadOnlySpan key, ReadOnlySpan source) + { + byte[] buffer = new byte[HashSizeInBytes]; + + int written = HashData(key, source, buffer.AsSpan()); + Debug.Assert(written == buffer.Length); + + return buffer; + } + + /// + /// Computes the HMAC of data using the SHA224 algorithm. + /// + /// The HMAC key. + /// The data to HMAC. + /// The buffer to receive the HMAC value. + /// The total number of bytes written to . + /// + /// The buffer in is too small to hold the calculated hash + /// size. The SHA224 algorithm always produces a 224-bit HMAC, or 28 bytes. + /// + public static int HashData(ReadOnlySpan key, ReadOnlySpan source, Span destination) + { + if (!TryHashData(key, source, destination, out int bytesWritten)) + { + throw new ArgumentException("Destination is too short.", nameof(destination)); + } + + return bytesWritten; + } + + /// + /// Attempts to compute the HMAC of data using the SHA224 algorithm. + /// + /// The HMAC key. + /// The data to HMAC. + /// The buffer to receive the HMAC value. + /// + /// When this method returns, the total number of bytes written into . + /// + /// + /// if is too small to hold the + /// calculated hash, otherwise. + /// + public static bool TryHashData(ReadOnlySpan key, ReadOnlySpan source, Span destination, out int bytesWritten) + { + if (destination.Length < HashSizeInBytes) + { + bytesWritten = 0; + return false; + } + + bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.SHA224, key, source, destination); + Debug.Assert(bytesWritten == HashSizeInBytes); + + return true; + } + + private HMACCommon _hMacCommon; + private const int BlockSize = 64; + } +} diff --git a/PspCrypto/Security/Cryptography/HashAlgorithmNames.cs b/PspCrypto/Security/Cryptography/HashAlgorithmNames.cs new file mode 100644 index 0000000..5bd4b4a --- /dev/null +++ b/PspCrypto/Security/Cryptography/HashAlgorithmNames.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PspCrypto.Security.Cryptography +{ + internal static class HashAlgorithmNames + { + public const string SHA224 = "SHA224"; + } +} diff --git a/PspCrypto/Security/Cryptography/HashProvider.cs b/PspCrypto/Security/Cryptography/HashProvider.cs new file mode 100644 index 0000000..8b862b7 --- /dev/null +++ b/PspCrypto/Security/Cryptography/HashProvider.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PspCrypto.Security.Cryptography +{ + // + // This abstract class represents a reusable hash object and can wrap a CNG or WinRT hash object. + // + internal abstract class HashProvider : IDisposable + { + // Adds new data to be hashed. This can be called repeatedly in order to hash data from noncontiguous sources. + public void AppendHashData(byte[] data, int offset, int count) + { + ArgumentNullException.ThrowIfNull(data); + + // AppendHashData can be called via exposed APIs (e.g. a type that derives from + // HMACSHA1 and calls HashCore) and could be passed bad data from there. It could + // also receive a bad count from HashAlgorithm reading from a Stream that returns + // an invalid number of bytes read. Since our implementations of AppendHashDataCore + // end up using unsafe code, we want to be sure the arguments are valid. + if (offset < 0) + throw new ArgumentOutOfRangeException(nameof(offset), "Non-negative number required."); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), "Non-negative number required."); + if (data.Length - offset < count) + throw new ArgumentException("Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection."); + + AppendHashData(new ReadOnlySpan(data, offset, count)); + } + + public abstract void AppendHashData(ReadOnlySpan data); + + // Compute the hash based on the appended data and resets the HashProvider for more hashing. + public abstract int FinalizeHashAndReset(Span destination); + + public abstract int GetCurrentHash(Span destination); + + public byte[] FinalizeHashAndReset() + { + byte[] ret = new byte[HashSizeInBytes]; + + int written = FinalizeHashAndReset(ret); + Debug.Assert(written == HashSizeInBytes); + + return ret; + } + + public bool TryFinalizeHashAndReset(Span destination, out int bytesWritten) + { + if (destination.Length < HashSizeInBytes) + { + bytesWritten = 0; + return false; + } + + bytesWritten = FinalizeHashAndReset(destination); + return true; + } + + // Returns the length of the byte array returned by FinalizeHashAndReset. + public abstract int HashSizeInBytes { get; } + + // Releases any native resources and keys used by the HashProvider. + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // Releases any native resources and keys used by the HashProvider. + public abstract void Dispose(bool disposing); + + public abstract void Reset(); + } +} diff --git a/PspCrypto/Security/Cryptography/HashProviderDispenser.cs b/PspCrypto/Security/Cryptography/HashProviderDispenser.cs new file mode 100644 index 0000000..56413e4 --- /dev/null +++ b/PspCrypto/Security/Cryptography/HashProviderDispenser.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace PspCrypto.Security.Cryptography +{ + internal class HashProviderDispenser + { + public static HashProvider CreateHashProvider(string hashAlgorithmId) + { + switch (hashAlgorithmId) + { + case HashAlgorithmNames.SHA224: + return new SHAManagedHashProvider(hashAlgorithmId); + } + throw new CryptographicException(string.Format("'{0}' is not a known hash algorithm.", hashAlgorithmId)); + } + + public static class OneShotHashProvider + { + public static unsafe int MacData( + string hashAlgorithmId, + ReadOnlySpan key, + ReadOnlySpan source, + Span destination) + { + using HashProvider provider = CreateMacProvider(hashAlgorithmId, key); + provider.AppendHashData(source); + return provider.FinalizeHashAndReset(destination); + } + + public static int HashData(string hashAlgorithmId, ReadOnlySpan source, Span destination) + { + HashProvider provider = CreateHashProvider(hashAlgorithmId); + provider.AppendHashData(source); + return provider.FinalizeHashAndReset(destination); + } + } + + public static unsafe HashProvider CreateMacProvider(string hashAlgorithmId, ReadOnlySpan key) + { + switch (hashAlgorithmId) + { + case HashAlgorithmNames.SHA224: + return new HMACManagedHashProvider(hashAlgorithmId, key); + } + throw new CryptographicException(string.Format("'{0}' is not a known hash algorithm.", hashAlgorithmId)); + } + } +} diff --git a/PspCrypto/Security/Cryptography/SHA224.cs b/PspCrypto/Security/Cryptography/SHA224.cs new file mode 100644 index 0000000..5a719ed --- /dev/null +++ b/PspCrypto/Security/Cryptography/SHA224.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Security.Cryptography; +using System.Diagnostics; + +namespace PspCrypto.Security.Cryptography +{ + public abstract class SHA224 : HashAlgorithm + { + /// + /// The hash size produced by the SHA224 algorithm, in bits. + /// + public const int HashSizeInBits = 224; + + /// + /// The hash size produced by the SHA224 algorithm, in bytes. + /// + public const int HashSizeInBytes = HashSizeInBits / 8; + + public SHA224() + { + // SHA-224 hash length are 224 bits long + HashSizeValue = HashSizeInBits; + } + + public static new SHA224 Create() => new Implementation(); + + public new static SHA224 Create(string hashName) + { + var o = (SHA224)CryptoConfig.CreateFromName(hashName); + // in case machine.config isn't configured to use any SHA224 implementation + if (o == null) + { + o = new Implementation(); + } + return o; + } + + /// + /// Computes the hash of data using the SHA224 algorithm. + /// + /// The data to hash. + /// The hash of the data. + /// + /// is . + /// + public static byte[] HashData(byte[] source) + { + ArgumentNullException.ThrowIfNull(source); + + return HashData(new ReadOnlySpan(source)); + } + + /// + /// Computes the hash of data using the SHA224 algorithm. + /// + /// The data to hash. + /// The hash of the data. + public static byte[] HashData(ReadOnlySpan source) + { + byte[] buffer = GC.AllocateUninitializedArray(HashSizeInBytes); + + int written = HashData(source, buffer.AsSpan()); + Debug.Assert(written == buffer.Length); + + return buffer; + } + + /// + /// Computes the hash of data using the SHA224 algorithm. + /// + /// The data to hash. + /// The buffer to receive the hash value. + /// The total number of bytes written to . + /// + /// The buffer in is too small to hold the calculated hash + /// size. The SHA224 algorithm always produces a 224-bit hash, or 28 bytes. + /// + public static int HashData(ReadOnlySpan source, Span destination) + { + if (!TryHashData(source, destination, out int bytesWritten)) + throw new ArgumentException("Destination is too short.", nameof(destination)); + + return bytesWritten; + } + + + /// + /// Attempts to compute the hash of data using the SHA224 algorithm. + /// + /// The data to hash. + /// The buffer to receive the hash value. + /// + /// When this method returns, the total number of bytes written into . + /// + /// + /// if is too small to hold the + /// calculated hash, otherwise. + /// + public static bool TryHashData(ReadOnlySpan source, Span destination, out int bytesWritten) + { + if (destination.Length < HashSizeInBytes) + { + bytesWritten = 0; + return false; + } + + bytesWritten = HashProviderDispenser.OneShotHashProvider.HashData(HashAlgorithmNames.SHA224, source, destination); + Debug.Assert(bytesWritten == HashSizeInBytes); + + return true; + } + + private sealed class Implementation : SHA224 + { + private readonly HashProvider _hashProvider; + + public Implementation() + { + _hashProvider = HashProviderDispenser.CreateHashProvider(HashAlgorithmNames.SHA224); + HashSizeValue = _hashProvider.HashSizeInBytes * 8; + } + + protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) => + _hashProvider.AppendHashData(array, ibStart, cbSize); + + protected sealed override void HashCore(ReadOnlySpan source) => + _hashProvider.AppendHashData(source); + + protected sealed override byte[] HashFinal() => + _hashProvider.FinalizeHashAndReset(); + + protected sealed override bool TryHashFinal(Span destination, out int bytesWritten) => + _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten); + + public sealed override void Initialize() => _hashProvider.Reset(); + + protected sealed override void Dispose(bool disposing) + { + _hashProvider.Dispose(disposing); + base.Dispose(disposing); + } + } + } +} diff --git a/PspCrypto/Security/Cryptography/SHAManagedHashProvider.cs b/PspCrypto/Security/Cryptography/SHAManagedHashProvider.cs new file mode 100644 index 0000000..bb93dab --- /dev/null +++ b/PspCrypto/Security/Cryptography/SHAManagedHashProvider.cs @@ -0,0 +1,376 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +using static System.Numerics.BitOperations; + +namespace PspCrypto.Security.Cryptography +{ + internal sealed class SHAManagedHashProvider : HashProvider + { + private int hashSizeInBytes; + private SHAManagedImplementationBase impl; + private MemoryStream buffer; + + public SHAManagedHashProvider(string hashAlgorithmId) + { + switch (hashAlgorithmId) + { + case HashAlgorithmNames.SHA224: + impl = new SHA224ManagedImplementation(); + hashSizeInBytes = 28; + break; + default: + throw new CryptographicException(string.Format("'{0}' is not a known hash algorithm.", hashAlgorithmId)); + } + } + + public override void AppendHashData(ReadOnlySpan data) + { + buffer ??= new MemoryStream(1000); + + buffer.Write(data); + } + + public override int FinalizeHashAndReset(Span destination) + { + GetCurrentHash(destination); + buffer = null; + + return hashSizeInBytes; + } + + public override int GetCurrentHash(Span destination) + { + Debug.Assert(destination.Length >= hashSizeInBytes); + + impl.Initialize(); + if (buffer != null) + { + impl.HashCore(buffer.GetBuffer(), 0, (int)buffer.Length); + } + impl.HashFinal().CopyTo(destination); + + return hashSizeInBytes; + } + + public override int HashSizeInBytes => hashSizeInBytes; + + public override void Reset() + { + buffer = null; + impl.Initialize(); + } + + public override void Dispose(bool disposing) + { + } + + private abstract class SHAManagedImplementationBase + { + public abstract void Initialize(); + public abstract void HashCore(byte[] partIn, int ibStart, int cbSize); + public abstract byte[] HashFinal(); + } + + private sealed class SHA224ManagedImplementation : SHAManagedImplementationBase + { + private byte[] _buffer; + private long _count; // Number of bytes in the hashed message + private uint[] _stateSHA224; + private uint[] _W; + + public SHA224ManagedImplementation() + { + _stateSHA224 = new uint[8]; + _buffer = new byte[64]; + _W = new uint[64]; + + InitializeState(); + } + + public override void Initialize() + { + InitializeState(); + + // Zeroize potentially sensitive information. + Array.Clear(_buffer, 0, _buffer.Length); + Array.Clear(_W, 0, _W.Length); + } + + private void InitializeState() + { + _count = 0; + + _stateSHA224[0] = 0xc1059ed8; + _stateSHA224[1] = 0x367cd507; + _stateSHA224[2] = 0x3070dd17; + _stateSHA224[3] = 0xf70e5939; + _stateSHA224[4] = 0xffc00b31; + _stateSHA224[5] = 0x68581511; + _stateSHA224[6] = 0x64f98fa7; + _stateSHA224[7] = 0xbefa4fa4; + } + + /* SHA256 block update operation. Continues an SHA message-digest + operation, processing another message block, and updating the + context. + */ + public override unsafe void HashCore(byte[] partIn, int ibStart, int cbSize) + { + int bufferLen; + int partInLen = cbSize; + int partInBase = ibStart; + + /* Compute length of buffer */ + bufferLen = (int)(_count & 0x3f); + + /* Update number of bytes */ + _count += partInLen; + + fixed (uint* stateSHA256 = _stateSHA224) + { + fixed (byte* buffer = _buffer) + { + fixed (uint* expandedBuffer = _W) + { + if (bufferLen > 0 && bufferLen + partInLen >= 64) + { + Buffer.BlockCopy(partIn, partInBase, _buffer, bufferLen, 64 - bufferLen); + partInBase += 64 - bufferLen; + partInLen -= 64 - bufferLen; + SHATransform(expandedBuffer, stateSHA256, buffer); + bufferLen = 0; + } + + /* Copy input to temporary buffer and hash */ + while (partInLen >= 64) + { + Buffer.BlockCopy(partIn, partInBase, _buffer, 0, 64); + partInBase += 64; + partInLen -= 64; + SHATransform(expandedBuffer, stateSHA256, buffer); + } + + if (partInLen > 0) + { + Buffer.BlockCopy(partIn, partInBase, _buffer, bufferLen, partInLen); + } + } + } + } + } + + /* SHA256 finalization. Ends an SHA256 message-digest operation, writing + the message digest. + */ + public override byte[] HashFinal() + { + byte[] pad; + int padLen; + long bitCount; + byte[] hash = new byte[28]; // HashSizeValue = 224 + + /* Compute padding: 80 00 00 ... 00 00 + */ + + padLen = 64 - (int)(_count & 0x3f); + if (padLen <= 8) + padLen += 64; + + pad = new byte[padLen]; + pad[0] = 0x80; + + // Convert count to bit count + bitCount = _count * 8; + + pad[padLen - 8] = (byte)(bitCount >> 56 & 0xff); + pad[padLen - 7] = (byte)(bitCount >> 48 & 0xff); + pad[padLen - 6] = (byte)(bitCount >> 40 & 0xff); + pad[padLen - 5] = (byte)(bitCount >> 32 & 0xff); + pad[padLen - 4] = (byte)(bitCount >> 24 & 0xff); + pad[padLen - 3] = (byte)(bitCount >> 16 & 0xff); + pad[padLen - 2] = (byte)(bitCount >> 8 & 0xff); + pad[padLen - 1] = (byte)(bitCount >> 0 & 0xff); + + /* Digest padding */ + HashCore(pad, 0, pad.Length); + + /* Store digest */ + SHAUtils.DWORDToBigEndian(hash, _stateSHA224, 7); + + return hash; + } + + private static readonly uint[] _K = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + private static unsafe void SHATransform(uint* expandedBuffer, uint* state, byte* block) + { + uint a, b, c, d, e, f, h, g; + uint aa, bb, cc, dd, ee, ff, hh, gg; + uint T1; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; + + // fill in the first 16 bytes of W. + SHAUtils.DWORDFromBigEndian(expandedBuffer, 16, block); + SHA256Expand(expandedBuffer); + + /* Apply the SHA256 compression function */ + // We are trying to be smart here and avoid as many copies as we can + // The perf gain with this method over the straightforward modify and shift + // forward is >= 20%, so it's worth the pain + for (int j = 0; j < 64;) + { + T1 = h + Sigma_1(e) + Ch(e, f, g) + _K[j] + expandedBuffer[j]; + ee = d + T1; + aa = T1 + Sigma_0(a) + Maj(a, b, c); + j++; + + T1 = g + Sigma_1(ee) + Ch(ee, e, f) + _K[j] + expandedBuffer[j]; + ff = c + T1; + bb = T1 + Sigma_0(aa) + Maj(aa, a, b); + j++; + + T1 = f + Sigma_1(ff) + Ch(ff, ee, e) + _K[j] + expandedBuffer[j]; + gg = b + T1; + cc = T1 + Sigma_0(bb) + Maj(bb, aa, a); + j++; + + T1 = e + Sigma_1(gg) + Ch(gg, ff, ee) + _K[j] + expandedBuffer[j]; + hh = a + T1; + dd = T1 + Sigma_0(cc) + Maj(cc, bb, aa); + j++; + + T1 = ee + Sigma_1(hh) + Ch(hh, gg, ff) + _K[j] + expandedBuffer[j]; + h = aa + T1; + d = T1 + Sigma_0(dd) + Maj(dd, cc, bb); + j++; + + T1 = ff + Sigma_1(h) + Ch(h, hh, gg) + _K[j] + expandedBuffer[j]; + g = bb + T1; + c = T1 + Sigma_0(d) + Maj(d, dd, cc); + j++; + + T1 = gg + Sigma_1(g) + Ch(g, h, hh) + _K[j] + expandedBuffer[j]; + f = cc + T1; + b = T1 + Sigma_0(c) + Maj(c, d, dd); + j++; + + T1 = hh + Sigma_1(f) + Ch(f, g, h) + _K[j] + expandedBuffer[j]; + e = dd + T1; + a = T1 + Sigma_0(b) + Maj(b, c, d); + j++; + } + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; + } + + private static uint Ch(uint x, uint y, uint z) + { + return x & y ^ (x ^ 0xffffffff) & z; + } + + private static uint Maj(uint x, uint y, uint z) + { + return x & y ^ x & z ^ y & z; + } + + private static uint sigma_0(uint x) + { + return RotateRight(x, 7) ^ RotateRight(x, 18) ^ x >> 3; + } + + private static uint sigma_1(uint x) + { + return RotateRight(x, 17) ^ RotateRight(x, 19) ^ x >> 10; + } + + private static uint Sigma_0(uint x) + { + return RotateRight(x, 2) ^ RotateRight(x, 13) ^ RotateRight(x, 22); + } + + private static uint Sigma_1(uint x) + { + return RotateRight(x, 6) ^ RotateRight(x, 11) ^ RotateRight(x, 25); + } + + /* This function creates W_16,...,W_63 according to the formula + W_j <- sigma_1(W_{j-2}) + W_{j-7} + sigma_0(W_{j-15}) + W_{j-16}; + */ + private static unsafe void SHA256Expand(uint* x) + { + for (int i = 16; i < 64; i++) + { + x[i] = sigma_1(x[i - 2]) + x[i - 7] + sigma_0(x[i - 15]) + x[i - 16]; + } + } + } + + private static class SHAUtils + { + // digits == number of DWORDs + public static unsafe void DWORDFromBigEndian(uint* x, int digits, byte* block) + { + int i; + int j; + + for (i = 0, j = 0; i < digits; i++, j += 4) + x[i] = (uint)(block[j] << 24 | block[j + 1] << 16 | block[j + 2] << 8 | block[j + 3]); + } + + // encodes x (DWORD) into block (unsigned char), most significant byte first. + // digits == number of DWORDs + public static void DWORDToBigEndian(byte[] block, uint[] x, int digits) + { + int i; + int j; + + for (i = 0, j = 0; i < digits; i++, j += 4) + { + block[j] = (byte)(x[i] >> 24 & 0xff); + block[j + 1] = (byte)(x[i] >> 16 & 0xff); + block[j + 2] = (byte)(x[i] >> 8 & 0xff); + block[j + 3] = (byte)(x[i] & 0xff); + } + } + } + } +} diff --git a/PspCrypto/Structs.cs b/PspCrypto/Structs.cs new file mode 100644 index 0000000..850e09c --- /dev/null +++ b/PspCrypto/Structs.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace PspCrypto +{ + public enum SceExecFileDecryptMode : byte + { + /* Not an executable. */ + DECRYPT_MODE_NO_EXEC = 0, + /* 1.50 Kernel module. */ + DECRYPT_MODE_BOGUS_MODULE = 1, + DECRYPT_MODE_KERNEL_MODULE = 2, + DECRYPT_MODE_VSH_MODULE = 3, + DECRYPT_MODE_USER_MODULE = 4, + DECRYPT_MODE_UMD_GAME_EXEC = 9, + DECRYPT_MODE_GAMESHARING_EXEC = 10, + /* USB/WLAN module. */ + DECRYPT_MODE_UNKNOWN_11 = 11, + DECRYPT_MODE_MS_UPDATER = 12, + DECRYPT_MODE_DEMO_EXEC = 13, + DECRYPT_MODE_APP_MODULE = 14, + DECRYPT_MODE_UNKNOWN_18 = 18, + DECRYPT_MODE_UNKNOWN_19 = 19, + DECRYPT_MODE_POPS_EXEC = 20, + /* MS module. */ + DECRYPT_MODE_UNKNOWN_21 = 21, + /* APP module. */ + DECRYPT_MODE_UNKNOWN_22 = 22, + /* USER module. */ + DECRYPT_MODE_UNKNOWN_23 = 23, + /* USER module. */ + DECRYPT_MODE_UNKNOWN_25 = 25, + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public unsafe struct PSPHeader2 + { + public Span RawHdr + { + get + { + fixed (uint* ptr = &magic) + { + return new Span(ptr, 0x80); + } + } + } + public uint magic; + public ushort modAttribute; + public ushort compAttribute; + public byte moduleVerLo; + public byte moduleVerHi; + private fixed byte _modName[27]; + + public Span modName + { + get + { + fixed (byte* ptr = _modName) + { + return new Span(ptr, 27); + } + } + } + public byte terminal; + public byte modVersion; + public byte nSegments; + public int elfSize; + public int pspSize; + public uint bootEntry; + public int modInfoOffset; + public uint bssSize; + private fixed ushort _segAlign[4]; + + public Span segAlign + { + get + { + fixed (ushort* ptr = _segAlign) + { + return new Span(ptr, 4); + } + } + } + private fixed uint _segAddress[4]; + + public Span segAddress + { + get + { + fixed (uint* ptr = _segAddress) + { + return new Span(ptr, 4); + } + } + } + private fixed uint _segSize[4]; + + public Span segSize + { + get + { + fixed (uint* ptr = _segSize) + { + return new Span(ptr, 4); + } + } + } + public fixed uint reserved[5]; + public uint devkitVersion; + public SceExecFileDecryptMode decryptMode; + public byte padding; + public ushort overlapSize; + private fixed byte _aesKey[16]; + public Span aesKey + { + get + { + fixed (byte* ptr = _aesKey) + { + return new Span(ptr, 16); + } + } + } + + public Span keyData + { + get + { + fixed (byte* ptr = _aesKey) + { + return new Span(ptr, 0x30); + } + } + } + + public Span keyData50 + { + get + { + fixed (byte* ptr = _aesKey) + { + return new Span(ptr, 0x50); + } + } + } + + private fixed byte _cmacKey[16]; + public Span cmacKey + { + get + { + fixed (byte* ptr = _cmacKey) + { + return new Span(ptr, 16); + } + } + } + private fixed byte _cmacHeaderHash[16]; + public Span cmacHeaderHash + { + get + { + fixed (byte* ptr = _cmacHeaderHash) + { + return new Span(ptr, 16); + } + } + } + + public Span sizeInfo + { + get + { + fixed (int* ptr = &dataSize) + { + return new Span(ptr, 0x10); + } + } + } + public int dataSize; + public int dataOffset; + public uint unk184; + public uint unk188; + private fixed byte _cmacDataHash[16]; + + public Span cmacDataHash + { + get + { + fixed (byte* ptr = _cmacDataHash) + { + return new Span(ptr, 16); + } + } + } + + public Span CheckData + { + get + { + fixed (uint* ptr = &tag) + { + return new Span(ptr, 0x80); + } + } + } + public uint tag; + private fixed byte _sCheck[0x58]; + + public Span sCheck + { + get + { + fixed (byte* ptr = _sCheck) + { + return new Span(ptr, 0x58); + } + } + } + private fixed byte _sha1Hash[20]; + + public Span sha1Hash + { + get + { + fixed (byte* ptr = _sha1Hash) + { + return new Span(ptr, 20); + } + } + } + private fixed byte _keyData4[16]; + + public Span keyData4 + { + get + { + fixed (byte* ptr = _keyData4) + { + return new Span(ptr, 16); + } + } + } + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct PbpHeader + { + public int Sig; + public int Version; + public int ParamOff; + public int Icon0Off; + public int Icon1Off; + public int Pic0Off; + public int Pic1Off; + public int Snd0Off; + public int DataPspOff; + public int DataPsarOff; + } +} diff --git a/PspCrypto/Utils.cs b/PspCrypto/Utils.cs new file mode 100644 index 0000000..8e003c3 --- /dev/null +++ b/PspCrypto/Utils.cs @@ -0,0 +1,34 @@ +using System; +using System.Runtime.InteropServices; + +namespace PspCrypto +{ + public static class Utils + { + public static bool IsEmpty(Span buf, int buf_size) + { + if (buf != null && buf.Length >= buf_size) + { + int i; + for (i = 0; i < buf_size; i++) + { + if (buf[i] != 0) return false; + } + } + return true; + } + + public static void BuildDrmBBMacFinal2(Span mac) + { + Span checksum = new byte[20 + 0x10]; + ref var aesHdr = ref MemoryMarshal.AsRef(checksum); + aesHdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC; + aesHdr.keyseed = 0x63; + aesHdr.data_size = 0x10; + mac.CopyTo(checksum.Slice(20)); + KIRKEngine.sceUtilsBufferCopyWithRange(checksum, 0x10, checksum, 0x10, + KIRKEngine.KIRK_CMD_ENCRYPT_IV_0); + checksum.Slice(20, 0x10).CopyTo(mac); + } + } +} diff --git a/PspCrypto/__sce_discinfo b/PspCrypto/__sce_discinfo new file mode 100644 index 0000000..eff16fc Binary files /dev/null and b/PspCrypto/__sce_discinfo differ diff --git a/Vita/ContentManager/Account.cs b/Vita/ContentManager/Account.cs new file mode 100644 index 0000000..af8a01c --- /dev/null +++ b/Vita/ContentManager/Account.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Vita.ContentManager +{ + public class Account + { + public Account(UInt64 accountId) + { + this.accountId = accountId; + } + private UInt64 accountId; + public bool Devkit; + + public byte[] AccountId + { + get + { + if (Devkit) return new byte[8]; + return BitConverter.GetBytes(accountId); + } + } + public string AccountIdStr + { + get + { + return BitConverter.ToString(AccountId).Replace("-", "").ToLowerInvariant(); + } + } + + public string CmaKeyStr + { + get + { + return KeyGenerator.GenerateKeyStr(AccountIdStr); + } + } + + public byte[] CmaKey + { + get + { + return KeyGenerator.GenerateKey(AccountId); + } + } + + + } +} diff --git a/CHOVY-TRANSFER/cmakeys.cs b/Vita/ContentManager/KeyGenerator.cs similarity index 85% rename from CHOVY-TRANSFER/cmakeys.cs rename to Vita/ContentManager/KeyGenerator.cs index 31a3b9c..1012092 100644 --- a/CHOVY-TRANSFER/cmakeys.cs +++ b/Vita/ContentManager/KeyGenerator.cs @@ -1,67 +1,66 @@ -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace KeyDerivation -{ - class CmaKeys - { - static Byte[] Passphrase = Encoding.ASCII.GetBytes("Sri Jayewardenepura Kotte"); - static Byte[] Key = { 0xA9, 0xFA, 0x5A, 0x62, 0x79, 0x9F, 0xCC, 0x4C, 0x72, 0x6B, 0x4E, 0x2C, 0xE3, 0x50, 0x6D, 0x38 }; - - public static string GenerateKeyStr(string Aid) - { - try - { - Int64 longlong = Convert.ToInt64(Aid, 16); - - byte[] AidBytes = BitConverter.GetBytes(longlong); - Array.Reverse(AidBytes); - - byte[] DerivedKey = CmaKeys.GenerateKey(AidBytes); - - - return BitConverter.ToString(DerivedKey).Replace("-", ""); - } - catch (Exception) - { - return "INVALID_AID"; - } - } - public static byte[] GenerateKey(byte[] Aid) - { - var ms = new MemoryStream(); - ms.Write(Aid, 0, Aid.Length); - ms.Write(Passphrase, 0, Passphrase.Length); - Byte[] DerviedKey = ms.ToArray(); - ms.Dispose(); - - SHA256 sha = SHA256.Create(); - DerviedKey = sha.ComputeHash(DerviedKey); - sha.Dispose(); - - DerviedKey = Decrypt(DerviedKey, Key); - - return DerviedKey; - } - - private static byte[] Decrypt(byte[] cipherData, - byte[] Key) - { - MemoryStream ms = new MemoryStream(); - Aes alg = Aes.Create(); - alg.Mode = CipherMode.ECB; - alg.Padding = PaddingMode.None; - alg.KeySize = 128; - alg.Key = Key; - CryptoStream cs = new CryptoStream(ms, - alg.CreateDecryptor(), CryptoStreamMode.Write); - cs.Write(cipherData, 0, cipherData.Length); - cs.Close(); - byte[] decryptedData = ms.ToArray(); - return decryptedData; - } - - } +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Vita.ContentManager +{ + public class KeyGenerator + { + static Byte[] Passphrase = Encoding.ASCII.GetBytes("Sri Jayewardenepura Kotte"); + static Byte[] Key = { 0xA9, 0xFA, 0x5A, 0x62, 0x79, 0x9F, 0xCC, 0x4C, 0x72, 0x6B, 0x4E, 0x2C, 0xE3, 0x50, 0x6D, 0x38 }; + + public static string GenerateKeyStr(string Aid) + { + try + { + Int64 longlong = Convert.ToInt64(Aid, 16); + + byte[] AidBytes = BitConverter.GetBytes(longlong); + Array.Reverse(AidBytes); + + byte[] DerivedKey = GenerateKey(AidBytes); + + + return BitConverter.ToString(DerivedKey).Replace("-", ""); + } + catch (Exception) + { + return "INVALID_AID"; + } + } + public static byte[] GenerateKey(byte[] Aid) + { + var ms = new MemoryStream(); + ms.Write(Aid, 0, Aid.Length); + ms.Write(Passphrase, 0, Passphrase.Length); + Byte[] DerviedKey = ms.ToArray(); + ms.Dispose(); + + SHA256 sha = SHA256.Create(); + DerviedKey = sha.ComputeHash(DerviedKey); + sha.Dispose(); + + DerviedKey = Decrypt(DerviedKey, Key); + + return DerviedKey; + } + + private static byte[] Decrypt(byte[] cipherData, byte[] Key) + { + MemoryStream ms = new MemoryStream(); + Aes alg = Aes.Create(); + alg.Mode = CipherMode.ECB; + alg.Padding = PaddingMode.None; + alg.KeySize = 128; + alg.Key = Key; + CryptoStream cs = new CryptoStream(ms, + alg.CreateDecryptor(), CryptoStreamMode.Write); + cs.Write(cipherData, 0, cipherData.Length); + cs.Close(); + byte[] decryptedData = ms.ToArray(); + return decryptedData; + } + + } } \ No newline at end of file diff --git a/Vita/ContentManager/SettingsReader.cs b/Vita/ContentManager/SettingsReader.cs new file mode 100644 index 0000000..f0490df --- /dev/null +++ b/Vita/ContentManager/SettingsReader.cs @@ -0,0 +1,177 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Vita.ContentManager +{ + public class SettingsReader + { + private static string? overrideBackupsFolder = null; + public static string AppFolder + { + get + { + return Path.Combine(BackupsFolder, "APP"); + } + } + public static string PspSavedataFolder + { + get + { + return Path.Combine(BackupsFolder, "PSAVEDATA"); + } + } + + public static string PsmFolder + { + get + { + return Path.Combine(BackupsFolder, "PSM"); + } + } + public static string SystemFolder + { + get + { + return Path.Combine(BackupsFolder, "SYSTEM"); + } + } + public static string Ps1Folder + { + get + { + return Path.Combine(BackupsFolder, "PSGAME"); + } + } + public static string PspFolder + { + get + { + return Path.Combine(BackupsFolder, "PGAME"); + } + } + public static string BackupsFolder + { + get + { + if (overrideBackupsFolder is not null) return overrideBackupsFolder; + + string? cmaFolder = getQcmaPSVitaFolder(); + if (cmaFolder is not null) return cmaFolder; + cmaFolder = getDevkitCmaPSVitaFolder(); + if (cmaFolder is not null) return cmaFolder; + cmaFolder = getSonyCmaPSVitaFolder(); + if (cmaFolder is not null) return cmaFolder; + return getDefaultCmaPSVitaFolder(); + } + set + { + overrideBackupsFolder = value; + } + } + + private static string getDefaultCmaPSVitaFolder() + { + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "PS Vita"); + } + + private static string getQcmaConfFile() + { + if (OperatingSystem.IsLinux()) + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "codestation", "qcma.conf"); + else if (OperatingSystem.IsMacOS()) + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Preferences", "com.codestation.qcma.plist"); + else + throw new PlatformNotSupportedException("cannot open qcma config as i dont know where it is."); + } + private static string? getQcmaConfigSetting(string file, string key) + { + if (!File.Exists(file)) return null; + + if (OperatingSystem.IsLinux()) + { + using (TextReader confFile = File.OpenText(file)) + { + for (string? ln = confFile.ReadLine(); + ln is not null; + ln = confFile.ReadLine()) + { + ln = ln.Trim(); + if (ln.StartsWith("[")) continue; + + string[] kvp = ln.Split('='); + if (kvp.Length < 2) continue; + + string settingKey = kvp[0].Trim(); + string settingValue = kvp[1].Trim(); + + + if (settingKey == key) + return settingValue; + } + } + } + else if (OperatingSystem.IsMacOS()) + { + throw new PlatformNotSupportedException("TODO: Implement reading bplist file from mac os"); + } + return null; + } + + private static string? getRegistryKey(string registryPath, string keyName) + { + if (OperatingSystem.IsWindows()) + { + using (RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(registryPath)) + { + if (regKey is null) return null; + string? keyData = (regKey.GetValue(keyName) as string); + if (keyData is null) return null; + return keyData; + } + } + else + { + throw new PlatformNotSupportedException("cannot use registry on os other than windows"); + } + } + + private static string? getSonyCmaPSVitaFolder() + { + if (OperatingSystem.IsWindows()) + { + return getRegistryKey(@"Software\Sony Corporation\Sony Corporation\Content Manager Assistant\Settings", "ApplicationHomePath"); + } + return null; + } + private static string? getDevkitCmaPSVitaFolder() + { + if (OperatingSystem.IsWindows()) + { + return getRegistryKey(@"Software\SCE\PSP2\Content Manager Assistant for PlayStation(R)Vita DevKit\Settings", "ApplicationHomePath"); + } + return null; + } + private static string? getQcmaPSVitaFolder() + { + if (OperatingSystem.IsWindows()) + { + return getRegistryKey(@"Software\codestation\qcma", "appsPath"); + } + else if (OperatingSystem.IsLinux()) + { + string qcmaConf = getQcmaConfFile(); + return getQcmaConfigSetting(qcmaConf, "appsPath"); + } + else if (OperatingSystem.IsMacOS()) + { + string qcmaConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Preferences", "com.codestation.qcma.plist"); + // TODO: read file + } + return null; + } + } +} diff --git a/CHOVY-TRANSFER/PSVIMGBuilder.cs b/Vita/PsvImgTools/PSVIMGBuilder.cs similarity index 72% rename from CHOVY-TRANSFER/PSVIMGBuilder.cs rename to Vita/PsvImgTools/PSVIMGBuilder.cs index c17ea36..e1fb974 100644 --- a/CHOVY-TRANSFER/PSVIMGBuilder.cs +++ b/Vita/PsvImgTools/PSVIMGBuilder.cs @@ -1,488 +1,548 @@ -using Org.BouncyCastle.Crypto.Digests; -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using static PSVIMGTOOLS.SceIoStat; - -namespace PSVIMGTOOLS -{ - class PSVIMGBuilder - { - private byte[] IV = new byte[0x10]; - private byte[] KEY; - private Random rnd = new Random(); - private Stream mainStream; - private Sha256Digest shaCtx; - private byte[] blockData; - private MemoryStream blockStream; - private long contentSize = 0; - - - //async - private int blocksWritten = 0; - private bool finished = false; - - public Int64 ContentSize - { - get - { - return contentSize; - } - } - public Int32 BlocksWritten - { - get - { - return blocksWritten; - } - } - - public Boolean HasFinished - { - get - { - return finished; - } - } - - //Footer - private long totalBytes = 0; - - private byte[] aes_cbc_encrypt(byte[] plainText, byte[] IV, byte[] KEY, int size=-1) - { - if (size < 0) - { - size = plainText.Length; - } - - MemoryStream ms = new MemoryStream(); - /* - *- DEBUG Disable Encryption - ms.Write(plainText, 0x00, size); - ms.Seek(0x00,SeekOrigin.Begin); - return ms.ToArray();*/ - - Aes alg = Aes.Create(); - alg.Mode = CipherMode.CBC; - alg.Padding = PaddingMode.None; - alg.KeySize = 256; - alg.BlockSize = 128; - alg.Key = KEY; - alg.IV = IV; - CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write); - cs.Write(plainText, 0, size); - cs.Close(); - byte[] cipherText = ms.ToArray(); - return cipherText; - } - - private byte[] aes_ecb_encrypt(byte[] plainText, byte[] KEY, int size = -1) - { - if (size < 0) - { - size = plainText.Length; - } - - MemoryStream ms = new MemoryStream(); - /* - *- DEBUG Disable Encryption - ms.Write(plainText, 0x00, size); - ms.Seek(0x00,SeekOrigin.Begin); - return ms.ToArray();*/ - - Aes alg = Aes.Create(); - alg.Mode = CipherMode.ECB; - alg.Padding = PaddingMode.None; - alg.KeySize = 256; - alg.BlockSize = 128; - alg.Key = KEY; - CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write); - cs.Write(plainText, 0, size); - cs.Close(); - byte[] cipherText = ms.ToArray(); - return cipherText; - } - - private void writeUInt64(Stream dst,UInt64 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x8); - } - private void writeInt64(Stream dst,Int64 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x8); - } - private void writeUInt16(Stream dst, UInt16 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x2); - } - private void writeInt16(Stream dst, Int16 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x2); - } - - private void writeInt32(Stream dst, Int32 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x4); - } - private void writeUInt32(Stream dst, UInt32 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x4); - } - - private SceDateTime dateTimeToSceDateTime(DateTime dt) - { - SceDateTime sdt = new SceDateTime(); - sdt.Day = Convert.ToUInt16(dt.Day); - sdt.Month = Convert.ToUInt16(dt.Month); - sdt.Year = Convert.ToUInt16(dt.Year); - - - sdt.Hour = Convert.ToUInt16(dt.Hour); - sdt.Minute = Convert.ToUInt16(dt.Minute); - sdt.Second = Convert.ToUInt16(dt.Second); - sdt.Microsecond = Convert.ToUInt32(dt.Millisecond * 1000); - return sdt; - } - - private SceIoStat sceIoStat(string path) - { - SceIoStat stats = new SceIoStat(); - FileAttributes attrbutes = File.GetAttributes(path); - - if (attrbutes.HasFlag(FileAttributes.Directory)) - { - stats.Mode |= Modes.Directory; - stats.Size = 0; - } - else - { - stats.Mode |= Modes.File; - stats.Size = Convert.ToUInt64(new FileInfo(path).Length); - - } - - if(attrbutes.HasFlag(FileAttributes.ReadOnly)) - { - stats.Mode |= Modes.GroupRead; - - stats.Mode |= Modes.OthersRead; - - stats.Mode |= Modes.UserRead; - } - else - { - stats.Mode |= Modes.GroupRead; - stats.Mode |= Modes.GroupWrite; - - stats.Mode |= Modes.OthersRead; - stats.Mode |= Modes.OthersWrite; - - stats.Mode |= Modes.UserRead; - stats.Mode |= Modes.UserWrite; - } - - stats.CreationTime = dateTimeToSceDateTime(File.GetCreationTimeUtc(path)); - stats.AccessTime = dateTimeToSceDateTime(File.GetLastAccessTimeUtc(path)); - stats.ModificaionTime = dateTimeToSceDateTime(File.GetLastWriteTimeUtc(path)); - - return stats; - } - - private void writeSceDateTime(Stream dst,SceDateTime time) - { - writeUInt16(dst, time.Year); - writeUInt16(dst, time.Month); - writeUInt16(dst, time.Day); - - writeUInt16(dst, time.Hour); - writeUInt16(dst, time.Minute); - writeUInt16(dst, time.Second); - writeUInt32(dst, time.Microsecond); - } - - private void writeSceIoStat(Stream dst, SceIoStat stats) - { - writeUInt32(dst, Convert.ToUInt32(stats.Mode)); - writeUInt32(dst, Convert.ToUInt32(stats.Attributes)); - writeUInt64(dst, stats.Size); - writeSceDateTime(dst, stats.CreationTime); - writeSceDateTime(dst, stats.AccessTime); - writeSceDateTime(dst, stats.ModificaionTime); - foreach(UInt32 i in stats.Private) - { - writeUInt32(dst,i); - } - } - - private void memset(byte[] buf, byte content, long length) - { - for(int i = 0; i < length; i++) - { - buf[i] = content; - } - } - - private void writeStringWithPadding(Stream dst, string str, int padSize, byte padByte = 0x78) - { - int StrLen = str.Length; - if(StrLen > padSize) - { - StrLen = padSize; - } - - int PaddingLen = (padSize - StrLen)-1; - writeString(dst, str, StrLen); - dst.WriteByte(0x00); - writePadding(dst, padByte, PaddingLen); - } - - private void writeString(Stream dst, string str, int len=-1) - { - if(len < 0) - { - len = str.Length; - } - - byte[] StrBytes = Encoding.UTF8.GetBytes(str); - dst.Write(StrBytes, 0x00, len); - } - - private void writePadding(Stream dst, byte paddingByte, long paddingLen) - { - byte[] paddingData = new byte[paddingLen]; - memset(paddingData, paddingByte, paddingLen); - dst.Write(paddingData, 0x00, paddingData.Length); - } - private byte[] getHeader(string FilePath, string ParentPath, string PathRel) - { - using (MemoryStream Header = new MemoryStream()) - { - writeInt64(Header, DateTime.UtcNow.Ticks); // SysTime - writeInt64(Header, 0); // Flags - writeSceIoStat(Header, sceIoStat(FilePath)); - writeStringWithPadding(Header, ParentPath, 256); // Parent Path - writeUInt32(Header, 1); //unk_16C - writeStringWithPadding(Header, PathRel, 256); //Relative Path - writePadding(Header, 0x78, 904); //'x' - writeString(Header, PSVIMGConstants.PSVIMG_HEADER_END); //EndOfHeader - Header.Seek(0x00, SeekOrigin.Begin); - return Header.ToArray(); - } - } - - private void startNewBlock() - { - blockData = new byte[PSVIMGConstants.FULL_PSVIMG_SIZE]; - blockStream = new MemoryStream(blockData, 0x00, PSVIMGConstants.FULL_PSVIMG_SIZE); - } - - - private byte[] shaBlock(int length = PSVIMGConstants.PSVIMG_BLOCK_SIZE,bool final=false) - { - byte[] outbytes = new byte[PSVIMGConstants.SHA256_BLOCK_SIZE]; - shaCtx.BlockUpdate(blockData, 0x00, length); - Sha256Digest shaTmp = (Sha256Digest)shaCtx.Copy(); - shaTmp.DoFinal(outbytes,0x00); - return outbytes; - } - - private void finishBlock(bool final = false) - { - int len = Convert.ToInt32(blockStream.Position); - byte[] shaBytes = shaBlock(len, final); - blockStream.Write(shaBytes, 0x00, PSVIMGConstants.SHA256_BLOCK_SIZE); - len += PSVIMGConstants.SHA256_BLOCK_SIZE; - - //Get next IV - byte[] encryptedBlock = aes_cbc_encrypt(blockData, IV, KEY, len); - for (int i = 0; i < IV.Length; i++) - { - int encBlockOffset = (encryptedBlock.Length - IV.Length)+i; - IV[i] = encryptedBlock[encBlockOffset]; - } - - mainStream.Write(encryptedBlock, 0x00, encryptedBlock.Length); - totalBytes += encryptedBlock.Length; - - blockStream.Dispose(); - } - - private int remainingBlockSize() - { - return Convert.ToInt32((PSVIMGConstants.PSVIMG_BLOCK_SIZE - blockStream.Position)); - } - - private void writeBlock(byte[] data, bool update=false) - { - long dLen = data.Length; - long writeTotal = 0; - while (dLen > 0) - { - int remaining = remainingBlockSize(); - - if (dLen > remaining) - { - byte[] dataRemains = new byte[remaining]; - Array.Copy(data, writeTotal, dataRemains, 0, remaining); - blockStream.Write(dataRemains, 0x00, remaining); - - writeTotal += remaining; - dLen -= remaining; - - - finishBlock(); - startNewBlock(); - if (update) - { - blocksWritten += 1; - } - } - else - { - byte[] dataRemains = new byte[dLen]; - Array.Copy(data, writeTotal, dataRemains, 0, dLen); - blockStream.Write(dataRemains, 0x00, Convert.ToInt32(dLen)); - - writeTotal += dLen; - dLen -= dLen; - } - } - } - private byte[] getPadding(long size) - { - using (MemoryStream ms = new MemoryStream()) - { - long paddingSize = PSVIMGPadding.GetPadding(size); - if(paddingSize != 0) - { - writePadding(ms, 0x2B, paddingSize-PSVIMGConstants.PSVIMG_PADDING_END.Length); - writeString(ms, PSVIMGConstants.PSVIMG_PADDING_END); - } - ms.Seek(0x00, SeekOrigin.Begin); - return ms.ToArray(); - } - } - - private byte[] getTailer() - { - using (MemoryStream ms = new MemoryStream()) - { - writeUInt64(ms, 0x00); - writePadding(ms, 0x7a, 1004); - writeString(ms, PSVIMGConstants.PSVIMG_TAILOR_END); - - ms.Seek(0x00, SeekOrigin.Begin); - return ms.ToArray(); - } - } - - private void writeStream(Stream dst) - { - while(dst.Position < dst.Length) - { - byte[] work_buf; - Int64 bytes_remain = (dst.Length - dst.Position); - if (bytes_remain > 0x33554432) - { - work_buf = new byte[0x33554432]; - } - else - { - work_buf = new byte[bytes_remain]; - } - dst.Read(work_buf, 0x00, work_buf.Length); - writeBlock(work_buf, true); - } - } - - private byte[] getFooter() - { - using (MemoryStream ms = new MemoryStream()) - { - totalBytes += 0x10; //number of bytes used by this footer. - - writeInt32(ms, 0x00); // int padding (idk wht this is) - writeUInt32(ms, 0x00); - writeInt64(ms, totalBytes); - ms.Seek(0x00, SeekOrigin.Begin); - return aes_cbc_encrypt(ms.ToArray(), IV, KEY); - } - - } - - public void AddFileAsync(string FilePath, string ParentPath, string PathRel) - { - finished = false; - new Thread(() => - { - long sz = Convert.ToInt64(sceIoStat(FilePath).Size); - writeBlock(getHeader(FilePath, ParentPath, PathRel)); - using (FileStream fs = File.OpenRead(FilePath)) - { - writeStream(fs); - } - writeBlock(getPadding(sz)); - writeBlock(getTailer()); - contentSize += sz; - finished = true; - }).Start(); - - } - public void AddFile(string FilePath, string ParentPath, string PathRel) - { - - long sz = Convert.ToInt64(sceIoStat(FilePath).Size); - writeBlock(getHeader(FilePath, ParentPath, PathRel)); - using (FileStream fs = File.OpenRead(FilePath)) - { - writeStream(fs); - } - writeBlock(getPadding(sz)); - writeBlock(getTailer()); - contentSize += sz; - } - - public void AddDir(string DirPath, string ParentPath, string PathRel) - { - writeBlock(getHeader(DirPath, ParentPath, PathRel)); - writeBlock(getPadding(0)); - writeBlock(getTailer()); - } - public long Finish() - { - finishBlock(true); - byte[] footer = getFooter(); - mainStream.Write(footer, 0x00, footer.Length); - - blockStream.Dispose(); - mainStream.Dispose(); - return contentSize; - } - - - public PSVIMGBuilder(Stream dst, byte[] Key) - { - totalBytes = 0; - contentSize = 0; - shaCtx = new Sha256Digest(); - mainStream = dst; - KEY = Key; - - rnd.NextBytes(IV); - IV = aes_ecb_encrypt(IV, Key); - - mainStream.Write(IV, 0x00, IV.Length); - totalBytes += IV.Length; - - startNewBlock(); - } - } -} +using Li.Progress; +using Org.BouncyCastle.Crypto.Digests; +using System.Security.Cryptography; +using System.Text; +using static Vita.PsvImgTools.SceIoStat; + +namespace Vita.PsvImgTools +{ + public class PSVIMGBuilder : ProgressTracker + { + private const Int64 BUFFER_SZ = 0x10000; + private byte[] IV = new byte[0x10]; + private byte[] KEY; + private Random rnd = new Random(); + private Stream mainStream; + private Sha256Digest shaCtx; + private byte[] blockData; + private MemoryStream blockStream; + private long contentSize = 0; + + //async + private int blocksWritten = 0; + private bool finished = false; + + public Int64 ContentSize + { + get + { + return contentSize; + } + } + public Int32 BlocksWritten + { + get + { + return blocksWritten; + } + } + + public Boolean HasFinished + { + get + { + return finished; + } + } + + //Footer + private long totalBytes = 0; + + private byte[] aes_cbc_encrypt(byte[] plainText, byte[] IV, byte[] KEY, int size=-1) + { + if (size < 0) + { + size = plainText.Length; + } + + MemoryStream ms = new MemoryStream(); + /* DEBUG Disable Encryption + ms.Write(plainText, 0x00, size); + ms.Seek(0x00,SeekOrigin.Begin); + return ms.ToArray();*/ + + Aes alg = Aes.Create(); + alg.Mode = CipherMode.CBC; + alg.Padding = PaddingMode.None; + alg.KeySize = 256; + alg.BlockSize = 128; + alg.Key = KEY; + alg.IV = IV; + CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write); + cs.Write(plainText, 0, size); + cs.Close(); + byte[] cipherText = ms.ToArray(); + return cipherText; + } + + private byte[] aes_ecb_encrypt(byte[] plainText, byte[] KEY, int size = -1) + { + if (size < 0) + { + size = plainText.Length; + } + + MemoryStream ms = new MemoryStream(); + /* DEBUG Disable Encryption + ms.Write(plainText, 0x00, size); + ms.Seek(0x00,SeekOrigin.Begin); + return ms.ToArray();*/ + + Aes alg = Aes.Create(); + alg.Mode = CipherMode.ECB; + alg.Padding = PaddingMode.None; + alg.KeySize = 256; + alg.BlockSize = 128; + alg.Key = KEY; + CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write); + cs.Write(plainText, 0, size); + cs.Close(); + byte[] cipherText = ms.ToArray(); + return cipherText; + } + + // TODO: Switch to Li.Utilities.StreamUtil for this . + private void writeUInt64(Stream dst,UInt64 value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x8); + } + private void writeInt64(Stream dst,Int64 value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x8); + } + private void writeUInt16(Stream dst, UInt16 value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x2); + } + private void writeInt16(Stream dst, Int16 value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x2); + } + + private void writeInt32(Stream dst, Int32 value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x4); + } + private void writeUInt32(Stream dst, UInt32 value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x4); + } + + internal virtual SceDateTime dateTimeToSceDateTime(DateTime dt) + { + SceDateTime sdt = new SceDateTime(); + sdt.Day = Convert.ToUInt16(dt.Day); + sdt.Month = Convert.ToUInt16(dt.Month); + sdt.Year = Convert.ToUInt16(dt.Year); + + + sdt.Hour = Convert.ToUInt16(dt.Hour); + sdt.Minute = Convert.ToUInt16(dt.Minute); + sdt.Second = Convert.ToUInt16(dt.Second); + sdt.Microsecond = Convert.ToUInt32(dt.Millisecond * 1000); + return sdt; + } + internal virtual SceIoStat sceIoStat() + { + SceIoStat stats = new SceIoStat(); + + stats.Mode |= Modes.Directory; + // set size.. + stats.Size = 0; + + // fake the rest-- + stats.Mode |= Modes.GroupRead; + stats.Mode |= Modes.GroupWrite; + + stats.Mode |= Modes.OthersRead; + stats.Mode |= Modes.OthersWrite; + + stats.Mode |= Modes.UserRead; + stats.Mode |= Modes.UserWrite; + + stats.CreationTime = dateTimeToSceDateTime(DateTime.Now); + stats.AccessTime = dateTimeToSceDateTime(DateTime.Now); + stats.ModificaionTime = dateTimeToSceDateTime(DateTime.Now); + + return stats; + } + internal virtual SceIoStat sceIoStat(Stream str) + { + SceIoStat stats = new SceIoStat(); + + // streams being a directory doesnt really make sense .. + stats.Mode |= Modes.File; + + // set size.. + stats.Size = Convert.ToUInt64(str.Length); + + // fake the rest-- + stats.Mode |= Modes.GroupRead; + stats.Mode |= Modes.GroupWrite; + + stats.Mode |= Modes.OthersRead; + stats.Mode |= Modes.OthersWrite; + + stats.Mode |= Modes.UserRead; + stats.Mode |= Modes.UserWrite; + + stats.CreationTime = dateTimeToSceDateTime(DateTime.Now); + stats.AccessTime = dateTimeToSceDateTime(DateTime.Now); + stats.ModificaionTime = dateTimeToSceDateTime(DateTime.Now); + + return stats; + } + internal virtual SceIoStat sceIoStat(string path) + { + SceIoStat stats = new SceIoStat(); + FileAttributes attrbutes = File.GetAttributes(path); + + if (attrbutes.HasFlag(FileAttributes.Directory)) + { + stats.Mode |= Modes.Directory; + stats.Size = 0; + } + else + { + stats.Mode |= Modes.File; + stats.Size = Convert.ToUInt64(new FileInfo(path).Length); + } + + if(attrbutes.HasFlag(FileAttributes.ReadOnly)) + { + stats.Mode |= Modes.GroupRead; + + stats.Mode |= Modes.OthersRead; + + stats.Mode |= Modes.UserRead; + } + else + { + stats.Mode |= Modes.GroupRead; + stats.Mode |= Modes.GroupWrite; + + stats.Mode |= Modes.OthersRead; + stats.Mode |= Modes.OthersWrite; + + stats.Mode |= Modes.UserRead; + stats.Mode |= Modes.UserWrite; + } + + stats.CreationTime = dateTimeToSceDateTime(File.GetCreationTimeUtc(path)); + stats.AccessTime = dateTimeToSceDateTime(File.GetLastAccessTimeUtc(path)); + stats.ModificaionTime = dateTimeToSceDateTime(File.GetLastWriteTimeUtc(path)); + + return stats; + } + + internal virtual void writeSceDateTime(Stream dst,SceDateTime time) + { + writeUInt16(dst, time.Year); + writeUInt16(dst, time.Month); + writeUInt16(dst, time.Day); + + writeUInt16(dst, time.Hour); + writeUInt16(dst, time.Minute); + writeUInt16(dst, time.Second); + writeUInt32(dst, time.Microsecond); + } + + internal virtual void writeSceIoStat(Stream dst, SceIoStat stats) + { + writeUInt32(dst, Convert.ToUInt32(stats.Mode)); + writeUInt32(dst, Convert.ToUInt32(stats.Attributes)); + writeUInt64(dst, stats.Size); + writeSceDateTime(dst, stats.CreationTime); + writeSceDateTime(dst, stats.AccessTime); + writeSceDateTime(dst, stats.ModificaionTime); + foreach(UInt32 i in stats.Private) + { + writeUInt32(dst,i); + } + } + + internal virtual void memset(byte[] buf, byte content, long length) + { + for(int i = 0; i < length; i++) + { + buf[i] = content; + } + } + + internal virtual void writeStringWithPadding(Stream dst, string str, int padSize, byte padByte = 0x78) + { + int StrLen = str.Length; + if(StrLen > padSize) + { + StrLen = padSize; + } + + int PaddingLen = (padSize - StrLen)-1; + writeString(dst, str, StrLen); + dst.WriteByte(0x00); + writePadding(dst, padByte, PaddingLen); + } + + internal virtual void writeString(Stream dst, string str, int len=-1) + { + if(len < 0) + { + len = str.Length; + } + + byte[] StrBytes = Encoding.UTF8.GetBytes(str); + dst.Write(StrBytes, 0x00, len); + } + + internal virtual void writePadding(Stream dst, byte paddingByte, long paddingLen) + { + byte[] paddingData = new byte[paddingLen]; + memset(paddingData, paddingByte, paddingLen); + dst.Write(paddingData, 0x00, paddingData.Length); + } + internal virtual byte[] getHeader(SceIoStat Stat, string ParentPath, string PathRel) + { + using (MemoryStream Header = new MemoryStream()) + { + writeInt64(Header, DateTime.UtcNow.Ticks); // SysTime + writeInt64(Header, 0); // Flags + writeSceIoStat(Header, Stat); + writeStringWithPadding(Header, ParentPath, 256); // Parent Path + writeUInt32(Header, 1); //unk_16C + writeStringWithPadding(Header, PathRel, 256); //Relative Path + writePadding(Header, 0x78, 904); //'x' + writeString(Header, PSVIMGConstants.PSVIMG_HEADER_END); //EndOfHeader + Header.Seek(0x00, SeekOrigin.Begin); + return Header.ToArray(); + } + } + internal virtual byte[] getHeader(string FilePath, string ParentPath, string PathRel) + { + using (MemoryStream Header = new MemoryStream()) + { + writeInt64(Header, DateTime.UtcNow.Ticks); // SysTime + writeInt64(Header, 0); // Flags + writeSceIoStat(Header, sceIoStat(FilePath)); + writeStringWithPadding(Header, ParentPath, 256); // Parent Path + writeUInt32(Header, 1); //unk_16C + writeStringWithPadding(Header, PathRel, 256); //Relative Path + writePadding(Header, 0x78, 904); //'x' + writeString(Header, PSVIMGConstants.PSVIMG_HEADER_END); //EndOfHeader + Header.Seek(0x00, SeekOrigin.Begin); + return Header.ToArray(); + } + } + + internal virtual void startNewBlock() + { + blockData = new byte[PSVIMGConstants.FULL_PSVIMG_SIZE]; + blockStream = new MemoryStream(blockData, 0x00, PSVIMGConstants.FULL_PSVIMG_SIZE); + } + + + internal virtual byte[] shaBlock(int length = PSVIMGConstants.PSVIMG_BLOCK_SIZE,bool final=false) + { + byte[] outbytes = new byte[PSVIMGConstants.SHA256_BLOCK_SIZE]; + shaCtx.BlockUpdate(blockData, 0x00, length); + Sha256Digest shaTmp = (Sha256Digest)shaCtx.Copy(); + shaTmp.DoFinal(outbytes,0x00); + return outbytes; + } + + internal virtual void finishBlock(bool final = false) + { + int len = Convert.ToInt32(blockStream.Position); + byte[] shaBytes = shaBlock(len, final); + blockStream.Write(shaBytes, 0x00, PSVIMGConstants.SHA256_BLOCK_SIZE); + len += PSVIMGConstants.SHA256_BLOCK_SIZE; + + //Get next IV + byte[] encryptedBlock = aes_cbc_encrypt(blockData, IV, KEY, len); + for (int i = 0; i < IV.Length; i++) + { + int encBlockOffset = (encryptedBlock.Length - IV.Length)+i; + IV[i] = encryptedBlock[encBlockOffset]; + } + + mainStream.Write(encryptedBlock, 0x00, encryptedBlock.Length); + totalBytes += encryptedBlock.Length; + + blockStream.Dispose(); + } + + internal virtual int remainingBlockSize() + { + return Convert.ToInt32((PSVIMGConstants.PSVIMG_BLOCK_SIZE - blockStream.Position)); + } + + internal virtual void writeBlock(byte[] data, bool update=false) + { + long dLen = data.Length; + long writeTotal = 0; + while (dLen > 0) + { + int remaining = remainingBlockSize(); + + if (dLen > remaining) + { + byte[] dataRemains = new byte[remaining]; + Array.Copy(data, writeTotal, dataRemains, 0, remaining); + blockStream.Write(dataRemains, 0x00, remaining); + + writeTotal += remaining; + dLen -= remaining; + + + finishBlock(); + startNewBlock(); + if (update) + blocksWritten += 1; + } + else + { + byte[] dataRemains = new byte[dLen]; + Array.Copy(data, writeTotal, dataRemains, 0, dLen); + blockStream.Write(dataRemains, 0x00, Convert.ToInt32(dLen)); + + writeTotal += dLen; + dLen -= dLen; + } + } + } + internal virtual byte[] getPadding(long size) + { + using (MemoryStream ms = new MemoryStream()) + { + long paddingSize = PSVIMGPadding.GetPadding(size); + if(paddingSize != 0) + { + writePadding(ms, 0x2B, paddingSize-PSVIMGConstants.PSVIMG_PADDING_END.Length); + writeString(ms, PSVIMGConstants.PSVIMG_PADDING_END); + } + ms.Seek(0x00, SeekOrigin.Begin); + return ms.ToArray(); + } + } + + internal virtual byte[] getTailer() + { + using (MemoryStream ms = new MemoryStream()) + { + writeUInt64(ms, 0x00); + writePadding(ms, 0x7a, 1004); + writeString(ms, PSVIMGConstants.PSVIMG_TAILOR_END); + + ms.Seek(0x00, SeekOrigin.Begin); + return ms.ToArray(); + } + } + + internal virtual void writeStream(Stream dst, string file) + { + while(dst.Position < dst.Length) + { + byte[] work_buf; + Int64 bytes_remain = (dst.Length - dst.Position); + if (bytes_remain > BUFFER_SZ) + work_buf = new byte[BUFFER_SZ]; + else + work_buf = new byte[bytes_remain]; + dst.Read(work_buf, 0x00, work_buf.Length); + writeBlock(work_buf, true); + + updateProgress(Convert.ToInt32(dst.Position), Convert.ToInt32(dst.Length), "PSVIMG Package File: " + Path.GetFileName(file)); + } + } + + private byte[] getFooter() + { + using (MemoryStream ms = new MemoryStream()) + { + totalBytes += 0x10; //number of bytes used by this footer. + + writeInt32(ms, 0x00); // int padding (idk wht this is) + writeUInt32(ms, 0x00); + writeInt64(ms, totalBytes); + ms.Seek(0x00, SeekOrigin.Begin); + return aes_cbc_encrypt(ms.ToArray(), IV, KEY); + } + + } + public void AddFile(byte[] sData, string ParentPath, string PathRel) + { + using (MemoryStream ms = new MemoryStream(sData)) + { + AddFile(ms, ParentPath, PathRel); + } + } + public void AddFile(Stream sData, string ParentPath, string PathRel) + { + SceIoStat stat = sceIoStat(sData); + long sz = Convert.ToInt64(stat.Size); + writeBlock(getHeader(stat, ParentPath, PathRel)); + writeStream(sData, PathRel); + writeBlock(getPadding(sz)); + writeBlock(getTailer()); + contentSize += sz; + finished = true; + } + public void AddFile(string FilePath, string ParentPath, string PathRel) + { + + long sz = Convert.ToInt64(sceIoStat(FilePath).Size); + writeBlock(getHeader(FilePath, ParentPath, PathRel)); + using (FileStream fs = File.OpenRead(FilePath)) + writeStream(fs, PathRel); + writeBlock(getPadding(sz)); + writeBlock(getTailer()); + contentSize += sz; + finished = true; + } + public void AddDir(string ParentPath, string PathRel) + { + writeBlock(getHeader(sceIoStat(), ParentPath, PathRel)); + writeBlock(getPadding(0)); + writeBlock(getTailer()); + } + public void AddDir(string DirPath, string ParentPath, string PathRel) + { + writeBlock(getHeader(DirPath, ParentPath, PathRel)); + writeBlock(getPadding(0)); + writeBlock(getTailer()); + } + public long Finish() + { + finishBlock(true); + byte[] footer = getFooter(); + mainStream.Write(footer, 0x00, footer.Length); + + blockStream.Dispose(); + //mainStream.Dispose(); + return contentSize; + } + + + public PSVIMGBuilder(Stream dst, byte[] Key) + { + totalBytes = 0; + contentSize = 0; + shaCtx = new Sha256Digest(); + mainStream = dst; + KEY = Key; + + rnd.NextBytes(IV); + IV = aes_ecb_encrypt(IV, Key); + + mainStream.Write(IV, 0x00, IV.Length); + totalBytes += IV.Length; + + startNewBlock(); + } + } +} diff --git a/Vita/PsvImgTools/PSVIMGFileStream.cs b/Vita/PsvImgTools/PSVIMGFileStream.cs new file mode 100644 index 0000000..2de4568 --- /dev/null +++ b/Vita/PsvImgTools/PSVIMGFileStream.cs @@ -0,0 +1,350 @@ +using System; +using System.IO; +using static Vita.PsvImgTools.SceIoStat; + +namespace Vita.PsvImgTools +{ + public class PSVIMGFileStream : Stream + { + + long length = 0; + long startPos = 0; + long endPos = 0; + long position = 0; + + private PSVIMGStream psvStream; + public PSVIMGFileStream(PSVIMGStream psv, string Path) + { + psvStream = psv; + if (Path.First() == '/') + findFile(Path); + else + findFileMatching(Path); + } + + public void WriteToFile(string FilePath) + { + using (FileStream fs = File.OpenWrite(FilePath)) + { + fs.SetLength(0); + int written = 0; + long left = length - written; + byte[] work_buf; + Seek(0x00, SeekOrigin.Begin); + while (left > 0) + { + left = length - written; + if (left < 0x10000) + { + work_buf = new byte[left]; + } + else + { + work_buf = new byte[0x10000]; + } + Read(work_buf, 0x00, work_buf.Length); + fs.Write(work_buf, 0x00, work_buf.Length); + written += work_buf.Length; + } + + + } + + } + public override bool CanRead + { + get + { + return true; + } + } + + public override bool CanSeek + { + get + { + return true; + } + } + public override bool CanWrite + { + get + { + return false; + } + } + public override long Length + { + get + { + return length; + } + } + + public override long Position + { + get + { + return position; + } + set + { + Seek(value, SeekOrigin.Begin); + } + } + + public override void Flush() + { + psvStream.Flush(); + } + private int _read(byte[] buffer, int offset, int count) + { + + using (MemoryStream ms = new MemoryStream()) + { + int read = 0; + while (true) + { + int remainBlock = Convert.ToInt32(psvStream.BlockRemaining - PSVIMGConstants.SHA256_BLOCK_SIZE); + int remainRead = count - read; + + if (remainRead < remainBlock) + { + byte[] tmp = new byte[remainRead]; + psvStream.Read(tmp, 0x00, remainRead); + ms.Write(tmp, 0x00, tmp.Length); + read += remainRead; + break; + } + else + { + byte[] tmp = new byte[remainBlock]; + psvStream.Read(tmp, 0x00, remainBlock); + ms.Write(tmp, 0x00, tmp.Length); + psvStream.Seek(PSVIMGConstants.SHA256_BLOCK_SIZE, SeekOrigin.Current); + read += Convert.ToInt32(remainBlock); + } + } + ms.Seek(0x00, SeekOrigin.Begin); + return ms.Read(buffer, offset, count); + } + + } + + private long _seek(long amount, SeekOrigin orig) + { + long ToSeek = 0; + long SeekAdd = 0; + long remainBlock = psvStream.BlockRemaining - PSVIMGConstants.SHA256_BLOCK_SIZE; + while (true) + { + long remainSeek = amount - ToSeek; + + if (remainSeek < remainBlock) + { + ToSeek += remainSeek; + break; + } + else + { + ToSeek += remainBlock; + SeekAdd += PSVIMGConstants.SHA256_BLOCK_SIZE; + } + remainBlock = PSVIMGConstants.PSVIMG_BLOCK_SIZE; + } + ToSeek += SeekAdd; + return psvStream.Seek(ToSeek, orig); + } + public override int Read(byte[] buffer, int offset, int count) + { + if (startPos + count > endPos) + { + count = Convert.ToInt32(endPos); + } + return _read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + if (origin == SeekOrigin.Begin) + { + if (offset <= endPos) + { + psvStream.Seek(startPos, SeekOrigin.Begin); + _seek(offset, SeekOrigin.Current); + position = offset; + return position; + } + else + { + throw new IndexOutOfRangeException("Offset is out of range of file"); + } + + } + else if (origin == SeekOrigin.Current) + { + if (offset <= endPos) + { + _seek(offset, SeekOrigin.Current); + position += offset; + return position; + } + else + { + throw new IndexOutOfRangeException("Offset is out of range of file"); + } + } + else + { + long realOffset = endPos + offset; + if (realOffset <= endPos) + { + _seek(realOffset, SeekOrigin.Begin); + return Position; + } + else + { + throw new IndexOutOfRangeException("Offset is out of range of file"); + } + } + + } + + public override void SetLength(long value) + { + throw new NotImplementedException("PSVFileStream is Read-Only"); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException("PSVFileStream is Read-Only"); + } + + private ushort readUInt16() + { + byte[] intBuf = new byte[0x2]; + _read(intBuf, 0x00, 0x02); + return BitConverter.ToUInt16(intBuf, 0); + } + private uint readUInt32() + { + byte[] intBuf = new byte[0x4]; + _read(intBuf, 0x00, 0x04); + return BitConverter.ToUInt32(intBuf, 0); + } + private ulong readUInt64() + { + byte[] intBuf = new byte[0x8]; + _read(intBuf, 0x00, 0x08); + return BitConverter.ToUInt64(intBuf, 0); + } + private SceDateTime readDatetime() + { + SceDateTime dateTime = new SceDateTime(); + dateTime.Year = readUInt16(); + dateTime.Month = readUInt16(); + dateTime.Day = readUInt16(); + dateTime.Hour = readUInt16(); + dateTime.Minute = readUInt16(); + dateTime.Second = readUInt16(); + dateTime.Microsecond = readUInt32(); + return dateTime; + } + private SceIoStat readStats() + { + SceIoStat stat = new SceIoStat(); + stat.Mode = (Modes)readUInt32(); + stat.Attributes = (AttributesEnum)readUInt32(); + stat.Size = readUInt64(); + stat.CreationTime = readDatetime(); + stat.AccessTime = readDatetime(); + stat.ModificaionTime = readDatetime(); + for (int i = 0; i < stat.Private.Length; i++) + { + stat.Private[i] = readUInt32(); + } + return stat; + } + private PsvImgHeader readHeader() + { + PsvImgHeader header = new PsvImgHeader(); + header.SysTime = readUInt64(); + header.Flags = readUInt64(); + header.Statistics = readStats(); + _read(header.bParentPath, 0x00, 256); + header.unk_16C = readUInt32(); + _read(header.bPath, 0x00, 256); + _read(header.Padding, 0x00, 904); + _read(header.bEnd, 0x00, 12); + return header; + } + + public override void Close() + { + psvStream.Dispose(); + base.Close(); + } + + private PsvImgTailer readTailer() + { + PsvImgTailer tailer = new PsvImgTailer(); + tailer.Flags = readUInt64(); + _read(tailer.Padding, 0x00, 1004); + _read(tailer.bEnd, 0x00, 12); + return tailer; + } + + private void findFileMatching(string path) + { + _seek(0x00, SeekOrigin.Begin); + while (psvStream.Position < psvStream.Length) + { + PsvImgHeader header = readHeader(); + long size = (long)header.Statistics.Size; + long padding = PSVIMGPadding.GetPadding(size); + + if (header.Path.Contains(path, StringComparison.InvariantCultureIgnoreCase)) + { + length = size; + startPos = psvStream.Position; + endPos = startPos + length; + return; + } + else + { + _seek(size + padding, SeekOrigin.Current); + PsvImgTailer tailer = readTailer(); + } + + } + throw new FileNotFoundException("Cannot find file specified"); + + } + private void findFile(string path) + { + _seek(0x00, SeekOrigin.Begin); + while (psvStream.Position < psvStream.Length) + { + PsvImgHeader header = readHeader(); + long size = (long)header.Statistics.Size; + long padding = PSVIMGPadding.GetPadding(size); + + if (header.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase)) + { + length = size; + startPos = psvStream.Position; + endPos = startPos + length; + return; + } + else + { + _seek(size + padding, SeekOrigin.Current); + PsvImgTailer tailer = readTailer(); + } + + } + throw new FileNotFoundException("Cannot find file specified"); + + } + } +} diff --git a/Vita/PsvImgTools/PSVIMGStream.cs b/Vita/PsvImgTools/PSVIMGStream.cs new file mode 100644 index 0000000..c6caae4 --- /dev/null +++ b/Vita/PsvImgTools/PSVIMGStream.cs @@ -0,0 +1,365 @@ +using System; +using System.IO; +using System.Security.Cryptography; + + +namespace Vita.PsvImgTools +{ + public class PSVIMGStream : Stream + { + private Stream baseStream; + private MemoryStream blockStream; + private byte[] key; + public Stream BaseStream + { + get + { + return baseStream; + } + } + + public byte[] Key + { + get + { + return key; + } + set + { + key = value; + } + } + + public long BlockNo + { + get + { + return getBlockIndex(); + } + set + { + seekToBlock(value); + update(); + } + } + + public long BlockRemaining + { + get + { + return getRemainingBlock(); + } + } + + public long BlockPosition + { + get + { + return blockStream.Position; + } + set + { + blockStream.Seek(value, SeekOrigin.Begin); + } + } + public override bool CanWrite + { + get + { + return false; + } + } + + public override bool CanRead + { + get + { + return true; + } + } + public override long Length + { + get + { + return baseStream.Length - PSVIMGConstants.AES_BLOCK_SIZE; + } + } + + public override bool CanSeek + { + get + { + return true; + } + } + + public override long Position + { + get + { + return baseStream.Position - PSVIMGConstants.AES_BLOCK_SIZE; + } + set + { + Seek(value, SeekOrigin.Begin); + } + + } + + public PSVIMGStream(Stream file, byte[] KEY) + { + baseStream = file; + key = KEY; + if (!verifyFooter()) + { + throw new Exception("Invalid KEY!"); + } + blockStream = new MemoryStream(); + baseStream.Seek(PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.Begin); + update(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + int remaining = (int)getRemainingBlock(); + int read = 0; + + if (count < remaining) + { + read += blockStream.Read(buffer, offset, count); + baseStream.Seek(count, SeekOrigin.Current); + } + else + { + using (MemoryStream ms = new MemoryStream()) + { + while (true) + { + update(); + remaining = (int)getRemainingBlock(); + int curPos = count - read; + + if (curPos > remaining) + { + read += remaining; + blockStream.CopyTo(ms, remaining); + baseStream.Seek(remaining, SeekOrigin.Current); + } + else + { + read += curPos; + blockStream.CopyTo(ms, curPos); + baseStream.Seek(curPos, SeekOrigin.Current); + break; + } + + } + ms.Seek(0x00, SeekOrigin.Begin); + ms.Read(buffer, offset, count); + } + } + return read; + + } + + public override void Flush() + { + update(); + baseStream.Flush(); + blockStream.Flush(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + long ret = 0; + if (origin == SeekOrigin.Begin) + { + ret = baseStream.Seek(offset + PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.Begin); + } + else if (origin == SeekOrigin.Current) + { + long pos = baseStream.Position; + if (pos + offset >= PSVIMGConstants.AES_BLOCK_SIZE) + { + ret = baseStream.Seek(offset, SeekOrigin.Current); + } + else + { + ret = baseStream.Seek(offset + PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.Current); + } + } + else if (origin == SeekOrigin.End) + { + long pos = baseStream.Length; + if (pos + offset >= PSVIMGConstants.AES_BLOCK_SIZE) + { + ret = baseStream.Seek(offset, SeekOrigin.End); + } + else + { + ret = baseStream.Seek(offset + PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.End); + } + } + update(); + return ret; + } + + public override void SetLength(long value) + { + throw new NotImplementedException("PSVIMGStream is Read-Only"); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException("PSVIMGStream is Read-Only"); + } + + + public override void Close() + { + blockStream.Dispose(); + baseStream.Dispose(); + base.Close(); + } + private void update() + { + long offset = Position % PSVIMGConstants.FULL_PSVIMG_SIZE; + long blockIndex = getBlockIndex(); + byte[] decryptedBlock = getBlock(blockIndex); + blockStream.Seek(0x00, SeekOrigin.Begin); + blockStream.SetLength(decryptedBlock.Length); + blockStream.Write(decryptedBlock, 0x00, decryptedBlock.Length); + seekToBlock(blockIndex); + baseStream.Seek(offset, SeekOrigin.Current); + blockStream.Seek(offset, SeekOrigin.Begin); + } + + private long getBlockIndex() + { + long i = 0; + long curPos = baseStream.Position; + long fullBlock; + long blockOffset; + + while (true) + { + blockOffset = i * PSVIMGConstants.FULL_PSVIMG_SIZE + PSVIMGConstants.AES_BLOCK_SIZE; + long remaining = getRemainingBase(); + if (remaining < PSVIMGConstants.FULL_PSVIMG_SIZE) + { + fullBlock = blockOffset + remaining; + } + else + { + fullBlock = blockOffset + PSVIMGConstants.FULL_PSVIMG_SIZE; + } + if (curPos >= blockOffset && curPos < fullBlock) + { + break; + } + if (blockOffset > baseStream.Length) + { + break; + } + i++; + } + return i; + + + } + private long getRemainingBase() + { + return baseStream.Length - baseStream.Position; + } + private long getRemainingBlock() + { + return blockStream.Length - blockStream.Position; + } + private byte[] getIV(long blockindex) + { + byte[] iv = new byte[0x10]; + seekToBlock(blockindex); + baseStream.Seek(baseStream.Position - PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.Begin); + baseStream.Read(iv, 0x00, iv.Length); + return iv; + } + private byte[] aes_cbc_decrypt(byte[] cipherData, byte[] IV) + { + MemoryStream ms = new MemoryStream(); + Aes alg = Aes.Create(); + alg.Mode = CipherMode.CBC; + alg.Padding = PaddingMode.None; + alg.KeySize = 256; + alg.BlockSize = 128; + alg.Key = key; + alg.IV = IV; + CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write); + cs.Write(cipherData, 0, cipherData.Length); + cs.Close(); + byte[] decryptedData = ms.ToArray(); + return decryptedData; + } + + private void seekToBlock(long blockIndex) + { + long blockOffset; + blockOffset = blockIndex * PSVIMGConstants.FULL_PSVIMG_SIZE + PSVIMGConstants.AES_BLOCK_SIZE; + + if (blockOffset > baseStream.Length) + { + blockOffset = baseStream.Length; + } + + baseStream.Seek(blockOffset, SeekOrigin.Begin); + } + + private bool verifyFooter() + { + byte[] Footer = new byte[0x10]; + byte[] IV = new byte[PSVIMGConstants.AES_BLOCK_SIZE]; + + baseStream.Seek(baseStream.Length - (Footer.Length + IV.Length), SeekOrigin.Begin); + baseStream.Read(IV, 0x00, PSVIMGConstants.AES_BLOCK_SIZE); + baseStream.Read(Footer, 0x00, 0x10); + + byte[] FooterDec = aes_cbc_decrypt(Footer, IV); + ulong FooterLen; + using (MemoryStream ms = new MemoryStream(FooterDec)) + { + ms.Seek(0x4, SeekOrigin.Current); + ms.Seek(0x4, SeekOrigin.Current); + byte[] LenInt = new byte[0x8]; + ms.Read(LenInt, 0x00, 0x8); + FooterLen = BitConverter.ToUInt64(LenInt, 0x00); + } + if (Convert.ToUInt64(baseStream.Length) == FooterLen) + { + return true; + } + else + { + return false; + } + } + + private byte[] getBlock(long blockIndex) + { + byte[] iv = getIV(blockIndex); + long remaining = getRemainingBase(); + byte[] encryptedBlock; + if (PSVIMGConstants.FULL_PSVIMG_SIZE < remaining) + { + encryptedBlock = new byte[PSVIMGConstants.FULL_PSVIMG_SIZE]; + } + else + { + encryptedBlock = new byte[remaining]; + } + + + baseStream.Read(encryptedBlock, 0x00, encryptedBlock.Length); + byte[] decryptedBlock = aes_cbc_decrypt(encryptedBlock, iv); + return decryptedBlock; + } + } +} \ No newline at end of file diff --git a/CHOVY-TRANSFER/PSVIMGStructs.cs b/Vita/PsvImgTools/PSVIMGStructs.cs similarity index 72% rename from CHOVY-TRANSFER/PSVIMGStructs.cs rename to Vita/PsvImgTools/PSVIMGStructs.cs index 3f67c05..a81e0ec 100644 --- a/CHOVY-TRANSFER/PSVIMGStructs.cs +++ b/Vita/PsvImgTools/PSVIMGStructs.cs @@ -1,212 +1,213 @@ -using System; - -namespace PSVIMGTOOLS -{ - - internal class PSVIMGConstants - { - public const int AES_BLOCK_SIZE = 0x10; - public const int SHA256_BLOCK_SIZE = 0x20; - public const int PSVIMG_BLOCK_SIZE = 0x8000; - public const int PSVIMG_ENTRY_ALIGN = 0x400; - - public const string PSVIMG_HEADER_END = "EndOfHeader\n"; - public const string PSVIMG_TAILOR_END = "EndOfTailer\n"; - public const string PSVIMG_PADDING_END = "\n"; - - public const int FULL_PSVIMG_SIZE = PSVIMG_BLOCK_SIZE + SHA256_BLOCK_SIZE; - } - - internal class StringReader - { - internal static string ReadUntilTerminator(byte[] StringBytes) - { - string str = ""; - foreach (byte sByte in StringBytes) - { - if (sByte != 0x00) - { - str += (char)sByte; - } - else - { - return str; - } - } - return str; - } - } - - internal class SceDateTime - { - public UInt16 Year; - public UInt16 Month; - public UInt16 Day; - public UInt16 Hour; - public UInt16 Minute; - public UInt16 Second; - public UInt32 Microsecond; - - public SceDateTime() - { - - } - } - - internal class SceIoStat - { - public enum Modes{ - /** Format bits mask */ - FormatBits = 0xF000, - /** Symbolic link */ - SymbLink = 0x4000, - /** Directory */ - Directory = 0x1000, - /** Regular file */ - File = 0x2000, - - /** Set UID */ - SetUid = 0x0800, - /** Set GID */ - SetGid = 0x0400, - /** Sticky */ - Sticky = 0x0200, - - /** Others access rights mask */ - OthersAcesssMask = 0x01C0, - /** Others read permission */ - OthersRead = 0x0100, - /** Others write permission */ - OthersWrite = 0x0080, - /** Others execute permission */ - OthersExecute = 0x0040, - - /** Group access rights mask */ - GroupAcessMask = 0x0038, - /** Group read permission */ - GroupRead = 0x0020, - /** Group write permission */ - GroupWrite = 0x0010, - /** Group execute permission */ - GroupExecute = 0x0008, - - /** User access rights mask */ - UserAcessMask = 0x0007, - /** User read permission */ - UserRead = 0x0004, - /** User write permission */ - UserWrite = 0x0002, - /** User execute permission */ - UserExecute = 0x0001, - }; - public enum AttributesEnum - { - /** Format mask */ - FormatMask = 0x0038, // Format mask - /** Symlink */ - SymbLink = 0x0008, // Symbolic link - /** Directory */ - Directory = 0x0010, // Directory - /** Regular file */ - File = 0x0020, // Regular file - - /** Hidden read permission */ - Read = 0x0004, // read - /** Hidden write permission */ - Write = 0x0002, // write - /** Hidden execute permission */ - Execute = 0x0001, // execute - }; - - public Modes Mode; - public AttributesEnum Attributes; - /** Size of the file in bytes. */ - public UInt64 Size; - /** Creation time. */ - public SceDateTime CreationTime; - /** Access time. */ - public SceDateTime AccessTime; - /** Modification time. */ - public SceDateTime ModificaionTime; - /** Device-specific data. */ - public UInt32[] Private = new UInt32[6]; - public SceIoStat() - { - for(int i = 0; i < Private.Length; i++) - { - Private[i] = 0; - } - } - }; - - internal class PsvImgTailer - { - public UInt64 Flags; - public Byte[] Padding = new Byte[1004]; - public Byte[] bEnd = new Byte[12]; - - public String End - { - get - { - return StringReader.ReadUntilTerminator(bEnd); - } - } - } - internal class PSVIMGPadding - { - public static long GetPadding(long size) - { - long padding; - if ((size & (PSVIMGConstants.PSVIMG_ENTRY_ALIGN - 1)) >= 1) - { - padding = (PSVIMGConstants.PSVIMG_ENTRY_ALIGN - (size & (PSVIMGConstants.PSVIMG_ENTRY_ALIGN - 1))); - } - else - { - padding = 0; - } - return padding; - } - } - - internal class PsvImgHeader - { - public UInt64 SysTime; - public UInt64 Flags; - public SceIoStat Statistics; - public Byte[] bParentPath = new Byte[256]; - public UInt32 unk_16C; // set to 1 - public Byte[] bPath = new Byte[256]; - public Byte[] Padding = new Byte[904]; - public Byte[] bEnd = new Byte[12]; - - public String Path - { - get - { - return StringReader.ReadUntilTerminator(bPath); - } - } - - public String End - { - get - { - return StringReader.ReadUntilTerminator(bEnd); - } - } - - public String ParentPath - { - get - { - return StringReader.ReadUntilTerminator(bParentPath); - } - } - public PsvImgHeader() - { - - } - } -} +using System; + +namespace Vita.PsvImgTools +{ + + public class PSVIMGConstants + { + public const int AES_BLOCK_SIZE = 0x10; + public const int SHA256_BLOCK_SIZE = 0x20; + public const int PSVIMG_BLOCK_SIZE = 0x8000; + public const int PSVIMG_ENTRY_ALIGN = 0x400; + + public const string PSVIMG_HEADER_END = "EndOfHeader\n"; + public const string PSVIMG_TAILOR_END = "EndOfTailer\n"; + public const string PSVIMG_PADDING_END = "\n"; + + public const int FULL_PSVIMG_SIZE = PSVIMG_BLOCK_SIZE + SHA256_BLOCK_SIZE; + } + + internal class StringReader + { + internal static string ReadUntilTerminator(byte[] StringBytes) + { + string str = ""; + foreach (byte sByte in StringBytes) + { + if (sByte != 0x00) + { + str += (char)sByte; + } + else + { + return str; + } + } + return str; + } + } + + internal class SceDateTime + { + public ushort Year; + public ushort Month; + public ushort Day; + public ushort Hour; + public ushort Minute; + public ushort Second; + public uint Microsecond; + + public SceDateTime() + { + + } + } + + internal class SceIoStat + { + public enum Modes + { + /** Format bits mask */ + FormatBits = 0xF000, + /** Symbolic link */ + SymbLink = 0x4000, + /** Directory */ + Directory = 0x1000, + /** Regular file */ + File = 0x2000, + + /** Set UID */ + SetUid = 0x0800, + /** Set GID */ + SetGid = 0x0400, + /** Sticky */ + Sticky = 0x0200, + + /** Others access rights mask */ + OthersAcesssMask = 0x01C0, + /** Others read permission */ + OthersRead = 0x0100, + /** Others write permission */ + OthersWrite = 0x0080, + /** Others execute permission */ + OthersExecute = 0x0040, + + /** Group access rights mask */ + GroupAcessMask = 0x0038, + /** Group read permission */ + GroupRead = 0x0020, + /** Group write permission */ + GroupWrite = 0x0010, + /** Group execute permission */ + GroupExecute = 0x0008, + + /** User access rights mask */ + UserAcessMask = 0x0007, + /** User read permission */ + UserRead = 0x0004, + /** User write permission */ + UserWrite = 0x0002, + /** User execute permission */ + UserExecute = 0x0001, + }; + public enum AttributesEnum + { + /** Format mask */ + FormatMask = 0x0038, // Format mask + /** Symlink */ + SymbLink = 0x0008, // Symbolic link + /** Directory */ + Directory = 0x0010, // Directory + /** Regular file */ + File = 0x0020, // Regular file + + /** Hidden read permission */ + Read = 0x0004, // read + /** Hidden write permission */ + Write = 0x0002, // write + /** Hidden execute permission */ + Execute = 0x0001, // execute + }; + + public Modes Mode; + public AttributesEnum Attributes; + /** Size of the file in bytes. */ + public ulong Size; + /** Creation time. */ + public SceDateTime CreationTime; + /** Access time. */ + public SceDateTime AccessTime; + /** Modification time. */ + public SceDateTime ModificaionTime; + /** Device-specific data. */ + public uint[] Private = new uint[6]; + public SceIoStat() + { + for (int i = 0; i < Private.Length; i++) + { + Private[i] = 0; + } + } + }; + + internal class PsvImgTailer + { + public ulong Flags; + public byte[] Padding = new byte[1004]; + public byte[] bEnd = new byte[12]; + + public string End + { + get + { + return StringReader.ReadUntilTerminator(bEnd); + } + } + } + internal class PSVIMGPadding + { + public static long GetPadding(long size) + { + long padding; + if ((size & PSVIMGConstants.PSVIMG_ENTRY_ALIGN - 1) >= 1) + { + padding = PSVIMGConstants.PSVIMG_ENTRY_ALIGN - (size & PSVIMGConstants.PSVIMG_ENTRY_ALIGN - 1); + } + else + { + padding = 0; + } + return padding; + } + } + + internal class PsvImgHeader + { + public ulong SysTime; + public ulong Flags; + public SceIoStat Statistics; + public byte[] bParentPath = new byte[256]; + public uint unk_16C; // set to 1 + public byte[] bPath = new byte[256]; + public byte[] Padding = new byte[904]; + public byte[] bEnd = new byte[12]; + + public string Path + { + get + { + return StringReader.ReadUntilTerminator(bPath); + } + } + + public string End + { + get + { + return StringReader.ReadUntilTerminator(bEnd); + } + } + + public string ParentPath + { + get + { + return StringReader.ReadUntilTerminator(bParentPath); + } + } + public PsvImgHeader() + { + + } + } +} diff --git a/CHOVY-TRANSFER/PSVMDBuilder.cs b/Vita/PsvImgTools/PSVMDBuilder.cs similarity index 87% rename from CHOVY-TRANSFER/PSVMDBuilder.cs rename to Vita/PsvImgTools/PSVMDBuilder.cs index fca25ae..bfcc897 100644 --- a/CHOVY-TRANSFER/PSVMDBuilder.cs +++ b/Vita/PsvImgTools/PSVMDBuilder.cs @@ -1,208 +1,208 @@ -using Ionic.Zlib; -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; -namespace PSVIMGTOOLS -{ - class PSVMDBuilder - { - private static void memset(byte[] buf, byte content, long length) - { - for (int i = 0; i < length; i++) - { - buf[i] = content; - } - } - - private static void writeUInt64(Stream dst, UInt64 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x8); - } - private static void writeInt64(Stream dst, Int64 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x8); - } - private static void writeUInt16(Stream dst, UInt16 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x2); - } - private static void writeInt16(Stream dst, Int16 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x2); - } - - private static void writeInt32(Stream dst, Int32 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x4); - } - private static void writeUInt32(Stream dst, UInt32 value) - { - byte[] ValueBytes = BitConverter.GetBytes(value); - dst.Write(ValueBytes, 0x00, 0x4); - } - - - private static void writeString(Stream dst, string str, int len = -1) - { - if (len < 0) - { - len = str.Length; - } - - byte[] StrBytes = Encoding.UTF8.GetBytes(str); - dst.Write(StrBytes, 0x00, len); - } - - private static void writePadding(Stream dst, byte paddingByte, long paddingLen) - { - byte[] paddingData = new byte[paddingLen]; - memset(paddingData, paddingByte, paddingLen); - dst.Write(paddingData, 0x00, paddingData.Length); - } - private static void writeStringWithPadding(Stream dst, string str, int padSize, byte padByte = 0x78) - { - int StrLen = str.Length; - if (StrLen > padSize) - { - StrLen = padSize; - } - - int PaddingLen = (padSize - StrLen) - 1; - writeString(dst, str, StrLen); - dst.WriteByte(0x00); - writePadding(dst, padByte, PaddingLen); - } - - private static byte[] aes_ecb_decrypt(byte[] cipherText, byte[] KEY, int size = -1) - { - if (size < 0) - { - size = cipherText.Length; - } - - MemoryStream ms = new MemoryStream(); - - Aes alg = Aes.Create(); - alg.Mode = CipherMode.ECB; - alg.Padding = PaddingMode.None; - alg.KeySize = 256; - alg.BlockSize = 128; - alg.Key = KEY; - CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write); - cs.Write(cipherText, 0, size); - cs.Close(); - byte[] plainText = ms.ToArray(); - return plainText; - } - - private static byte[] aes_cbc_decrypt(byte[] cipherData, byte[] IV, byte[] Key) - { - MemoryStream ms = new MemoryStream(); - Aes alg = Aes.Create(); - alg.Mode = CipherMode.CBC; - alg.Padding = PaddingMode.None; - alg.KeySize = 256; - alg.BlockSize = 128; - alg.Key = Key; - alg.IV = IV; - CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write); - cs.Write(cipherData, 0, cipherData.Length); - cs.Close(); - byte[] decryptedData = ms.ToArray(); - return decryptedData; - } - private static byte[] aes_cbc_encrypt(byte[] plainText, byte[] IV, byte[] KEY, int size = -1) - { - if (size < 0) - { - size = plainText.Length; - } - - MemoryStream ms = new MemoryStream(); - - Aes alg = Aes.Create(); - alg.Mode = CipherMode.CBC; - alg.Padding = PaddingMode.None; - alg.KeySize = 256; - alg.BlockSize = 128; - alg.Key = KEY; - alg.IV = IV; - CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write); - cs.Write(plainText, 0, size); - cs.Close(); - byte[] cipherText = ms.ToArray(); - return cipherText; - } - - - public static void CreatePsvmd(Stream OutputStream, Stream EncryptedPsvimg, long ContentSize, string BackupType,byte[] Key) - { - byte[] IV = new byte[PSVIMGConstants.AES_BLOCK_SIZE]; - EncryptedPsvimg.Seek(0x00, SeekOrigin.Begin); - EncryptedPsvimg.Read(IV, 0x00, IV.Length); - IV = aes_ecb_decrypt(IV, Key); - MemoryStream ms = new MemoryStream(); - - writeUInt32(ms, 0xFEE1900D); // magic - writeUInt32(ms, 0x2); // type - writeUInt64(ms, 0x03000000); // fw ver - ms.Write(new byte[0x10], 0x00, 0x10); // PSID - writeStringWithPadding(ms, BackupType, 0x40, 0x00); //backup type - writeInt64(ms, EncryptedPsvimg.Length); // total size - writeUInt64(ms, 0x2); //version - writeInt64(ms, ContentSize); // content size - ms.Write(IV, 0x00, 0x10); // IV - writeUInt64(ms, 0x00); //ux0 info - writeUInt64(ms, 0x00); //ur0 info - writeUInt64(ms, 0x00); //unused 98 - writeUInt64(ms, 0x00); //unused A0 - writeUInt32(ms, 0x1); //add data - - ms.Seek(0x00, SeekOrigin.Begin); - byte[] psvMd = ms.ToArray(); - ms.Close(); - - ms = new MemoryStream(); - byte[] psvMdCompressed = ZlibStream.CompressBuffer(psvMd); - psvMdCompressed[0x1] = 0x9C; - ms.Write(psvMdCompressed, 0x00, psvMdCompressed.Length); - - SHA256 sha = SHA256.Create(); - byte[] shadata = sha.ComputeHash(psvMdCompressed); - ms.Write(shadata, 0x00, shadata.Length); - - int PaddingLen = Convert.ToInt32(PSVIMGConstants.AES_BLOCK_SIZE - (ms.Length & (PSVIMGConstants.AES_BLOCK_SIZE - 1))); - writePadding(ms, 0x00, PaddingLen); - - writeInt32(ms, PaddingLen); //Padding Length - writeUInt32(ms, 0x00); - writeInt64(ms, (ms.Length+0x8)+IV.Length); - ms.Seek(0x00, SeekOrigin.Begin); - byte[] toEncrypt = ms.ToArray(); - ms.Close(); - - byte[] EncryptedData = aes_cbc_encrypt(toEncrypt, IV, Key); - OutputStream.Write(IV, 0x00, IV.Length); - OutputStream.Write(EncryptedData, 0x00, EncryptedData.Length); - return; - } - - - public static byte[] DecryptPsvmd(Stream PsvMdFile, byte[] Key) - { - byte[] IV = new byte[PSVIMGConstants.AES_BLOCK_SIZE]; - PsvMdFile.Read(IV, 0x00, IV.Length); - byte[] remaining = new byte[PsvMdFile.Length - IV.Length]; - PsvMdFile.Read(remaining, 0x00, remaining.Length); - byte[] zlibCompressed = aes_cbc_decrypt(remaining, IV, Key); - return zlibCompressed; - // return ZlibStream.UncompressBuffer(zlibCompressed); - } - } -} +using Ionic.Zlib; +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +namespace Vita.PsvImgTools +{ + public class PSVMDBuilder + { + private static void memset(byte[] buf, byte content, long length) + { + for (int i = 0; i < length; i++) + { + buf[i] = content; + } + } + + private static void writeUInt64(Stream dst, ulong value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x8); + } + private static void writeInt64(Stream dst, long value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x8); + } + private static void writeUInt16(Stream dst, ushort value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x2); + } + private static void writeInt16(Stream dst, short value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x2); + } + + private static void writeInt32(Stream dst, int value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x4); + } + private static void writeUInt32(Stream dst, uint value) + { + byte[] ValueBytes = BitConverter.GetBytes(value); + dst.Write(ValueBytes, 0x00, 0x4); + } + + + private static void writeString(Stream dst, string str, int len = -1) + { + if (len < 0) + { + len = str.Length; + } + + byte[] StrBytes = Encoding.UTF8.GetBytes(str); + dst.Write(StrBytes, 0x00, len); + } + + private static void writePadding(Stream dst, byte paddingByte, long paddingLen) + { + byte[] paddingData = new byte[paddingLen]; + memset(paddingData, paddingByte, paddingLen); + dst.Write(paddingData, 0x00, paddingData.Length); + } + private static void writeStringWithPadding(Stream dst, string str, int padSize, byte padByte = 0x78) + { + int StrLen = str.Length; + if (StrLen > padSize) + { + StrLen = padSize; + } + + int PaddingLen = padSize - StrLen - 1; + writeString(dst, str, StrLen); + dst.WriteByte(0x00); + writePadding(dst, padByte, PaddingLen); + } + + private static byte[] aes_ecb_decrypt(byte[] cipherText, byte[] KEY, int size = -1) + { + if (size < 0) + { + size = cipherText.Length; + } + + MemoryStream ms = new MemoryStream(); + + Aes alg = Aes.Create(); + alg.Mode = CipherMode.ECB; + alg.Padding = PaddingMode.None; + alg.KeySize = 256; + alg.BlockSize = 128; + alg.Key = KEY; + CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write); + cs.Write(cipherText, 0, size); + cs.Close(); + byte[] plainText = ms.ToArray(); + return plainText; + } + + private static byte[] aes_cbc_decrypt(byte[] cipherData, byte[] IV, byte[] Key) + { + MemoryStream ms = new MemoryStream(); + Aes alg = Aes.Create(); + alg.Mode = CipherMode.CBC; + alg.Padding = PaddingMode.None; + alg.KeySize = 256; + alg.BlockSize = 128; + alg.Key = Key; + alg.IV = IV; + CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write); + cs.Write(cipherData, 0, cipherData.Length); + cs.Close(); + byte[] decryptedData = ms.ToArray(); + return decryptedData; + } + private static byte[] aes_cbc_encrypt(byte[] plainText, byte[] IV, byte[] KEY, int size = -1) + { + if (size < 0) + { + size = plainText.Length; + } + + MemoryStream ms = new MemoryStream(); + + Aes alg = Aes.Create(); + alg.Mode = CipherMode.CBC; + alg.Padding = PaddingMode.None; + alg.KeySize = 256; + alg.BlockSize = 128; + alg.Key = KEY; + alg.IV = IV; + CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write); + cs.Write(plainText, 0, size); + cs.Close(); + byte[] cipherText = ms.ToArray(); + return cipherText; + } + + + public static void CreatePsvmd(Stream OutputStream, Stream EncryptedPsvimg, long ContentSize, string BackupType, byte[] Key) + { + byte[] IV = new byte[PSVIMGConstants.AES_BLOCK_SIZE]; + EncryptedPsvimg.Seek(0x00, SeekOrigin.Begin); + EncryptedPsvimg.Read(IV, 0x00, IV.Length); + IV = aes_ecb_decrypt(IV, Key); + MemoryStream ms = new MemoryStream(); + + writeUInt32(ms, 0xFEE1900D); // magic + writeUInt32(ms, 0x2); // type + writeUInt64(ms, 0x03000000); // fw ver + ms.Write(new byte[0x10], 0x00, 0x10); // PSID + writeStringWithPadding(ms, BackupType, 0x40, 0x00); //backup type + writeInt64(ms, EncryptedPsvimg.Length); // total size + writeUInt64(ms, 0x2); //version + writeInt64(ms, ContentSize); // content size + ms.Write(IV, 0x00, 0x10); // IV + writeUInt64(ms, 0x00); //ux0 info + writeUInt64(ms, 0x00); //ur0 info + writeUInt64(ms, 0x00); //unused 98 + writeUInt64(ms, 0x00); //unused A0 + writeUInt32(ms, 0x1); //add data + + ms.Seek(0x00, SeekOrigin.Begin); + byte[] psvMd = ms.ToArray(); + ms.Close(); + + ms = new MemoryStream(); + byte[] psvMdCompressed = ZlibStream.CompressBuffer(psvMd); + psvMdCompressed[0x1] = 0x9C; + ms.Write(psvMdCompressed, 0x00, psvMdCompressed.Length); + + SHA256 sha = SHA256.Create(); + byte[] shadata = sha.ComputeHash(psvMdCompressed); + ms.Write(shadata, 0x00, shadata.Length); + + int PaddingLen = Convert.ToInt32(PSVIMGConstants.AES_BLOCK_SIZE - (ms.Length & PSVIMGConstants.AES_BLOCK_SIZE - 1)); + writePadding(ms, 0x00, PaddingLen); + + writeInt32(ms, PaddingLen); //Padding Length + writeUInt32(ms, 0x00); + writeInt64(ms, ms.Length + 0x8 + IV.Length); + ms.Seek(0x00, SeekOrigin.Begin); + byte[] toEncrypt = ms.ToArray(); + ms.Close(); + + byte[] EncryptedData = aes_cbc_encrypt(toEncrypt, IV, Key); + OutputStream.Write(IV, 0x00, IV.Length); + OutputStream.Write(EncryptedData, 0x00, EncryptedData.Length); + return; + } + + + public static byte[] DecryptPsvmd(Stream PsvMdFile, byte[] Key) + { + byte[] IV = new byte[PSVIMGConstants.AES_BLOCK_SIZE]; + PsvMdFile.Read(IV, 0x00, IV.Length); + byte[] remaining = new byte[PsvMdFile.Length - IV.Length]; + PsvMdFile.Read(remaining, 0x00, remaining.Length); + byte[] zlibCompressed = aes_cbc_decrypt(remaining, IV, Key); + return zlibCompressed; + // return ZlibStream.UncompressBuffer(zlibCompressed); + } + } +} diff --git a/Vita/Vita.csproj b/Vita/Vita.csproj new file mode 100644 index 0000000..8820e9b --- /dev/null +++ b/Vita/Vita.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/packages/BouncyCastle.1.8.5/BouncyCastle.1.8.5.nupkg b/packages/BouncyCastle.1.8.5/BouncyCastle.1.8.5.nupkg deleted file mode 100644 index f6d7c2a..0000000 Binary files a/packages/BouncyCastle.1.8.5/BouncyCastle.1.8.5.nupkg and /dev/null differ diff --git a/packages/BouncyCastle.1.8.5/README.md b/packages/BouncyCastle.1.8.5/README.md deleted file mode 100644 index 270d9cc..0000000 --- a/packages/BouncyCastle.1.8.5/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# The Bouncy Castle Crypto Package For C Sharp - -The Bouncy Castle Crypto package is a C\# implementation of cryptographic algorithms and protocols, it was developed by the Legion of the Bouncy Castle, a registered Australian Charity, with a little help! The Legion, and the latest goings on with this package, can be found at [http://www.bouncycastle.org](http://www.bouncycastle.org). In addition to providing basic cryptography algorithms, the package also provides support for CMS, TSP, X.509 certificate generation and a variety of other standards such as OpenPGP. - -The Legion also gratefully acknowledges the contributions made to this package by others (see [here](http://www.bouncycastle.org/csharp/contributors.html) for the current list). If you would like to contribute to our efforts please feel free to get in touch with us or visit our [donations page](https://www.bouncycastle.org/donate), sponsor some specific work, or purchase a support contract through [Crypto Workshop](http://www.cryptoworkshop.com). - -Except where otherwise stated, this software is distributed under a license based on the MIT X Consortium license. To view the license, [see here](http://www.bouncycastle.org/licence.html). The OpenPGP library also includes a modified BZIP2 library which is licensed under the [Apache Software License, Version 2.0](http://www.apache.org/licenses/). - -**Note**: this source tree is not the FIPS version of the APIs - if you are interested in our FIPS version please contact us directly at [office@bouncycastle.org](mailto:office@bouncycastle.org). - -## Mailing Lists - -For those who are interested, there are 2 mailing lists for participation in this project. To subscribe use the links below and include the word subscribe in the message body. (To unsubscribe, replace **subscribe** with **unsubscribe** in the message body) - -* [announce-crypto-csharp-request@bouncycastle.org](mailto:announce-crypto-csharp-request@bouncycastle.org) - This mailing list is for new release announcements only, general subscribers cannot post to it. -* [dev-crypto-csharp-request@bouncycastle.org](mailto:dev-crypto-csharp-request@bouncycastle.org) - This mailing list is for discussion of development of the package. This includes bugs, comments, requests for enhancements, questions about use or operation. - -**NOTE:**You need to be subscribed to send mail to the above mailing list. - -## Feedback - -If you want to provide feedback directly to the members of **The Legion** then please use [feedback-crypto@bouncycastle.org](mailto:feedback-crypto@bouncycastle.org), if you want to help this project survive please consider [donating](https://www.bouncycastle.org/donate). - -For bug reporting/requests you can report issues here on github, via feedback-crypto if required, and we also have a [Jira issue tracker](http://www.bouncycastle.org/jira). We will accept pull requests based on this repository as well. - -## Finally - -Enjoy! diff --git a/packages/BouncyCastle.1.8.5/lib/BouncyCastle.Crypto.dll b/packages/BouncyCastle.1.8.5/lib/BouncyCastle.Crypto.dll deleted file mode 100644 index 05036dd..0000000 Binary files a/packages/BouncyCastle.1.8.5/lib/BouncyCastle.Crypto.dll and /dev/null differ diff --git a/packages/DotNetZip.1.13.4/DotNetZip.1.13.4.nupkg b/packages/DotNetZip.1.13.4/DotNetZip.1.13.4.nupkg deleted file mode 100644 index 611052b..0000000 Binary files a/packages/DotNetZip.1.13.4/DotNetZip.1.13.4.nupkg and /dev/null differ diff --git a/packages/DotNetZip.1.13.4/lib/net40/DotNetZip.dll b/packages/DotNetZip.1.13.4/lib/net40/DotNetZip.dll deleted file mode 100644 index 2b6455d..0000000 Binary files a/packages/DotNetZip.1.13.4/lib/net40/DotNetZip.dll and /dev/null differ diff --git a/packages/DotNetZip.1.13.4/lib/net40/DotNetZip.pdb b/packages/DotNetZip.1.13.4/lib/net40/DotNetZip.pdb deleted file mode 100644 index 87522e7..0000000 Binary files a/packages/DotNetZip.1.13.4/lib/net40/DotNetZip.pdb and /dev/null differ diff --git a/packages/DotNetZip.1.13.4/lib/net40/DotNetZip.xml b/packages/DotNetZip.1.13.4/lib/net40/DotNetZip.xml deleted file mode 100644 index bcb5bbf..0000000 --- a/packages/DotNetZip.1.13.4/lib/net40/DotNetZip.xml +++ /dev/null @@ -1,18529 +0,0 @@ - - - - DotNetZip - - - - - Delivers the remaining bits, left-aligned, in a byte. - - - - This is valid only if NumRemainingBits is less than 8; - in other words it is valid only after a call to Flush(). - - - - - - Reset the BitWriter. - - - - This is useful when the BitWriter writes into a MemoryStream, and - is used by a BZip2Compressor, which itself is re-used for multiple - distinct data blocks. - - - - - - Write some number of bits from the given value, into the output. - - - - The nbits value should be a max of 25, for safety. For performance - reasons, this method does not check! - - - - - - Write a full 8-bit byte into the output. - - - - - Write four 8-bit bytes into the output. - - - - - Write all available byte-aligned bytes. - - - - This method writes no new output, but flushes any accumulated - bits. At completion, the accumulator may contain up to 7 - bits. - - - This is necessary when re-assembling output from N independent - compressors, one for each of N blocks. The output of any - particular compressor will in general have some fragment of a byte - remaining. This fragment needs to be accumulated into the - parent BZip2OutputStream. - - - - - - Writes all available bytes, and emits padding for the final byte as - necessary. This must be the last method invoked on an instance of - BitWriter. - - - - Knuth's increments seem to work better than Incerpi-Sedgewick here. - Possibly because the number of elems to sort is usually small, typically - <= 20. - - - - BZip2Compressor writes its compressed data out via a BitWriter. This - is necessary because BZip2 does byte shredding. - - - - - The number of uncompressed bytes being held in the buffer. - - - - I am thinking this may be useful in a Stream that uses this - compressor class. In the Close() method on the stream it could - check this value to see if anything has been written at all. You - may think the stream could easily track the number of bytes it - wrote, which would eliminate the need for this. But, there is the - case where the stream writes a complete block, and it is full, and - then writes no more. In that case the stream may want to check. - - - - - - Accept new bytes into the compressor data buffer - - - - This method does the first-level (cheap) run-length encoding, and - stores the encoded data into the rle block. - - - - - - Process one input byte into the block. - - - - - To "process" the byte means to do the run-length encoding. - There are 3 possible return values: - - 0 - the byte was not written, in other words, not - encoded into the block. This happens when the - byte b would require the start of a new run, and - the block has no more room for new runs. - - 1 - the byte was written, and the block is not full. - - 2 - the byte was written, and the block is full. - - - - 0 if the byte was not written, non-zero if written. - - - - Append one run to the output block. - - - - - This compressor does run-length-encoding before BWT and etc. This - method simply appends a run to the output block. The append always - succeeds. The return value indicates whether the block is full: - false (not full) implies that at least one additional run could be - processed. - - - true if the block is now full; otherwise false. - - - - Compress the data that has been placed (Run-length-encoded) into the - block. The compressed data goes into the CompressedBytes array. - - - - Side effects: 1. fills the CompressedBytes array. 2. sets the - AvailableBytesOut property. - - - - - This is the most hammered method of this class. - -

- This is the version using unrolled loops. -

-
- - Method "mainQSort3", file "blocksort.c", BZip2 1.0.2 - - - Array instance identical to sfmap, both are used only - temporarily and independently, so we do not need to allocate - additional memory. - - - - A read-only decorator stream that performs BZip2 decompression on Read. - - - - - Compressor State - - - - - Create a BZip2InputStream, wrapping it around the given input Stream. - - - - The input stream will be closed when the BZip2InputStream is closed. - - - The stream from which to read compressed data - - - - Create a BZip2InputStream with the given stream, and - specifying whether to leave the wrapped stream open when - the BZip2InputStream is closed. - - The stream from which to read compressed data - - Whether to leave the input stream open, when the BZip2InputStream closes. - - - - - This example reads a bzip2-compressed file, decompresses it, - and writes the decompressed data into a newly created file. - - - var fname = "logfile.log.bz2"; - using (var fs = File.OpenRead(fname)) - { - using (var decompressor = new Ionic.BZip2.BZip2InputStream(fs)) - { - var outFname = fname + ".decompressed"; - using (var output = File.Create(outFname)) - { - byte[] buffer = new byte[2048]; - int n; - while ((n = decompressor.Read(buffer, 0, buffer.Length)) > 0) - { - output.Write(buffer, 0, n); - } - } - } - } - - - - - - Read data from the stream. - - - - - To decompress a BZip2 data stream, create a BZip2InputStream, - providing a stream that reads compressed data. Then call Read() on - that BZip2InputStream, and the data read will be decompressed - as you read. - - - - A BZip2InputStream can be used only for Read(), not for Write(). - - - - The buffer into which the read data should be placed. - the offset within that data array to put the first byte read. - the number of bytes to read. - the number of bytes actually read - - - - Read a single byte from the stream. - - the byte read from the stream, or -1 if EOF - - - - Indicates whether the stream can be read. - - - The return value depends on whether the captive stream supports reading. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value depends on whether the captive stream supports writing. - - - - - Flush the stream. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the - total number of uncompressed bytes read in. - - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - this is irrelevant, since it will always throw! - irrelevant! - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - - - - Calling this method always throws a . - - this parameter is never used - this parameter is never used - this parameter is never used - - - - Dispose the stream. - - - indicates whether the Dispose method was invoked by user code. - - - - - Close the stream. - - - - - Read n bits from input, right justifying the result. - - - - For example, if you read 1 bit, the result is either 0 - or 1. - - - - The number of bits to read, always between 1 and 32. - - - - Called by createHuffmanDecodingTables() exclusively. - - - Called by recvDecodingTables() exclusively. - - - Freq table collected to save a pass over the data during - decompression. - - - Initializes the tt array. - - This method is called when the required length of the array is known. - I don't initialize it at construction time to avoid unneccessary - memory allocation when compressing small files. - - - - A write-only decorator stream that compresses data as it is - written using the BZip2 algorithm. - - - - - Constructs a new BZip2OutputStream, that sends its - compressed output to the given output stream. - - - - The destination stream, to which compressed output will be sent. - - - - - This example reads a file, then compresses it with bzip2 file, - and writes the compressed data into a newly created file. - - - var fname = "logfile.log"; - using (var fs = File.OpenRead(fname)) - { - var outFname = fname + ".bz2"; - using (var output = File.Create(outFname)) - { - using (var compressor = new Ionic.BZip2.BZip2OutputStream(output)) - { - byte[] buffer = new byte[2048]; - int n; - while ((n = fs.Read(buffer, 0, buffer.Length)) > 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - - - - Constructs a new BZip2OutputStream with specified blocksize. - - the destination stream. - - The blockSize in units of 100000 bytes. - The valid range is 1..9. - - - - - Constructs a new BZip2OutputStream. - - the destination stream. - - whether to leave the captive stream open upon closing this stream. - - - - - Constructs a new BZip2OutputStream with specified blocksize, - and explicitly specifies whether to leave the wrapped stream open. - - - the destination stream. - - The blockSize in units of 100000 bytes. - The valid range is 1..9. - - - whether to leave the captive stream open upon closing this stream. - - - - - Close the stream. - - - - This may or may not close the underlying stream. Check the - constructors that accept a bool value. - - - - - - Flush the stream. - - - - - The blocksize parameter specified at construction time. - - - - - Write data to the stream. - - - - - Use the BZip2OutputStream to compress data while writing: - create a BZip2OutputStream with a writable output stream. - Then call Write() on that BZip2OutputStream, providing - uncompressed data as input. The data sent to the output stream will - be the compressed form of the input data. - - - - A BZip2OutputStream can be used only for Write() not for Read(). - - - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Indicates whether the stream can be read. - - - The return value is always false. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value should always be true, unless and until the - object is disposed and closed. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the - total number of uncompressed bytes written through. - - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - this is irrelevant, since it will always throw! - irrelevant! - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - - - - Calling this method always throws a . - - this parameter is never used - this parameter is never used - this parameter is never used - never returns anything; always throws - - - - A write-only decorator stream that compresses data as it is - written using the BZip2 algorithm. This stream compresses by - block using multiple threads. - - - This class performs BZIP2 compression through writing. For - more information on the BZIP2 algorithm, see - . - - - - This class is similar to , - except that this implementation uses an approach that employs multiple - worker threads to perform the compression. On a multi-cpu or multi-core - computer, the performance of this class can be significantly higher than - the single-threaded BZip2OutputStream, particularly for larger streams. - How large? Anything over 10mb is a good candidate for parallel - compression. - - - - The tradeoff is that this class uses more memory and more CPU than the - vanilla BZip2OutputStream. Also, for small files, the - ParallelBZip2OutputStream can be much slower than the vanilla - BZip2OutputStream, because of the overhead associated to using the - thread pool. - - - - - - - Constructs a new ParallelBZip2OutputStream, that sends its - compressed output to the given output stream. - - - - The destination stream, to which compressed output will be sent. - - - - - This example reads a file, then compresses it with bzip2 file, - and writes the compressed data into a newly created file. - - - var fname = "logfile.log"; - using (var fs = File.OpenRead(fname)) - { - var outFname = fname + ".bz2"; - using (var output = File.Create(outFname)) - { - using (var compressor = new Ionic.BZip2.ParallelBZip2OutputStream(output)) - { - byte[] buffer = new byte[2048]; - int n; - while ((n = fs.Read(buffer, 0, buffer.Length)) > 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - - - - Constructs a new ParallelBZip2OutputStream with specified blocksize. - - the destination stream. - - The blockSize in units of 100000 bytes. - The valid range is 1..9. - - - - - Constructs a new ParallelBZip2OutputStream. - - the destination stream. - - whether to leave the captive stream open upon closing this stream. - - - - - Constructs a new ParallelBZip2OutputStream with specified blocksize, - and explicitly specifies whether to leave the wrapped stream open. - - - the destination stream. - - The blockSize in units of 100000 bytes. - The valid range is 1..9. - - - whether to leave the captive stream open upon closing this stream. - - - - - The maximum number of concurrent compression worker threads to use. - - - - - This property sets an upper limit on the number of concurrent worker - threads to employ for compression. The implementation of this stream - employs multiple threads from the .NET thread pool, via - ThreadPool.QueueUserWorkItem(), to compress the incoming data by - block. As each block of data is compressed, this stream re-orders the - compressed blocks and writes them to the output stream. - - - - A higher number of workers enables a higher degree of - parallelism, which tends to increase the speed of compression on - multi-cpu computers. On the other hand, a higher number of buffer - pairs also implies a larger memory consumption, more active worker - threads, and a higher cpu utilization for any compression. This - property enables the application to limit its memory consumption and - CPU utilization behavior depending on requirements. - - - - By default, DotNetZip allocates 4 workers per CPU core, subject to the - upper limit specified in this property. For example, suppose the - application sets this property to 16. Then, on a machine with 2 - cores, DotNetZip will use 8 workers; that number does not exceed the - upper limit specified by this property, so the actual number of - workers used will be 4 * 2 = 8. On a machine with 4 cores, DotNetZip - will use 16 workers; again, the limit does not apply. On a machine - with 8 cores, DotNetZip will use 16 workers, because of the limit. - - - - For each compression "worker thread" that occurs in parallel, there is - up to 2mb of memory allocated, for buffering and processing. The - actual number depends on the property. - - - - CPU utilization will also go up with additional workers, because a - larger number of buffer pairs allows a larger number of background - threads to compress in parallel. If you find that parallel - compression is consuming too much memory or CPU, you can adjust this - value downward. - - - - The default value is 16. Different values may deliver better or - worse results, depending on your priorities and the dynamic - performance characteristics of your storage and compute resources. - - - - The application can set this value at any time, but it is effective - only before the first call to Write(), which is when the buffers are - allocated. - - - - - - Close the stream. - - - - This may or may not close the underlying stream. Check the - constructors that accept a bool value. - - - - - - Flush the stream. - - - - - The blocksize parameter specified at construction time. - - - - - Write data to the stream. - - - - - Use the ParallelBZip2OutputStream to compress data while - writing: create a ParallelBZip2OutputStream with a writable - output stream. Then call Write() on that - ParallelBZip2OutputStream, providing uncompressed data as - input. The data sent to the output stream will be the compressed - form of the input data. - - - - A ParallelBZip2OutputStream can be used only for - Write() not for Read(). - - - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Indicates whether the stream can be read. - - - The return value is always false. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value depends on whether the captive stream supports writing. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the - total number of uncompressed bytes written through. - - - - - The total number of bytes written out by the stream. - - - This value is meaningful only after a call to Close(). - - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - this is irrelevant, since it will always throw! - irrelevant! - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - - - - Calling this method always throws a . - - this parameter is never used - this parameter is never used - this parameter is never used - never returns anything; always throws - - - - Returns the "random" number at a specific index. - - the index - the random number - - - - An enum that provides the different self-extractor flavors - - - - - A self-extracting zip archive that runs from the console or - command line. - - - - - A self-extracting zip archive that presents a graphical user - interface when it is executed. - - - - - The options for generating a self-extracting archive. - - - - - The type of SFX to create. - - - - - The command to run after extraction. - - - - - This is optional. Leave it empty (null in C# or Nothing in - VB) to run no command after extraction. - - - - If it is non-empty, the SFX will execute the command specified in this - string on the user's machine, and using the extract directory as the - working directory for the process, after unpacking the archive. The - program to execute can include a path, if you like. If you want to execute - a program that accepts arguments, specify the program name, followed by a - space, and then the arguments for the program, each separated by a space, - just as you would on a normal command line. Example: program.exe arg1 - arg2. The string prior to the first space will be taken as the - program name, and the string following the first space specifies the - arguments to the program. - - - - If you want to execute a program that has a space in the name or path of - the file, surround the program name in double-quotes. The first character - of the command line should be a double-quote character, and there must be - a matching double-quote following the end of the program file name. Any - optional arguments to the program follow that, separated by - spaces. Example: "c:\project files\program name.exe" arg1 arg2. - - - - If the flavor of the SFX is SelfExtractorFlavor.ConsoleApplication, - then the SFX starts a new process, using this string as the post-extract - command line. The SFX waits for the process to exit. The exit code of - the post-extract command line is returned as the exit code of the - command-line self-extractor exe. A non-zero exit code is typically used to - indicated a failure by the program. In the case of an SFX, a non-zero exit - code may indicate a failure during extraction, OR, it may indicate a - failure of the run-after-extract program if specified, OR, it may indicate - the run-after-extract program could not be fuond. There is no way to - distinguish these conditions from the calling shell, aside from parsing - the output of the SFX. If you have Quiet set to true, you may not - see error messages, if a problem occurs. - - - - If the flavor of the SFX is - SelfExtractorFlavor.WinFormsApplication, then the SFX starts a new - process, using this string as the post-extract command line, and using the - extract directory as the working directory for the process. The SFX does - not wait for the command to complete, and does not check the exit code of - the program. If the run-after-extract program cannot be fuond, a message - box is displayed indicating that fact. - - - - You can specify environment variables within this string, with a format like - %NAME%. The value of these variables will be expanded at the time - the SFX is run. Example: %WINDIR%\system32\xcopy.exe may expand at - runtime to c:\Windows\System32\xcopy.exe. - - - - By combining this with the RemoveUnpackedFilesAfterExecute - flag, you can create an SFX that extracts itself, runs a file that - was extracted, then deletes all the files that were extracted. If - you want it to run "invisibly" then set Flavor to - SelfExtractorFlavor.ConsoleApplication, and set Quiet - to true. The user running such an EXE will see a console window - appear, then disappear quickly. You may also want to specify the - default extract location, with DefaultExtractDirectory. - - - - If you set Flavor to - SelfExtractorFlavor.WinFormsApplication, and set Quiet to - true, then a GUI with progressbars is displayed, but it is - "non-interactive" - it accepts no input from the user. Instead the SFX - just automatically unpacks and exits. - - - - - - - The default extract directory the user will see when - running the self-extracting archive. - - - - - Passing null (or Nothing in VB) here will cause the Self Extractor to use - the the user's personal directory () for the default extract - location. - - - - This is only a default location. The actual extract location will be - settable on the command line when the SFX is executed. - - - - You can specify environment variables within this string, - with %NAME%. The value of these variables will be - expanded at the time the SFX is run. Example: - %USERPROFILE%\Documents\unpack may expand at runtime to - c:\users\melvin\Documents\unpack. - - - - - - The name of an .ico file in the filesystem to use for the application icon - for the generated SFX. - - - - - Normally, DotNetZip will embed an "zipped folder" icon into the generated - SFX. If you prefer to use a different icon, you can specify it here. It - should be a .ico file. This file is passed as the /win32icon - option to the csc.exe compiler when constructing the SFX file. - - - - - - - Whether the ConsoleApplication SFX will be quiet during extraction. - - - - - This option affects the way the generated SFX runs. By default it is - false. When you set it to true,... - - - - - Flavor - Behavior - - - - ConsoleApplication - no messages will be emitted during successful - operation. Double-clicking the SFX in Windows - Explorer or as an attachment in an email will cause a console - window to appear briefly, before it disappears. If you run the - ConsoleApplication SFX from the cmd.exe prompt, it runs as a - normal console app; by default, because it is quiet, it displays - no messages to the console. If you pass the -v+ command line - argument to the Console SFX when you run it, you will get verbose - messages to the console. - - - - - WinFormsApplication - the SFX extracts automatically when the application - is launched, with no additional user input. - - - - - - - When you set it to false,... - - - - - Flavor - Behavior - - - - ConsoleApplication - the extractor will emit a - message to the console for each entry extracted. - - When double-clicking to launch the SFX, the console window will - remain, and the SFX will emit a message for each file as it - extracts. The messages fly by quickly, they won't be easily - readable, unless the extracted files are fairly large. - - - - - - WinFormsApplication - the SFX presents a forms UI and allows the user to select - options before extracting. - - - - - - - - - - Specify what the self-extractor will do when extracting an entry - would overwrite an existing file. - - - - The default behavvior is to Throw. - - - - - - Whether to remove the files that have been unpacked, after executing the - PostExtractCommandLine. - - - - - If true, and if there is a - PostExtractCommandLine, and if the command runs successfully, - then the files that the SFX unpacked will be removed, afterwards. If - the command does not complete successfully (non-zero return code), - that is interpreted as a failure, and the extracted files will not be - removed. - - - - Setting this flag, and setting Flavor to - SelfExtractorFlavor.ConsoleApplication, and setting Quiet to - true, results in an SFX that extracts itself, runs a file that was - extracted, then deletes all the files that were extracted, with no - intervention by the user. You may also want to specify the default - extract location, with DefaultExtractDirectory. - - - - - - - The file version number to embed into the generated EXE. It will show up, for - example, during a mouseover in Windows Explorer. - - - - - - The product version to embed into the generated EXE. It will show up, for - example, during a mouseover in Windows Explorer. - - - - You can use any arbitrary string, but a human-readable version number is - recommended. For example "v1.2 alpha" or "v4.2 RC2". If you specify nothing, - then there is no product version embedded into the EXE. - - - - - - The copyright notice, if any, to embed into the generated EXE. - - - - It will show up, for example, while viewing properties of the file in - Windows Explorer. You can use any arbitrary string, but typically you - want something like "Copyright � Dino Chiesa 2011". - - - - - - The description to embed into the generated EXE. - - - - Use any arbitrary string. This text will be displayed during a - mouseover in Windows Explorer. If you specify nothing, then the string - "DotNetZip SFX Archive" is embedded into the EXE as the description. - - - - - - The product name to embed into the generated EXE. - - - - Use any arbitrary string. This text will be displayed - while viewing properties of the EXE file in - Windows Explorer. - - - - - - The title to display in the Window of a GUI SFX, while it extracts. - - - - - By default the title show in the GUI window of a self-extractor - is "DotNetZip Self-extractor (http://DotNetZip.codeplex.com/)". - You can change that by setting this property before saving the SFX. - - - - This property has an effect only when producing a Self-extractor - of flavor SelfExtractorFlavor.WinFormsApplication. - - - - - - - Additional options for the csc.exe compiler, when producing the SFX - EXE. - - - - - - The ZipFile type represents a zip archive file. - - - - - This is the main type in the DotNetZip class library. This class reads and - writes zip files, as defined in the specification - for zip files described by PKWare. The compression for this - implementation is provided by a managed-code version of Zlib, included with - DotNetZip in the classes in the Ionic.Zlib namespace. - - - - This class provides a general purpose zip file capability. Use it to read, - create, or update zip files. When you want to create zip files using a - Stream type to write the zip file, you may want to consider the class. - - - - Both the ZipOutputStream class and the ZipFile class can - be used to create zip files. Both of them support many of the common zip - features, including Unicode, different compression methods and levels, - and ZIP64. They provide very similar performance when creating zip - files. - - - - The ZipFile class is generally easier to use than - ZipOutputStream and should be considered a higher-level interface. For - example, when creating a zip file via calls to the PutNextEntry() and - Write() methods on the ZipOutputStream class, the caller is - responsible for opening the file, reading the bytes from the file, writing - those bytes into the ZipOutputStream, setting the attributes on the - ZipEntry, and setting the created, last modified, and last accessed - timestamps on the zip entry. All of these things are done automatically by a - call to ZipFile.AddFile(). - For this reason, the ZipOutputStream is generally recommended for use - only when your application emits arbitrary data, not necessarily data from a - filesystem file, directly into a zip file, and does so using a Stream - metaphor. - - - - Aside from the differences in programming model, there are other - differences in capability between the two classes. - - - - - ZipFile can be used to read and extract zip files, in addition to - creating zip files. ZipOutputStream cannot read zip files. If you want - to use a stream to read zip files, check out the class. - - - - ZipOutputStream does not support the creation of segmented or spanned - zip files. - - - - ZipOutputStream cannot produce a self-extracting archive. - - - - - Be aware that the ZipFile class implements the interface. In order for ZipFile to - produce a valid zip file, you use use it within a using clause (Using - in VB), or call the Dispose() method explicitly. See the examples - for how to employ a using clause. - - - - - - - Saves the ZipFile instance to a self-extracting zip archive. - - - - - - The generated exe image will execute on any machine that has the .NET - Framework 4.0 installed on it. The generated exe image is also a - valid ZIP file, readable with DotNetZip or another Zip library or tool - such as WinZip. - - - - There are two "flavors" of self-extracting archive. The - WinFormsApplication version will pop up a GUI and allow the - user to select a target directory into which to extract. There's also - a checkbox allowing the user to specify to overwrite existing files, - and another checkbox to allow the user to request that Explorer be - opened to see the extracted files after extraction. The other flavor - is ConsoleApplication. A self-extractor generated with that - flavor setting will run from the command line. It accepts command-line - options to set the overwrite behavior, and to specify the target - extraction directory. - - - - There are a few temporary files created during the saving to a - self-extracting zip. These files are created in the directory pointed - to by , which defaults to . These temporary files are - removed upon successful completion of this method. - - - - When a user runs the WinForms SFX, the user's personal directory (Environment.SpecialFolder.Personal) - will be used as the default extract location. If you want to set the - default extract location, you should use the other overload of - SaveSelfExtractor()/ The user who runs the SFX will have the - opportunity to change the extract directory before extracting. When - the user runs the Command-Line SFX, the user must explicitly specify - the directory to which to extract. The .NET Framework 4.0 is required - on the computer when the self-extracting archive is run. - - - - NB: This method is not available in the "Reduced" DotNetZip library. - - - - - - - string DirectoryPath = "c:\\Documents\\Project7"; - using (ZipFile zip = new ZipFile()) - { - zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)); - zip.Comment = "This will be embedded into a self-extracting console-based exe"; - zip.SaveSelfExtractor("archive.exe", SelfExtractorFlavor.ConsoleApplication); - } - - - Dim DirectoryPath As String = "c:\Documents\Project7" - Using zip As New ZipFile() - zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)) - zip.Comment = "This will be embedded into a self-extracting console-based exe" - zip.SaveSelfExtractor("archive.exe", SelfExtractorFlavor.ConsoleApplication) - End Using - - - - - a pathname, possibly fully qualified, to be created. Typically it - will end in an .exe extension. - - Indicates whether a Winforms or Console self-extractor is - desired. - - - - Saves the ZipFile instance to a self-extracting zip archive, using - the specified save options. - - - - - This method saves a self extracting archive, using the specified save - options. These options include the flavor of the SFX, the default extract - directory, the icon file, and so on. See the documentation - for for more - details. - - - - The user who runs the SFX will have the opportunity to change the extract - directory before extracting. If at the time of extraction, the specified - directory does not exist, the SFX will create the directory before - extracting the files. - - - - - - This example saves a WinForms-based self-extracting archive EXE that - will use c:\ExtractHere as the default extract location. The C# code - shows syntax for .NET 3.0, which uses an object initializer for - the SelfExtractorOptions object. - - string DirectoryPath = "c:\\Documents\\Project7"; - using (ZipFile zip = new ZipFile()) - { - zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)); - zip.Comment = "This will be embedded into a self-extracting WinForms-based exe"; - var options = new SelfExtractorOptions - { - Flavor = SelfExtractorFlavor.WinFormsApplication, - DefaultExtractDirectory = "%USERPROFILE%\\ExtractHere", - PostExtractCommandLine = ExeToRunAfterExtract, - SfxExeWindowTitle = "My Custom Window Title", - RemoveUnpackedFilesAfterExecute = true - }; - zip.SaveSelfExtractor("archive.exe", options); - } - - - Dim DirectoryPath As String = "c:\Documents\Project7" - Using zip As New ZipFile() - zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)) - zip.Comment = "This will be embedded into a self-extracting console-based exe" - Dim options As New SelfExtractorOptions() - options.Flavor = SelfExtractorFlavor.WinFormsApplication - options.DefaultExtractDirectory = "%USERPROFILE%\\ExtractHere" - options.PostExtractCommandLine = ExeToRunAfterExtract - options.SfxExeWindowTitle = "My Custom Window Title" - options.RemoveUnpackedFilesAfterExecute = True - zip.SaveSelfExtractor("archive.exe", options) - End Using - - - - The name of the EXE to generate. - provides the options for creating the - Self-extracting archive. - - - - Adds an item, either a file or a directory, to a zip file archive. - - - - - This method is handy if you are adding things to zip archive and don't - want to bother distinguishing between directories or files. Any files are - added as single entries. A directory added through this method is added - recursively: all files and subdirectories contained within the directory - are added to the ZipFile. - - - - The name of the item may be a relative path or a fully-qualified - path. Remember, the items contained in ZipFile instance get written - to the disk only when you call or a similar - save method. - - - - The directory name used for the file within the archive is the same - as the directory name (potentially a relative path) specified in the - . - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - - - This method has two overloads. - - the name of the file or directory to add. - - The ZipEntry added. - - - - Adds an item, either a file or a directory, to a zip file archive, - explicitly specifying the directory path to be used in the archive. - - - - - If adding a directory, the add is recursive on all files and - subdirectories contained within it. - - - The name of the item may be a relative path or a fully-qualified path. - The item added by this call to the ZipFile is not read from the - disk nor written to the zip file archive until the application calls - Save() on the ZipFile. - - - - This version of the method allows the caller to explicitly specify the - directory path to be used in the archive, which would override the - "natural" path of the filesystem file. - - - - Encryption will be used on the file data if the Password has - been set on the ZipFile object, prior to calling this method. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - Thrown if the file or directory passed in does not exist. - - - the name of the file or directory to add. - - - - The name of the directory path to use within the zip archive. This path - need not refer to an extant directory in the current filesystem. If the - files within the zip are later extracted, this is the path used for the - extracted file. Passing null (Nothing in VB) will use the - path on the fileOrDirectoryName. Passing the empty string ("") will - insert the item at the root path within the archive. - - - - - - - - This example shows how to zip up a set of files into a flat hierarchy, - regardless of where in the filesystem the files originated. The resulting - zip archive will contain a toplevel directory named "flat", which itself - will contain files Readme.txt, MyProposal.docx, and Image1.jpg. A - subdirectory under "flat" called SupportFiles will contain all the files - in the "c:\SupportFiles" directory on disk. - - - String[] itemnames= { - "c:\\fixedContent\\Readme.txt", - "MyProposal.docx", - "c:\\SupportFiles", // a directory - "images\\Image1.jpg" - }; - - try - { - using (ZipFile zip = new ZipFile()) - { - for (int i = 1; i < itemnames.Length; i++) - { - // will add Files or Dirs, recurses and flattens subdirectories - zip.AddItem(itemnames[i],"flat"); - } - zip.Save(ZipToCreate); - } - } - catch (System.Exception ex1) - { - System.Console.Error.WriteLine("exception: {0}", ex1); - } - - - - Dim itemnames As String() = _ - New String() { "c:\fixedContent\Readme.txt", _ - "MyProposal.docx", _ - "SupportFiles", _ - "images\Image1.jpg" } - Try - Using zip As New ZipFile - Dim i As Integer - For i = 1 To itemnames.Length - 1 - ' will add Files or Dirs, recursing and flattening subdirectories. - zip.AddItem(itemnames(i), "flat") - Next i - zip.Save(ZipToCreate) - End Using - Catch ex1 As Exception - Console.Error.WriteLine("exception: {0}", ex1.ToString()) - End Try - - - The ZipEntry added. - - - - Adds a File to a Zip file archive. - - - - - This call collects metadata for the named file in the filesystem, - including the file attributes and the timestamp, and inserts that metadata - into the resulting ZipEntry. Only when the application calls Save() on - the ZipFile, does DotNetZip read the file from the filesystem and - then write the content to the zip file archive. - - - - This method will throw an exception if an entry with the same name already - exists in the ZipFile. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - In this example, three files are added to a Zip archive. The ReadMe.txt - file will be placed in the root of the archive. The .png file will be - placed in a folder within the zip called photos\personal. The pdf file - will be included into a folder within the zip called Desktop. - - - try - { - using (ZipFile zip = new ZipFile()) - { - zip.AddFile("c:\\photos\\personal\\7440-N49th.png"); - zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf"); - zip.AddFile("ReadMe.txt"); - - zip.Save("Package.zip"); - } - } - catch (System.Exception ex1) - { - System.Console.Error.WriteLine("exception: " + ex1); - } - - - - Try - Using zip As ZipFile = New ZipFile - zip.AddFile("c:\photos\personal\7440-N49th.png") - zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf") - zip.AddFile("ReadMe.txt") - zip.Save("Package.zip") - End Using - Catch ex1 As Exception - Console.Error.WriteLine("exception: {0}", ex1.ToString) - End Try - - - - This method has two overloads. - - - - - - - The name of the file to add. It should refer to a file in the filesystem. - The name of the file may be a relative path or a fully-qualified path. - - The ZipEntry corresponding to the File added. - - - - Adds a File to a Zip file archive, potentially overriding the path to be - used within the zip archive. - - - - - The file added by this call to the ZipFile is not written to the - zip file archive until the application calls Save() on the ZipFile. - - - - This method will throw an exception if an entry with the same name already - exists in the ZipFile. - - - - This version of the method allows the caller to explicitly specify the - directory path to be used in the archive. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - In this example, three files are added to a Zip archive. The ReadMe.txt - file will be placed in the root of the archive. The .png file will be - placed in a folder within the zip called images. The pdf file will be - included into a folder within the zip called files\docs, and will be - encrypted with the given password. - - - try - { - using (ZipFile zip = new ZipFile()) - { - // the following entry will be inserted at the root in the archive. - zip.AddFile("c:\\datafiles\\ReadMe.txt", ""); - // this image file will be inserted into the "images" directory in the archive. - zip.AddFile("c:\\photos\\personal\\7440-N49th.png", "images"); - // the following will result in a password-protected file called - // files\\docs\\2008-Regional-Sales-Report.pdf in the archive. - zip.Password = "EncryptMe!"; - zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf", "files\\docs"); - zip.Save("Archive.zip"); - } - } - catch (System.Exception ex1) - { - System.Console.Error.WriteLine("exception: {0}", ex1); - } - - - - Try - Using zip As ZipFile = New ZipFile - ' the following entry will be inserted at the root in the archive. - zip.AddFile("c:\datafiles\ReadMe.txt", "") - ' this image file will be inserted into the "images" directory in the archive. - zip.AddFile("c:\photos\personal\7440-N49th.png", "images") - ' the following will result in a password-protected file called - ' files\\docs\\2008-Regional-Sales-Report.pdf in the archive. - zip.Password = "EncryptMe!" - zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf", "files\documents") - zip.Save("Archive.zip") - End Using - Catch ex1 As Exception - Console.Error.WriteLine("exception: {0}", ex1) - End Try - - - - - - - - - The name of the file to add. The name of the file may be a relative path - or a fully-qualified path. - - - - Specifies a directory path to use to override any path in the fileName. - This path may, or may not, correspond to a real directory in the current - filesystem. If the files within the zip are later extracted, this is the - path used for the extracted file. Passing null (Nothing in - VB) will use the path on the fileName, if any. Passing the empty string - ("") will insert the item at the root path within the archive. - - - The ZipEntry corresponding to the file added. - - - - This method removes a collection of entries from the ZipFile. - - - - A collection of ZipEntry instances from this zip file to be removed. For - example, you can pass in an array of ZipEntry instances; or you can call - SelectEntries(), and then add or remove entries from that - ICollection<ZipEntry> (ICollection(Of ZipEntry) in VB), and pass - that ICollection to this method. - - - - - - - - This method removes a collection of entries from the ZipFile, by name. - - - - A collection of strings that refer to names of entries to be removed - from the ZipFile. For example, you can pass in an array or a - List of Strings that provide the names of entries to be removed. - - - - - - - - This method adds a set of files to the ZipFile. - - - - - Use this method to add a set of files to the zip archive, in one call. - For example, a list of files received from - System.IO.Directory.GetFiles() can be added to a zip archive in one - call. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - The collection of names of the files to add. Each string should refer to a - file in the filesystem. The name of the file may be a relative path or a - fully-qualified path. - - - - This example shows how to create a zip file, and add a few files into it. - - String ZipFileToCreate = "archive1.zip"; - String DirectoryToZip = "c:\\reports"; - using (ZipFile zip = new ZipFile()) - { - // Store all files found in the top level directory, into the zip archive. - String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); - zip.AddFiles(filenames); - zip.Save(ZipFileToCreate); - } - - - - Dim ZipFileToCreate As String = "archive1.zip" - Dim DirectoryToZip As String = "c:\reports" - Using zip As ZipFile = New ZipFile - ' Store all files found in the top level directory, into the zip archive. - Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) - zip.AddFiles(filenames) - zip.Save(ZipFileToCreate) - End Using - - - - - - - - Adds or updates a set of files in the ZipFile. - - - - - Any files that already exist in the archive are updated. Any files that - don't yet exist in the archive are added. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - The collection of names of the files to update. Each string should refer to a file in - the filesystem. The name of the file may be a relative path or a fully-qualified path. - - - - - - Adds a set of files to the ZipFile, using the - specified directory path in the archive. - - - - - Any directory structure that may be present in the - filenames contained in the list is "flattened" in the - archive. Each file in the list is added to the archive in - the specified top-level directory. - - - - For ZipFile properties including , , , , , , and , their respective values at the - time of this call will be applied to each ZipEntry added. - - - - - The names of the files to add. Each string should refer to - a file in the filesystem. The name of the file may be a - relative path or a fully-qualified path. - - - - Specifies a directory path to use to override any path in the file name. - Th is path may, or may not, correspond to a real directory in the current - filesystem. If the files within the zip are later extracted, this is the - path used for the extracted file. Passing null (Nothing in - VB) will use the path on each of the fileNames, if any. Passing - the empty string ("") will insert the item at the root path within the - archive. - - - - - - - Adds a set of files to the ZipFile, using the specified directory - path in the archive, and preserving the full directory structure in the - filenames. - - - - - - Think of the as a "root" or - base directory used in the archive for the files that get added. when - is true, the hierarchy of files - found in the filesystem will be placed, with the hierarchy intact, - starting at that root in the archive. When preserveDirHierarchy - is false, the path hierarchy of files is flattned, and the flattened - set of files gets placed in the root within the archive as specified in - directoryPathInArchive. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - - The names of the files to add. Each string should refer to a file in the - filesystem. The name of the file may be a relative path or a - fully-qualified path. - - - - Specifies a directory path to use as a prefix for each entry name. - This path may, or may not, correspond to a real directory in the current - filesystem. If the files within the zip are later extracted, this is the - path used for the extracted file. Passing null (Nothing in - VB) will use the path on each of the fileNames, if any. Passing - the empty string ("") will insert the item at the root path within the - archive. - - - - whether the entries in the zip archive will reflect the directory - hierarchy that is present in the various filenames. For example, if - includes two paths, - \Animalia\Chordata\Mammalia\Info.txt and - \Plantae\Magnoliophyta\Dicotyledon\Info.txt, then calling this method - with = false will - result in an exception because of a duplicate entry name, while - calling this method with = - true will result in the full direcory paths being included in - the entries added to the ZipFile. - - - - - - Adds or updates a set of files to the ZipFile, using the specified - directory path in the archive. - - - - - - Any files that already exist in the archive are updated. Any files that - don't yet exist in the archive are added. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - The names of the files to add or update. Each string should refer to a - file in the filesystem. The name of the file may be a relative path or a - fully-qualified path. - - - - Specifies a directory path to use to override any path in the file name. - This path may, or may not, correspond to a real directory in the current - filesystem. If the files within the zip are later extracted, this is the - path used for the extracted file. Passing null (Nothing in - VB) will use the path on each of the fileNames, if any. Passing - the empty string ("") will insert the item at the root path within the - archive. - - - - - - - Adds or Updates a File in a Zip file archive. - - - - - This method adds a file to a zip archive, or, if the file already exists - in the zip archive, this method Updates the content of that given filename - in the zip archive. The UpdateFile method might more accurately be - called "AddOrUpdateFile". - - - - Upon success, there is no way for the application to learn whether the file - was added versus updated. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - This example shows how to Update an existing entry in a zipfile. The first - call to UpdateFile adds the file to the newly-created zip archive. The - second call to UpdateFile updates the content for that file in the zip - archive. - - - using (ZipFile zip1 = new ZipFile()) - { - // UpdateFile might more accurately be called "AddOrUpdateFile" - zip1.UpdateFile("MyDocuments\\Readme.txt"); - zip1.UpdateFile("CustomerList.csv"); - zip1.Comment = "This zip archive has been created."; - zip1.Save("Content.zip"); - } - - using (ZipFile zip2 = ZipFile.Read("Content.zip")) - { - zip2.UpdateFile("Updates\\Readme.txt"); - zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed."; - zip2.Save(); - } - - - - Using zip1 As New ZipFile - ' UpdateFile might more accurately be called "AddOrUpdateFile" - zip1.UpdateFile("MyDocuments\Readme.txt") - zip1.UpdateFile("CustomerList.csv") - zip1.Comment = "This zip archive has been created." - zip1.Save("Content.zip") - End Using - - Using zip2 As ZipFile = ZipFile.Read("Content.zip") - zip2.UpdateFile("Updates\Readme.txt") - zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed." - zip2.Save - End Using - - - - - - - - - The name of the file to add or update. It should refer to a file in the - filesystem. The name of the file may be a relative path or a - fully-qualified path. - - - - The ZipEntry corresponding to the File that was added or updated. - - - - - Adds or Updates a File in a Zip file archive. - - - - - This method adds a file to a zip archive, or, if the file already exists - in the zip archive, this method Updates the content of that given filename - in the zip archive. - - - - This version of the method allows the caller to explicitly specify the - directory path to be used in the archive. The entry to be added or - updated is found by using the specified directory path, combined with the - basename of the specified filename. - - - - Upon success, there is no way for the application to learn if the file was - added versus updated. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - - - The name of the file to add or update. It should refer to a file in the - filesystem. The name of the file may be a relative path or a - fully-qualified path. - - - - Specifies a directory path to use to override any path in the - fileName. This path may, or may not, correspond to a real - directory in the current filesystem. If the files within the zip are - later extracted, this is the path used for the extracted file. Passing - null (Nothing in VB) will use the path on the - fileName, if any. Passing the empty string ("") will insert the - item at the root path within the archive. - - - - The ZipEntry corresponding to the File that was added or updated. - - - - - Add or update a directory in a zip archive. - - - - If the specified directory does not exist in the archive, then this method - is equivalent to calling AddDirectory(). If the specified - directory already exists in the archive, then this method updates any - existing entries, and adds any new entries. Any entries that are in the - zip archive but not in the specified directory, are left alone. In other - words, the contents of the zip file will be a union of the previous - contents and the new files. - - - - - - - - The path to the directory to be added to the zip archive, or updated in - the zip archive. - - - - The ZipEntry corresponding to the Directory that was added or updated. - - - - - Add or update a directory in the zip archive at the specified root - directory in the archive. - - - - If the specified directory does not exist in the archive, then this method - is equivalent to calling AddDirectory(). If the specified - directory already exists in the archive, then this method updates any - existing entries, and adds any new entries. Any entries that are in the - zip archive but not in the specified directory, are left alone. In other - words, the contents of the zip file will be a union of the previous - contents and the new files. - - - - - - - - The path to the directory to be added to the zip archive, or updated - in the zip archive. - - - - Specifies a directory path to use to override any path in the - directoryName. This path may, or may not, correspond to a real - directory in the current filesystem. If the files within the zip are - later extracted, this is the path used for the extracted file. Passing - null (Nothing in VB) will use the path on the - directoryName, if any. Passing the empty string ("") will insert - the item at the root path within the archive. - - - - The ZipEntry corresponding to the Directory that was added or updated. - - - - - Add or update a file or directory in the zip archive. - - - - - This is useful when the application is not sure or does not care if the - item to be added is a file or directory, and does not know or does not - care if the item already exists in the ZipFile. Calling this method - is equivalent to calling RemoveEntry() if an entry by the same name - already exists, followed calling by AddItem(). - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - - - the path to the file or directory to be added or updated. - - - - - Add or update a file or directory. - - - - - This method is useful when the application is not sure or does not care if - the item to be added is a file or directory, and does not know or does not - care if the item already exists in the ZipFile. Calling this method - is equivalent to calling RemoveEntry(), if an entry by that name - exists, and then calling AddItem(). - - - - This version of the method allows the caller to explicitly specify the - directory path to be used for the item being added to the archive. The - entry or entries that are added or updated will use the specified - DirectoryPathInArchive. Extracting the entry from the archive will - result in a file stored in that directory path. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - - - The path for the File or Directory to be added or updated. - - - Specifies a directory path to use to override any path in the - itemName. This path may, or may not, correspond to a real - directory in the current filesystem. If the files within the zip are - later extracted, this is the path used for the extracted file. Passing - null (Nothing in VB) will use the path on the - itemName, if any. Passing the empty string ("") will insert the - item at the root path within the archive. - - - - - Adds a named entry into the zip archive, taking content for the entry - from a string. - - - - Calling this method creates an entry using the given fileName and - directory path within the archive. There is no need for a file by the - given name to exist in the filesystem; the name is used within the zip - archive only. The content for the entry is encoded using the default text - encoding for the machine. - - - - The content of the file, should it be extracted from the zip. - - - - The name, including any path, to use for the entry within the archive. - - - The ZipEntry added. - - - - This example shows how to add an entry to the zipfile, using a string as - content for that entry. - - - string Content = "This string will be the content of the Readme.txt file in the zip archive."; - using (ZipFile zip1 = new ZipFile()) - { - zip1.AddFile("MyDocuments\\Resume.doc", "files"); - zip1.AddEntry("Readme.txt", Content); - zip1.Comment = "This zip file was created at " + System.DateTime.Now.ToString("G"); - zip1.Save("Content.zip"); - } - - - - Public Sub Run() - Dim Content As String = "This string will be the content of the Readme.txt file in the zip archive." - Using zip1 As ZipFile = New ZipFile - zip1.AddEntry("Readme.txt", Content) - zip1.AddFile("MyDocuments\Resume.doc", "files") - zip1.Comment = ("This zip file was created at " & DateTime.Now.ToString("G")) - zip1.Save("Content.zip") - End Using - End Sub - - - - - - Adds a named entry into the zip archive, taking content for the entry - from a string, and using the specified text encoding. - - - - - - Calling this method creates an entry using the given fileName and - directory path within the archive. There is no need for a file by the - given name to exist in the filesystem; the name is used within the zip - archive only. - - - - The content for the entry, a string value, is encoded using the given - text encoding. A BOM (byte-order-mark) is emitted into the file, if the - Encoding parameter is set for that. - - - - Most Encoding classes support a constructor that accepts a boolean, - indicating whether to emit a BOM or not. For example see . - - - - - - The name, including any path, to use within the archive for the entry. - - - - The content of the file, should it be extracted from the zip. - - - - The text encoding to use when encoding the string. Be aware: This is - distinct from the text encoding used to encode the fileName, as specified - in . - - - The ZipEntry added. - - - - - Create an entry in the ZipFile using the given Stream - as input. The entry will have the given filename. - - - - - - The application should provide an open, readable stream; in this case it - will be read during the call to or one of - its overloads. - - - - The passed stream will be read from its current position. If - necessary, callers should set the position in the stream before - calling AddEntry(). This might be appropriate when using this method - with a MemoryStream, for example. - - - - In cases where a large number of streams will be added to the - ZipFile, the application may wish to avoid maintaining all of the - streams open simultaneously. To handle this situation, the application - should use the - overload. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - This example adds a single entry to a ZipFile via a Stream. - - - - String zipToCreate = "Content.zip"; - String fileNameInArchive = "Content-From-Stream.bin"; - using (System.IO.Stream streamToRead = MyStreamOpener()) - { - using (ZipFile zip = new ZipFile()) - { - ZipEntry entry= zip.AddEntry(fileNameInArchive, streamToRead); - zip.AddFile("Readme.txt"); - zip.Save(zipToCreate); // the stream is read implicitly here - } - } - - - - Dim zipToCreate As String = "Content.zip" - Dim fileNameInArchive As String = "Content-From-Stream.bin" - Using streamToRead as System.IO.Stream = MyStreamOpener() - Using zip As ZipFile = New ZipFile() - Dim entry as ZipEntry = zip.AddEntry(fileNameInArchive, streamToRead) - zip.AddFile("Readme.txt") - zip.Save(zipToCreate) '' the stream is read implicitly, here - End Using - End Using - - - - - - - The name, including any path, which is shown in the zip file for the added - entry. - - - The input stream from which to grab content for the file - - The ZipEntry added. - - - - Add a ZipEntry for which content is written directly by the application. - - - - - When the application needs to write the zip entry data, use this - method to add the ZipEntry. For example, in the case that the - application wishes to write the XML representation of a DataSet into - a ZipEntry, the application can use this method to do so. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - About progress events: When using the WriteDelegate, DotNetZip does - not issue any SaveProgress events with EventType = - Saving_EntryBytesRead. (This is because it is the - application's code that runs in WriteDelegate - there's no way for - DotNetZip to know when to issue a EntryBytesRead event.) - Applications that want to update a progress bar or similar status - indicator should do so from within the WriteDelegate - itself. DotNetZip will issue the other SaveProgress events, - including - Saving_Started, - - Saving_BeforeWriteEntry, and - Saving_AfterWriteEntry. - - - - Note: When you use PKZip encryption, it's normally necessary to - compute the CRC of the content to be encrypted, before compressing or - encrypting it. Therefore, when using PKZip encryption with a - WriteDelegate, the WriteDelegate CAN BE called twice: once to compute - the CRC, and the second time to potentially compress and - encrypt. Surprising, but true. This is because PKWARE specified that - the encryption initialization data depends on the CRC. - If this happens, for each call of the delegate, your - application must stream the same entry data in its entirety. If your - application writes different data during the second call, it will - result in a corrupt zip file. - - - - The double-read behavior happens with all types of entries, not only - those that use WriteDelegate. It happens if you add an entry from a - filesystem file, or using a string, or a stream, or an opener/closer - pair. But in those cases, DotNetZip takes care of reading twice; in - the case of the WriteDelegate, the application code gets invoked - twice. Be aware. - - - - As you can imagine, this can cause performance problems for large - streams, and it can lead to correctness problems when you use a - WriteDelegate. This is a pretty big pitfall. There are two - ways to avoid it. First, and most preferred: don't use PKZIP - encryption. If you use the WinZip AES encryption, this problem - doesn't occur, because the encryption protocol doesn't require the CRC - up front. Second: if you do choose to use PKZIP encryption, write out - to a non-seekable stream (like standard output, or the - Response.OutputStream in an ASP.NET application). In this case, - DotNetZip will use an alternative encryption protocol that does not - rely on the CRC of the content. This also implies setting bit 3 in - the zip entry, which still presents problems for some zip tools. - - - - In the future I may modify DotNetZip to *always* use bit 3 when PKZIP - encryption is in use. This seems like a win overall, but there will - be some work involved. If you feel strongly about it, visit the - DotNetZip forums and vote up the Workitem - tracking this issue. - - - - - the name of the entry to add - the delegate which will write the entry content - the ZipEntry added - - - - This example shows an application filling a DataSet, then saving the - contents of that DataSet as XML, into a ZipEntry in a ZipFile, using an - anonymous delegate in C#. The DataSet XML is never saved to a disk file. - - - var c1= new System.Data.SqlClient.SqlConnection(connstring1); - var da = new System.Data.SqlClient.SqlDataAdapter() - { - SelectCommand= new System.Data.SqlClient.SqlCommand(strSelect, c1) - }; - - DataSet ds1 = new DataSet(); - da.Fill(ds1, "Invoices"); - - using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) - { - zip.AddEntry(zipEntryName, (name,stream) => ds1.WriteXml(stream) ); - zip.Save(zipFileName); - } - - - - - - This example uses an anonymous method in C# as the WriteDelegate to provide - the data for the ZipEntry. The example is a bit contrived - the - AddFile() method is a simpler way to insert the contents of a file - into an entry in a zip file. On the other hand, if there is some sort of - processing or transformation of the file contents required before writing, - the application could use the WriteDelegate to do it, in this way. - - - using (var input = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite )) - { - using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) - { - zip.AddEntry(zipEntryName, (name,output) => - { - byte[] buffer = new byte[BufferSize]; - int n; - while ((n = input.Read(buffer, 0, buffer.Length)) != 0) - { - // could transform the data here... - output.Write(buffer, 0, n); - // could update a progress bar here - } - }); - - zip.Save(zipFileName); - } - } - - - - - - This example uses a named delegate in VB to write data for the given - ZipEntry (VB9 does not have anonymous delegates). The example here is a bit - contrived - a simpler way to add the contents of a file to a ZipEntry is to - simply use the appropriate AddFile() method. The key scenario for - which the WriteDelegate makes sense is saving a DataSet, in XML - format, to the zip file. The DataSet can write XML to a stream, and the - WriteDelegate is the perfect place to write into the zip file. There may be - other data structures that can write to a stream, but cannot be read as a - stream. The WriteDelegate would be appropriate for those cases as - well. - - - Private Sub WriteEntry (ByVal name As String, ByVal output As Stream) - Using input As FileStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - Dim n As Integer = -1 - Dim buffer As Byte() = New Byte(BufferSize){} - Do While n <> 0 - n = input.Read(buffer, 0, buffer.Length) - output.Write(buffer, 0, n) - Loop - End Using - End Sub - - Public Sub Run() - Using zip = New ZipFile - zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry)) - zip.Save(zipFileName) - End Using - End Sub - - - - - - Add an entry, for which the application will provide a stream - containing the entry data, on a just-in-time basis. - - - - - In cases where the application wishes to open the stream that - holds the content for the ZipEntry, on a just-in-time basis, the - application can use this method. The application provides an - opener delegate that will be called by the DotNetZip library to - obtain a readable stream that can be read to get the bytes for - the given entry. Typically, this delegate opens a stream. - Optionally, the application can provide a closer delegate as - well, which will be called by DotNetZip when all bytes have been - read from the entry. - - - - These delegates are called from within the scope of the call to - ZipFile.Save(). - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - This example uses anonymous methods in C# to open and close the - source stream for the content for a zip entry. - - - using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) - { - zip.AddEntry(zipEntryName, - (name) => File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ), - (name, stream) => stream.Close() - ); - - zip.Save(zipFileName); - } - - - - - - - This example uses delegates in VB.NET to open and close the - the source stream for the content for a zip entry. VB 9.0 lacks - support for "Sub" lambda expressions, and so the CloseDelegate must - be an actual, named Sub. - - - - Function MyStreamOpener(ByVal entryName As String) As Stream - '' This simply opens a file. You probably want to do somethinig - '' more involved here: open a stream to read from a database, - '' open a stream on an HTTP connection, and so on. - Return File.OpenRead(entryName) - End Function - - Sub MyStreamCloser(entryName As String, stream As Stream) - stream.Close() - End Sub - - Public Sub Run() - Dim dirToZip As String = "fodder" - Dim zipFileToCreate As String = "Archive.zip" - Dim opener As OpenDelegate = AddressOf MyStreamOpener - Dim closer As CloseDelegate = AddressOf MyStreamCloser - Dim numFilestoAdd As Int32 = 4 - Using zip As ZipFile = New ZipFile - Dim i As Integer - For i = 0 To numFilesToAdd - 1 - zip.AddEntry(String.Format("content-{0:000}.txt"), opener, closer) - Next i - zip.Save(zipFileToCreate) - End Using - End Sub - - - - - the name of the entry to add - - the delegate that will be invoked by ZipFile.Save() to get the - readable stream for the given entry. ZipFile.Save() will call - read on this stream to obtain the data for the entry. This data - will then be compressed and written to the newly created zip - file. - - - the delegate that will be invoked to close the stream. This may - be null (Nothing in VB), in which case no call is makde to close - the stream. - - the ZipEntry added - - - - - Updates the given entry in the ZipFile, using the given - string as content for the ZipEntry. - - - - - - Calling this method is equivalent to removing the ZipEntry for - the given file name and directory path, if it exists, and then calling - . See the documentation for - that method for further explanation. The string content is encoded - using the default encoding for the machine. This encoding is distinct - from the encoding used for the filename itself. See - . - - - - - - The name, including any path, to use within the archive for the entry. - - - - The content of the file, should it be extracted from the zip. - - - The ZipEntry added. - - - - - Updates the given entry in the ZipFile, using the given string as - content for the ZipEntry. - - - - Calling this method is equivalent to removing the ZipEntry for the - given file name and directory path, if it exists, and then calling . See the - documentation for that method for further explanation. - - - - The name, including any path, to use within the archive for the entry. - - - - The content of the file, should it be extracted from the zip. - - - - The text encoding to use when encoding the string. Be aware: This is - distinct from the text encoding used to encode the filename. See . - - - The ZipEntry added. - - - - - Updates the given entry in the ZipFile, using the given delegate - as the source for content for the ZipEntry. - - - - Calling this method is equivalent to removing the ZipEntry for the - given file name and directory path, if it exists, and then calling . See the - documentation for that method for further explanation. - - - - The name, including any path, to use within the archive for the entry. - - - the delegate which will write the entry content. - - The ZipEntry added. - - - - - Updates the given entry in the ZipFile, using the given delegates - to open and close the stream that provides the content for the ZipEntry. - - - - Calling this method is equivalent to removing the ZipEntry for the - given file name and directory path, if it exists, and then calling . See the - documentation for that method for further explanation. - - - - The name, including any path, to use within the archive for the entry. - - - - the delegate that will be invoked to open the stream - - - the delegate that will be invoked to close the stream - - - The ZipEntry added or updated. - - - - - Updates the given entry in the ZipFile, using the given stream as - input, and the given filename and given directory Path. - - - - - Calling the method is equivalent to calling RemoveEntry() if an - entry by the same name already exists, and then calling AddEntry() - with the given fileName and stream. - - - - The stream must be open and readable during the call to - ZipFile.Save. You can dispense the stream on a just-in-time basis - using the property. Check the - documentation of that property for more information. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - - - The name, including any path, to use within the archive for the entry. - - - The input stream from which to read file data. - The ZipEntry added. - - - - Add an entry into the zip archive using the given filename and - directory path within the archive, and the given content for the - file. No file is created in the filesystem. - - - The data to use for the entry. - - - The name, including any path, to use within the archive for the entry. - - - The ZipEntry added. - - - - Updates the given entry in the ZipFile, using the given byte - array as content for the entry. - - - - Calling this method is equivalent to removing the ZipEntry - for the given filename and directory path, if it exists, and then - calling . See the - documentation for that method for further explanation. - - - - The name, including any path, to use within the archive for the entry. - - - The content to use for the ZipEntry. - - The ZipEntry added. - - - - - Adds the contents of a filesystem directory to a Zip file archive. - - - - - - The name of the directory may be a relative path or a fully-qualified - path. Any files within the named directory are added to the archive. Any - subdirectories within the named directory are also added to the archive, - recursively. - - - - Top-level entries in the named directory will appear as top-level entries - in the zip archive. Entries in subdirectories in the named directory will - result in entries in subdirectories in the zip archive. - - - - If you want the entries to appear in a containing directory in the zip - archive itself, then you should call the AddDirectory() overload that - allows you to explicitly specify a directory path for use in the archive. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - - - - - - This method has 2 overloads. - - The name of the directory to add. - The ZipEntry added. - - - - Adds the contents of a filesystem directory to a Zip file archive, - overriding the path to be used for entries in the archive. - - - - - The name of the directory may be a relative path or a fully-qualified - path. The add operation is recursive, so that any files or subdirectories - within the name directory are also added to the archive. - - - - Top-level entries in the named directory will appear as top-level entries - in the zip archive. Entries in subdirectories in the named directory will - result in entries in subdirectories in the zip archive. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - - - In this code, calling the ZipUp() method with a value of "c:\reports" for - the directory parameter will result in a zip file structure in which all - entries are contained in a toplevel "reports" directory. - - - - public void ZipUp(string targetZip, string directory) - { - using (var zip = new ZipFile()) - { - zip.AddDirectory(directory, System.IO.Path.GetFileName(directory)); - zip.Save(targetZip); - } - } - - - - - - - - The name of the directory to add. - - - Specifies a directory path to use to override any path in the - DirectoryName. This path may, or may not, correspond to a real directory - in the current filesystem. If the zip is later extracted, this is the - path used for the extracted file or directory. Passing null - (Nothing in VB) or the empty string ("") will insert the items at - the root path within the archive. - - - The ZipEntry added. - - - - Creates a directory in the zip archive. - - - - - - Use this when you want to create a directory in the archive but there is - no corresponding filesystem representation for that directory. - - - - You will probably not need to do this in your code. One of the only times - you will want to do this is if you want an empty directory in the zip - archive. The reason: if you add a file to a zip archive that is stored - within a multi-level directory, all of the directory tree is implicitly - created in the zip archive. - - - - - - The name of the directory to create in the archive. - - The ZipEntry added. - - - - Checks a zip file to see if its directory is consistent. - - - - - - In cases of data error, the directory within a zip file can get out - of synch with the entries in the zip file. This method checks the - given zip file and returns true if this has occurred. - - - This method may take a long time to run for large zip files. - - - This method is not supported in the Reduced version of DotNetZip. - - - - Developers using COM can use the ComHelper.CheckZip(String) - method. - - - - - The filename to of the zip file to check. - - true if the named zip file checks OK. Otherwise, false. - - - - - - - Checks a zip file to see if its directory is consistent, - and optionally fixes the directory if necessary. - - - - - - In cases of data error, the directory within a zip file can get out of - synch with the entries in the zip file. This method checks the given - zip file, and returns true if this has occurred. It also optionally - fixes the zipfile, saving the fixed copy in Name_Fixed.zip. - - - - This method may take a long time to run for large zip files. It - will take even longer if the file actually needs to be fixed, and if - fixIfNecessary is true. - - - - This method is not supported in the Reduced version of DotNetZip. - - - - - The filename to of the zip file to check. - - If true, the method will fix the zip file if - necessary. - - - a TextWriter in which messages generated while checking will be written. - - - true if the named zip is OK; false if the file needs to be fixed. - - - - - - - Rewrite the directory within a zipfile. - - - - - - In cases of data error, the directory in a zip file can get out of - synch with the entries in the zip file. This method attempts to fix - the zip file if this has occurred. - - - This can take a long time for large zip files. - - This won't work if the zip file uses a non-standard - code page - neither IBM437 nor UTF-8. - - - This method is not supported in the Reduced or Compact Framework - versions of DotNetZip. - - - - Developers using COM can use the ComHelper.FixZipDirectory(String) - method. - - - - - The filename to of the zip file to fix. - - - - - - - Verify the password on a zip file. - - - - - Keep in mind that passwords in zipfiles are applied to - zip entries, not to the entire zip file. So testing a - zipfile for a particular password doesn't work in the - general case. On the other hand, it's often the case - that a single password will be used on all entries in a - zip file. This method works for that case. - - - There is no way to check a password without doing the - decryption. So this code decrypts and extracts the given - zipfile into - - - - The filename to of the zip file to fix. - - The password to check. - - a bool indicating whether the password matches. - - - - Provides a human-readable string with information about the ZipFile. - - - - - The information string contains 10 lines or so, about each ZipEntry, - describing whether encryption is in use, the compressed and uncompressed - length of the entry, the offset of the entry, and so on. As a result the - information string can be very long for zip files that contain many - entries. - - - This information is mostly useful for diagnostic purposes. - - - - - - Indicates whether to perform a full scan of the zip file when reading it. - - - - - - You almost never want to use this property. - - - - When reading a zip file, if this flag is true (True in - VB), the entire zip archive will be scanned and searched for entries. - For large archives, this can take a very, long time. The much more - efficient default behavior is to read the zip directory, which is - stored at the end of the zip file. But, in some cases the directory is - corrupted and you need to perform a full scan of the zip file to - determine the contents of the zip file. This property lets you do - that, when necessary. - - - - This flag is effective only when calling . Normally you would read a ZipFile with the - static ZipFile.Read - method. But you can't set the FullScan property on the - ZipFile instance when you use a static factory method like - ZipFile.Read. - - - - - - - This example shows how to read a zip file using the full scan approach, - and then save it, thereby producing a corrected zip file. - - - using (var zip = new ZipFile()) - { - zip.FullScan = true; - zip.Initialize(zipFileName); - zip.Save(newName); - } - - - - Using zip As New ZipFile - zip.FullScan = True - zip.Initialize(zipFileName) - zip.Save(newName) - End Using - - - - - - - Whether to sort the ZipEntries before saving the file. - - - - The default is false. If you have a large number of zip entries, the sort - alone can consume significant time. - - - - - using (var zip = new ZipFile()) - { - zip.AddFiles(filesToAdd); - zip.SortEntriesBeforeSaving = true; - zip.Save(name); - } - - - - Using zip As New ZipFile - zip.AddFiles(filesToAdd) - zip.SortEntriesBeforeSaving = True - zip.Save(name) - End Using - - - - - - - Indicates whether NTFS Reparse Points, like junctions, should be - traversed during calls to AddDirectory(). - - - - By default, calls to AddDirectory() will traverse NTFS reparse - points, like mounted volumes, and directory junctions. An example - of a junction is the "My Music" directory in Windows Vista. In some - cases you may not want DotNetZip to traverse those directories. In - that case, set this property to false. - - - - - using (var zip = new ZipFile()) - { - zip.AddDirectoryWillTraverseReparsePoints = false; - zip.AddDirectory(dirToZip,"fodder"); - zip.Save(zipFileToCreate); - } - - - - - - Size of the IO buffer used while saving. - - - - - - First, let me say that you really don't need to bother with this. It is - here to allow for optimizations that you probably won't make! It will work - fine if you don't set or get this property at all. Ok? - - - - Now that we have that out of the way, the fine print: This - property affects the size of the buffer that is used for I/O for each - entry contained in the zip file. When a file is read in to be compressed, - it uses a buffer given by the size here. When you update a zip file, the - data for unmodified entries is copied from the first zip file to the - other, through a buffer given by the size here. - - - - Changing the buffer size affects a few things: first, for larger buffer - sizes, the memory used by the ZipFile, obviously, will be larger - during I/O operations. This may make operations faster for very much - larger files. Last, for any given entry, when you use a larger buffer - there will be fewer progress events during I/O operations, because there's - one progress event generated for each time the buffer is filled and then - emptied. - - - - The default buffer size is 8k. Increasing the buffer size may speed - things up as you compress larger files. But there are no hard-and-fast - rules here, eh? You won't know til you test it. And there will be a - limit where ever larger buffers actually slow things down. So as I said - in the beginning, it's probably best if you don't set or get this property - at all. - - - - - - This example shows how you might set a large buffer size for efficiency when - dealing with zip entries that are larger than 1gb. - - using (ZipFile zip = new ZipFile()) - { - zip.SaveProgress += this.zip1_SaveProgress; - zip.AddDirectory(directoryToZip, ""); - zip.UseZip64WhenSaving = Zip64Option.Always; - zip.BufferSize = 65536*8; // 65536 * 8 = 512k - zip.Save(ZipFileToCreate); - } - - - - - - Size of the work buffer to use for the ZLIB codec during compression. - - - - - When doing ZLIB or Deflate compression, the library fills a buffer, - then passes it to the compressor for compression. Then the library - reads out the compressed bytes. This happens repeatedly until there - is no more uncompressed data to compress. This property sets the - size of the buffer that will be used for chunk-wise compression. In - order for the setting to take effect, your application needs to set - this property before calling one of the ZipFile.Save() - overloads. - - - Setting this affects the performance and memory efficiency of - compression and decompression. For larger files, setting this to a - larger size may improve compression performance, but the exact - numbers vary depending on available memory, the size of the streams - you are compressing, and a bunch of other variables. I don't have - good firm recommendations on how to set it. You'll have to test it - yourself. Or just leave it alone and accept the default. - - - - - - Indicates whether extracted files should keep their paths as - stored in the zip archive. - - - - - This property affects Extraction. It is not used when creating zip - archives. - - - - With this property set to false, the default, extracting entries - from a zip file will create files in the filesystem that have the full - path associated to the entry within the zip file. With this property set - to true, extracting entries from the zip file results in files - with no path: the folders are "flattened." - - - - An example: suppose the zip file contains entries /directory1/file1.txt and - /directory2/file2.txt. With FlattenFoldersOnExtract set to false, - the files created will be \directory1\file1.txt and \directory2\file2.txt. - With the property set to true, the files created are file1.txt and file2.txt. - - - - - - - The compression strategy to use for all entries. - - - - Set the Strategy used by the ZLIB-compatible compressor, when - compressing entries using the DEFLATE method. Different compression - strategies work better on different sorts of data. The strategy - parameter can affect the compression ratio and the speed of - compression but not the correctness of the compresssion. For more - information see Ionic.Zlib.CompressionStrategy. - - - - - The name of the ZipFile, on disk. - - - - - - When the ZipFile instance was created by reading an archive using - one of the ZipFile.Read methods, this property represents the name - of the zip file that was read. When the ZipFile instance was - created by using the no-argument constructor, this value is null - (Nothing in VB). - - - - If you use the no-argument constructor, and you then explicitly set this - property, when you call , this name will - specify the name of the zip file created. Doing so is equivalent to - calling . When instantiating a - ZipFile by reading from a stream or byte array, the Name - property remains null. When saving to a stream, the Name - property is implicitly set to null. - - - - - - Sets the compression level to be used for entries subsequently added to - the zip archive. - - - - - Varying the compression level used on entries can affect the - size-vs-speed tradeoff when compression and decompressing data streams - or files. - - - - As with some other properties on the ZipFile class, like , , and , setting this property on a ZipFile - instance will cause the specified CompressionLevel to be used on all - items that are subsequently added to the - ZipFile instance. If you set this property after you have added - items to the ZipFile, but before you have called Save(), - those items will not use the specified compression level. - - - - If you do not set this property, the default compression level is used, - which normally gives a good balance of compression efficiency and - compression speed. In some tests, using BestCompression can - double the time it takes to compress, while delivering just a small - increase in compression efficiency. This behavior will vary with the - type of data you compress. If you are in doubt, just leave this setting - alone, and accept the default. - - - - - - The compression method for the zipfile. - - - - By default, the compression method is CompressionMethod.Deflate. - - - - - - - A comment attached to the zip archive. - - - - - - This property is read/write. It allows the application to specify a - comment for the ZipFile, or read the comment for the - ZipFile. After setting this property, changes are only made - permanent when you call a Save() method. - - - - According to PKWARE's - zip specification, the comment is not encrypted, even if there is a - password set on the zip file. - - - - The specification does not describe how to indicate the encoding used - on a comment string. Many "compliant" zip tools and libraries use - IBM437 as the code page for comments; DotNetZip, too, follows that - practice. On the other hand, there are situations where you want a - Comment to be encoded with something else, for example using code page - 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the - comment following the same procedure it follows for encoding - filenames: (a) if is - Never, it uses the default encoding (IBM437). (b) if is Always, it always uses the - alternate encoding (). (c) if is AsNecessary, it uses the - alternate encoding only if the default encoding is not sufficient for - encoding the comment - in other words if decoding the result does not - produce the original string. This decision is taken at the time of - the call to ZipFile.Save(). - - - - When creating a zip archive using this library, it is possible to change - the value of between each - entry you add, and between adding entries and the call to - Save(). Don't do this. It will likely result in a zip file that is - not readable by any tool or application. For best interoperability, leave - alone, or specify it only - once, before adding any entries to the ZipFile instance. - - - - - - - Specifies whether the Creation, Access, and Modified times for entries - added to the zip file will be emitted in “Windows format” - when the zip archive is saved. - - - - - An application creating a zip archive can use this flag to explicitly - specify that the file times for the entries should or should not be stored - in the zip archive in the format used by Windows. By default this flag is - true, meaning the Windows-format times are stored in the zip - archive. - - - - When adding an entry from a file or directory, the Creation (), Access (), and Modified () times for the given entry are - automatically set from the filesystem values. When adding an entry from a - stream or string, all three values are implicitly set to - DateTime.Now. Applications can also explicitly set those times by - calling . - - - - PKWARE's - zip specification describes multiple ways to format these times in a - zip file. One is the format Windows applications normally use: 100ns ticks - since January 1, 1601 UTC. The other is a format Unix applications typically - use: seconds since January 1, 1970 UTC. Each format can be stored in an - "extra field" in the zip entry when saving the zip archive. The former - uses an extra field with a Header Id of 0x000A, while the latter uses a - header ID of 0x5455, although you probably don't need to know that. - - - - Not all tools and libraries can interpret these fields. Windows - compressed folders is one that can read the Windows Format timestamps, - while I believe the Infozip - tools can read the Unix format timestamps. Some tools and libraries - may be able to read only one or the other. DotNetZip can read or write - times in either or both formats. - - - - The times stored are taken from , , and . - - - - The value set here applies to all entries subsequently added to the - ZipFile. - - - - This property is not mutually exclusive of the property. It is possible and - legal and valid to produce a zip file that contains timestamps encoded in - the Unix format as well as in the Windows format, in addition to the LastModified time attached to each - entry in the archive, a time that is always stored in "DOS format". And, - notwithstanding the names PKWare uses for these time formats, any of them - can be read and written by any computer, on any operating system. But, - there are no guarantees that a program running on Mac or Linux will - gracefully handle a zip file with "Windows" formatted times, or that an - application that does not use DotNetZip but runs on Windows will be able to - handle file times in Unix format. - - - - When in doubt, test. Sorry, I haven't got a complete list of tools and - which sort of timestamps they can use and will tolerate. If you get any - good information and would like to pass it on, please do so and I will - include that information in this documentation. - - - - - This example shows how to save a zip file that contains file timestamps - in a format normally used by Unix. - - using (var zip = new ZipFile()) - { - // produce a zip file the Mac will like - zip.EmitTimesInWindowsFormatWhenSaving = false; - zip.EmitTimesInUnixFormatWhenSaving = true; - zip.AddDirectory(directoryToZip, "files"); - zip.Save(outputFile); - } - - - - Using zip As New ZipFile - '' produce a zip file the Mac will like - zip.EmitTimesInWindowsFormatWhenSaving = False - zip.EmitTimesInUnixFormatWhenSaving = True - zip.AddDirectory(directoryToZip, "files") - zip.Save(outputFile) - End Using - - - - - - - - - Specifies whether the Creation, Access, and Modified times - for entries added to the zip file will be emitted in "Unix(tm) - format" when the zip archive is saved. - - - - - An application creating a zip archive can use this flag to explicitly - specify that the file times for the entries should or should not be stored - in the zip archive in the format used by Unix. By default this flag is - false, meaning the Unix-format times are not stored in the zip - archive. - - - - When adding an entry from a file or directory, the Creation (), Access (), and Modified () times for the given entry are - automatically set from the filesystem values. When adding an entry from a - stream or string, all three values are implicitly set to DateTime.Now. - Applications can also explicitly set those times by calling . - - - - PKWARE's - zip specification describes multiple ways to format these times in a - zip file. One is the format Windows applications normally use: 100ns ticks - since January 1, 1601 UTC. The other is a format Unix applications - typically use: seconds since January 1, 1970 UTC. Each format can be - stored in an "extra field" in the zip entry when saving the zip - archive. The former uses an extra field with a Header Id of 0x000A, while - the latter uses a header ID of 0x5455, although you probably don't need to - know that. - - - - Not all tools and libraries can interpret these fields. Windows - compressed folders is one that can read the Windows Format timestamps, - while I believe the Infozip - tools can read the Unix format timestamps. Some tools and libraries may be - able to read only one or the other. DotNetZip can read or write times in - either or both formats. - - - - The times stored are taken from , , and . - - - - This property is not mutually exclusive of the property. It is possible and - legal and valid to produce a zip file that contains timestamps encoded in - the Unix format as well as in the Windows format, in addition to the LastModified time attached to each - entry in the zip archive, a time that is always stored in "DOS - format". And, notwithstanding the names PKWare uses for these time - formats, any of them can be read and written by any computer, on any - operating system. But, there are no guarantees that a program running on - Mac or Linux will gracefully handle a zip file with "Windows" formatted - times, or that an application that does not use DotNetZip but runs on - Windows will be able to handle file times in Unix format. - - - - When in doubt, test. Sorry, I haven't got a complete list of tools and - which sort of timestamps they can use and will tolerate. If you get any - good information and would like to pass it on, please do so and I will - include that information in this documentation. - - - - - - - - - Indicates whether verbose output is sent to the during AddXxx() and - ReadXxx() operations. - - - - This is a synthetic property. It returns true if the is non-null. - - - - - Returns true if an entry by the given name exists in the ZipFile. - - - the name of the entry to find - true if an entry with the given name exists; otherwise false. - - - - - Indicates whether to perform case-sensitive matching on the filename when - retrieving entries in the zipfile via the string-based indexer. - - - - The default value is false, which means don't do case-sensitive - matching. In other words, retrieving zip["ReadMe.Txt"] is the same as - zip["readme.txt"]. It really makes sense to set this to true only - if you are not running on Windows, which has case-insensitive - filenames. But since this library is not built for non-Windows platforms, - in most cases you should just leave this property alone. - - - - - Indicates whether to ignore duplicate files (report only the first entry) - when loading a zipfile. - - - - The default value is false, which will try to make all files - available (duplicates will have a "copy" suffix appended to their name). - Setting this to true prior to using Initialize to read a - zipfile will prevent this and instead just ignore the duplicates. - - - - - Indicates whether to encode entry filenames and entry comments using Unicode - (UTF-8). - - - - - The - PKWare zip specification provides for encoding file names and file - comments in either the IBM437 code page, or in UTF-8. This flag selects - the encoding according to that specification. By default, this flag is - false, and filenames and comments are encoded into the zip file in the - IBM437 codepage. Setting this flag to true will specify that filenames - and comments that cannot be encoded with IBM437 will be encoded with - UTF-8. - - - - Zip files created with strict adherence to the PKWare specification with - respect to UTF-8 encoding can contain entries with filenames containing - any combination of Unicode characters, including the full range of - characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other - alphabets. However, because at this time, the UTF-8 portion of the PKWare - specification is not broadly supported by other zip libraries and - utilities, such zip files may not be readable by your favorite zip tool or - archiver. In other words, interoperability will decrease if you set this - flag to true. - - - - In particular, Zip files created with strict adherence to the PKWare - specification with respect to UTF-8 encoding will not work well with - Explorer in Windows XP or Windows Vista, because Windows compressed - folders, as far as I know, do not support UTF-8 in zip files. Vista can - read the zip files, but shows the filenames incorrectly. Unpacking from - Windows Vista Explorer will result in filenames that have rubbish - characters in place of the high-order UTF-8 bytes. - - - - Also, zip files that use UTF-8 encoding will not work well with Java - applications that use the java.util.zip classes, as of v5.0 of the Java - runtime. The Java runtime does not correctly implement the PKWare - specification in this regard. - - - - As a result, we have the unfortunate situation that "correct" behavior by - the DotNetZip library with regard to Unicode encoding of filenames during - zip creation will result in zip files that are readable by strictly - compliant and current tools (for example the most recent release of the - commercial WinZip tool); but these zip files will not be readable by - various other tools or libraries, including Windows Explorer. - - - - The DotNetZip library can read and write zip files with UTF8-encoded - entries, according to the PKware spec. If you use DotNetZip for both - creating and reading the zip file, and you use UTF-8, there will be no - loss of information in the filenames. For example, using a self-extractor - created by this library will allow you to unpack files correctly with no - loss of information in the filenames. - - - - If you do not set this flag, it will remain false. If this flag is false, - your ZipFile will encode all filenames and comments using the - IBM437 codepage. This can cause "loss of information" on some filenames, - but the resulting zipfile will be more interoperable with other - utilities. As an example of the loss of information, diacritics can be - lost. The o-tilde character will be down-coded to plain o. The c with a - cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c. - Likewise, the O-stroke character (Unicode 248), used in Danish and - Norwegian, will be down-coded to plain o. Chinese characters cannot be - represented in codepage IBM437; when using the default encoding, Chinese - characters in filenames will be represented as ?. These are all examples - of "information loss". - - - - The loss of information associated to the use of the IBM437 encoding is - inconvenient, and can also lead to runtime errors. For example, using - IBM437, any sequence of 4 Chinese characters will be encoded as ????. If - your application creates a ZipFile, then adds two files, each with - names of four Chinese characters each, this will result in a duplicate - filename exception. In the case where you add a single file with a name - containing four Chinese characters, calling Extract() on the entry that - has question marks in the filename will result in an exception, because - the question mark is not legal for use within filenames on Windows. These - are just a few examples of the problems associated to loss of information. - - - - This flag is independent of the encoding of the content within the entries - in the zip file. Think of the zip file as a container - it supports an - encoding. Within the container are other "containers" - the file entries - themselves. The encoding within those entries is independent of the - encoding of the zip archive container for those entries. - - - - Rather than specify the encoding in a binary fashion using this flag, an - application can specify an arbitrary encoding via the property. Setting the encoding - explicitly when creating zip archives will result in non-compliant zip - files that, curiously, are fairly interoperable. The challenge is, the - PKWare specification does not provide for a way to specify that an entry - in a zip archive uses a code page that is neither IBM437 nor UTF-8. - Therefore if you set the encoding explicitly when creating a zip archive, - you must take care upon reading the zip archive to use the same code page. - If you get it wrong, the behavior is undefined and may result in incorrect - filenames, exceptions, stomach upset, hair loss, and acne. - - - - - - - Specify whether to use ZIP64 extensions when saving a zip archive. - - - - - - When creating a zip file, the default value for the property is . is - safest, in the sense that you will not get an Exception if a pre-ZIP64 - limit is exceeded. - - - - You may set the property at any time before calling Save(). - - - - When reading a zip file via the Zipfile.Read() method, DotNetZip - will properly read ZIP64-endowed zip archives, regardless of the value of - this property. DotNetZip will always read ZIP64 archives. This property - governs only whether DotNetZip will write them. Therefore, when updating - archives, be careful about setting this property after reading an archive - that may use ZIP64 extensions. - - - - An interesting question is, if you have set this property to - AsNecessary, and then successfully saved, does the resulting - archive use ZIP64 extensions or not? To learn this, check the property, after calling Save(). - - - - Have you thought about - donating? - - - - - - - - Indicates whether the archive requires ZIP64 extensions. - - - - - - This property is null (or Nothing in VB) if the archive has - not been saved, and there are fewer than 65334 ZipEntry items - contained in the archive. - - - - The Value is true if any of the following four conditions holds: - the uncompressed size of any entry is larger than 0xFFFFFFFF; the - compressed size of any entry is larger than 0xFFFFFFFF; the relative - offset of any entry within the zip archive is larger than 0xFFFFFFFF; or - there are more than 65534 entries in the archive. (0xFFFFFFFF = - 4,294,967,295). The result may not be known until a Save() is attempted - on the zip archive. The Value of this - property may be set only AFTER one of the Save() methods has been called. - - - - If none of the four conditions holds, and the archive has been saved, then - the Value is false. - - - - A Value of false does not indicate that the zip archive, as saved, - does not use ZIP64. It merely indicates that ZIP64 is not required. An - archive may use ZIP64 even when not required if the property is set to , or if the property is set to and the output stream was not - seekable. Use the property to determine if - the most recent Save() method resulted in an archive that utilized - the ZIP64 extensions. - - - - - - - - - Indicates whether the most recent Save() operation used ZIP64 extensions. - - - - - The use of ZIP64 extensions within an archive is not always necessary, and - for interoperability concerns, it may be desired to NOT use ZIP64 if - possible. The property can be - set to use ZIP64 extensions only when necessary. In those cases, - Sometimes applications want to know whether a Save() actually used ZIP64 - extensions. Applications can query this read-only property to learn - whether ZIP64 has been used in a just-saved ZipFile. - - - - The value is null (or Nothing in VB) if the archive has not - been saved. - - - - Non-null values (HasValue is true) indicate whether ZIP64 - extensions were used during the most recent Save() operation. The - ZIP64 extensions may have been used as required by any particular entry - because of its uncompressed or compressed size, or because the archive is - larger than 4294967295 bytes, or because there are more than 65534 entries - in the archive, or because the UseZip64WhenSaving property was set - to , or because the - UseZip64WhenSaving property was set to and the output stream was not seekable. - The value of this property does not indicate the reason the ZIP64 - extensions were used. - - - - - - - - - Indicates whether the most recent Read() operation read a zip file that uses - ZIP64 extensions. - - - - This property will return null (Nothing in VB) if you've added an entry after reading - the zip file. - - - - - The text encoding to use when writing new entries to the ZipFile, - for those entries that cannot be encoded with the default (IBM437) - encoding; or, the text encoding that was used when reading the entries - from the ZipFile. - - - - - In its - zip specification, PKWare describes two options for encoding - filenames and comments: using IBM437 or UTF-8. But, some archiving tools - or libraries do not follow the specification, and instead encode - characters using the system default code page. For example, WinRAR when - run on a machine in Shanghai may encode filenames with the Big-5 Chinese - (950) code page. This behavior is contrary to the Zip specification, but - it occurs anyway. - - - - When using DotNetZip to write zip archives that will be read by one of - these other archivers, set this property to specify the code page to use - when encoding the and for each ZipEntry in the zip file, for - values that cannot be encoded with the default codepage for zip files, - IBM437. This is why this property is "provisional". In all cases, IBM437 - is used where possible, in other words, where no loss of data would - result. It is possible, therefore, to have a given entry with a - Comment encoded in IBM437 and a FileName encoded with the - specified "provisional" codepage. - - - - Be aware that a zip file created after you've explicitly set the property to a value other than - IBM437 may not be compliant to the PKWare specification, and may not be - readable by compliant archivers. On the other hand, many (most?) - archivers are non-compliant and can read zip files created in arbitrary - code pages. The trick is to use or specify the proper codepage when - reading the zip. - - - - When creating a zip archive using this library, it is possible to change - the value of between each - entry you add, and between adding entries and the call to - Save(). Don't do this. It will likely result in a zipfile that is - not readable. For best interoperability, either leave alone, or specify it only once, - before adding any entries to the ZipFile instance. There is one - exception to this recommendation, described later. - - - - When using an arbitrary, non-UTF8 code page for encoding, there is no - standard way for the creator application - whether DotNetZip, WinZip, - WinRar, or something else - to formally specify in the zip file which - codepage has been used for the entries. As a result, readers of zip files - are not able to inspect the zip file and determine the codepage that was - used for the entries contained within it. It is left to the application - or user to determine the necessary codepage when reading zip files encoded - this way. In other words, if you explicitly specify the codepage when you - create the zipfile, you must explicitly specify the same codepage when - reading the zipfile. - - - - The way you specify the code page to use when reading a zip file varies - depending on the tool or library you use to read the zip. In DotNetZip, - you use a ZipFile.Read() method that accepts an encoding parameter. It - isn't possible with Windows Explorer, as far as I know, to specify an - explicit codepage to use when reading a zip. If you use an incorrect - codepage when reading a zipfile, you will get entries with filenames that - are incorrect, and the incorrect filenames may even contain characters - that are not legal for use within filenames in Windows. Extracting entries - with illegal characters in the filenames will lead to exceptions. It's too - bad, but this is just the way things are with code pages in zip - files. Caveat Emptor. - - - - Example: Suppose you create a zipfile that contains entries with - filenames that have Danish characters. If you use equal to "iso-8859-1" (cp 28591), - the filenames will be correctly encoded in the zip. But, to read that - zipfile correctly, you have to specify the same codepage at the time you - read it. If try to read that zip file with Windows Explorer or another - application that is not flexible with respect to the codepage used to - decode filenames in zipfiles, you will get a filename like "Inf�.txt". - - - - When using DotNetZip to read a zip archive, and the zip archive uses an - arbitrary code page, you must specify the encoding to use before or when - the Zipfile is READ. This means you must use a ZipFile.Read() - method that allows you to specify a System.Text.Encoding parameter. Setting - the ProvisionalAlternateEncoding property after your application has read in - the zip archive will not affect the entry names of entries that have already - been read in. - - - - And now, the exception to the rule described above. One strategy for - specifying the code page for a given zip file is to describe the code page - in a human-readable form in the Zip comment. For example, the comment may - read "Entries in this archive are encoded in the Big5 code page". For - maximum interoperability, the zip comment in this case should be encoded - in the default, IBM437 code page. In this case, the zip comment is - encoded using a different page than the filenames. To do this, Specify - ProvisionalAlternateEncoding to your desired region-specific code - page, once before adding any entries, and then reset - ProvisionalAlternateEncoding to IBM437 before setting the property and calling Save(). - - - - - This example shows how to read a zip file using the Big-5 Chinese code page - (950), and extract each entry in the zip file. For this code to work as - desired, the Zipfile must have been created using the big5 code page - (CP950). This is typical, for example, when using WinRar on a machine with - CP950 set as the default code page. In that case, the names of entries - within the Zip archive will be stored in that code page, and reading the zip - archive must be done using that code page. If the application did not use - the correct code page in ZipFile.Read(), then names of entries within the - zip archive would not be correctly retrieved. - - using (var zip = ZipFile.Read(zipFileName, System.Text.Encoding.GetEncoding("big5"))) - { - // retrieve and extract an entry using a name encoded with CP950 - zip[MyDesiredEntry].Extract("unpack"); - } - - - - Using zip As ZipFile = ZipFile.Read(ZipToExtract, System.Text.Encoding.GetEncoding("big5")) - ' retrieve and extract an entry using a name encoded with CP950 - zip(MyDesiredEntry).Extract("unpack") - End Using - - - - DefaultEncoding - - - - A Text Encoding to use when encoding the filenames and comments for - all the ZipEntry items, during a ZipFile.Save() operation. - - - - Whether the encoding specified here is used during the save depends - on . - - - - - - A flag that tells if and when this instance should apply - AlternateEncoding to encode the filenames and comments associated to - of ZipEntry objects contained within this instance. - - - - - Gets or sets the TextWriter to which status messages are delivered - for the instance. - - - - If the TextWriter is set to a non-null value, then verbose output is sent - to the TextWriter during Add, Read, Save and - Extract operations. Typically, console applications might use - Console.Out and graphical or headless applications might use a - System.IO.StringWriter. The output of this is suitable for viewing - by humans. - - - - - In this example, a console application instantiates a ZipFile, then - sets the StatusMessageTextWriter to Console.Out. At that - point, all verbose status messages for that ZipFile are sent to the - console. - - - - using (ZipFile zip= ZipFile.Read(FilePath)) - { - zip.StatusMessageTextWriter= System.Console.Out; - // messages are sent to the console during extraction - zip.ExtractAll(); - } - - - - Using zip As ZipFile = ZipFile.Read(FilePath) - zip.StatusMessageTextWriter= System.Console.Out - 'Status Messages will be sent to the console during extraction - zip.ExtractAll() - End Using - - - - In this example, a Windows Forms application instantiates a - ZipFile, then sets the StatusMessageTextWriter to a - StringWriter. At that point, all verbose status messages for that - ZipFile are sent to the StringWriter. - - - - var sw = new System.IO.StringWriter(); - using (ZipFile zip= ZipFile.Read(FilePath)) - { - zip.StatusMessageTextWriter= sw; - zip.ExtractAll(); - } - Console.WriteLine("{0}", sw.ToString()); - - - - Dim sw as New System.IO.StringWriter - Using zip As ZipFile = ZipFile.Read(FilePath) - zip.StatusMessageTextWriter= sw - zip.ExtractAll() - End Using - 'Status Messages are now available in sw - - - - - - - Gets or sets the name for the folder to store the temporary file - this library writes when saving a zip archive. - - - - - This library will create a temporary file when saving a Zip archive to a - file. This file is written when calling one of the Save() methods - that does not save to a stream, or one of the SaveSelfExtractor() - methods. - - - - By default, the library will create the temporary file in the directory - specified for the file itself, via the property or via - the method. - - - - Setting this property allows applications to override this default - behavior, so that the library will create the temporary file in the - specified folder. For example, to have the library create the temporary - file in the current working directory, regardless where the ZipFile - is saved, specfy ".". To revert to the default behavior, set this - property to null (Nothing in VB). - - - - When setting the property to a non-null value, the folder specified must - exist; if it does not an exception is thrown. The application should have - write and delete permissions on the folder. The permissions are not - explicitly checked ahead of time; if the application does not have the - appropriate rights, an exception will be thrown at the time Save() - is called. - - - - There is no temporary file created when reading a zip archive. When - saving to a Stream, there is no temporary file created. For example, if - the application is an ASP.NET application and calls Save() - specifying the Response.OutputStream as the output stream, there is - no temporary file created. - - - - - Thrown when setting the property if the directory does not exist. - - - - - - Sets the password to be used on the ZipFile instance. - - - - - - When writing a zip archive, this password is applied to the entries, not - to the zip archive itself. It applies to any ZipEntry subsequently - added to the ZipFile, using one of the AddFile, - AddDirectory, AddEntry, or AddItem methods, etc. - When reading a zip archive, this property applies to any entry - subsequently extracted from the ZipFile using one of the Extract - methods on the ZipFile class. - - - - When writing a zip archive, keep this in mind: though the password is set - on the ZipFile object, according to the Zip spec, the "directory" of the - archive - in other words the list of entries or files contained in the archive - is - not encrypted with the password, or protected in any way. If you set the - Password property, the password actually applies to individual entries - that are added to the archive, subsequent to the setting of this property. - The list of filenames in the archive that is eventually created will - appear in clear text, but the contents of the individual files are - encrypted. This is how Zip encryption works. - - - - One simple way around this limitation is to simply double-wrap sensitive - filenames: Store the files in a zip file, and then store that zip file - within a second, "outer" zip file. If you apply a password to the outer - zip file, then readers will be able to see that the outer zip file - contains an inner zip file. But readers will not be able to read the - directory or file list of the inner zip file. - - - - If you set the password on the ZipFile, and then add a set of files - to the archive, then each entry is encrypted with that password. You may - also want to change the password between adding different entries. If you - set the password, add an entry, then set the password to null - (Nothing in VB), and add another entry, the first entry is - encrypted and the second is not. If you call AddFile(), then set - the Password property, then call ZipFile.Save, the file - added will not be password-protected, and no warning will be generated. - - - - When setting the Password, you may also want to explicitly set the property, to specify how to encrypt the entries added - to the ZipFile. If you set the Password to a non-null value and do not - set , then PKZip 2.0 ("Weak") encryption is used. - This encryption is relatively weak but is very interoperable. If you set - the password to a null value (Nothing in VB), Encryption is - reset to None. - - - - All of the preceding applies to writing zip archives, in other words when - you use one of the Save methods. To use this property when reading or an - existing ZipFile, do the following: set the Password property on the - ZipFile, then call one of the Extract() overloads on the . In this case, the entry is extracted using the - Password that is specified on the ZipFile instance. If you - have not set the Password property, then the password is - null, and the entry is extracted with no password. - - - - If you set the Password property on the ZipFile, then call - Extract() an entry that has not been encrypted with a password, the - password is not used for that entry, and the ZipEntry is extracted - as normal. In other words, the password is used only if necessary. - - - - The class also has a Password property. It takes precedence - over this property on the ZipFile. Typically, you would use the - per-entry Password when most entries in the zip archive use one password, - and a few entries use a different password. If all entries in the zip - file use the same password, then it is simpler to just set this property - on the ZipFile itself, whether creating a zip archive or extracting - a zip archive. - - - - - - - This example creates a zip file, using password protection for the - entries, and then extracts the entries from the zip file. When creating - the zip file, the Readme.txt file is not protected with a password, but - the other two are password-protected as they are saved. During extraction, - each file is extracted with the appropriate password. - - - // create a file with encryption - using (ZipFile zip = new ZipFile()) - { - zip.AddFile("ReadMe.txt"); - zip.Password= "!Secret1"; - zip.AddFile("MapToTheSite-7440-N49th.png"); - zip.AddFile("2008-Regional-Sales-Report.pdf"); - zip.Save("EncryptedArchive.zip"); - } - - // extract entries that use encryption - using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) - { - zip.Password= "!Secret1"; - zip.ExtractAll("extractDir"); - } - - - - - Using zip As New ZipFile - zip.AddFile("ReadMe.txt") - zip.Password = "123456!" - zip.AddFile("MapToTheSite-7440-N49th.png") - zip.Password= "!Secret1"; - zip.AddFile("2008-Regional-Sales-Report.pdf") - zip.Save("EncryptedArchive.zip") - End Using - - - ' extract entries that use encryption - Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) - zip.Password= "!Secret1" - zip.ExtractAll("extractDir") - End Using - - - - - - ZipFile.Encryption - ZipEntry.Password - - - - The action the library should take when extracting a file that already - exists. - - - - - This property affects the behavior of the Extract methods (one of the - Extract() or ExtractWithPassword() overloads), when - extraction would would overwrite an existing filesystem file. If you do - not set this property, the library throws an exception when extracting an - entry would overwrite an existing file. - - - - This property has no effect when extracting to a stream, or when the file - to be extracted does not already exist. - - - - - - - The action the library should take when an error is encountered while - opening or reading files as they are saved into a zip archive. - - - - - Errors can occur as a file is being saved to the zip archive. For - example, the File.Open may fail, or a File.Read may fail, because of - lock conflicts or other reasons. - - - - The first problem might occur after having called AddDirectory() on a - directory that contains a Clipper .dbf file; the file is locked by - Clipper and cannot be opened for read by another process. An example of - the second problem might occur when trying to zip a .pst file that is in - use by Microsoft Outlook. Outlook locks a range on the file, which allows - other processes to open the file, but not read it in its entirety. - - - - This property tells DotNetZip what you would like to do in the case of - these errors. The primary options are: ZipErrorAction.Throw to - throw an exception (this is the default behavior if you don't set this - property); ZipErrorAction.Skip to Skip the file for which there - was an error and continue saving; ZipErrorAction.Retry to Retry - the entry that caused the problem; or - ZipErrorAction.InvokeErrorEvent to invoke an event handler. - - - - This property is implicitly set to ZipErrorAction.InvokeErrorEvent - if you add a handler to the event. If you set - this property to something other than - ZipErrorAction.InvokeErrorEvent, then the ZipError - event is implicitly cleared. What it means is you can set one or the - other (or neither), depending on what you want, but you never need to set - both. - - - - As with some other properties on the ZipFile class, like , , and , setting this property on a ZipFile - instance will cause the specified ZipErrorAction to be used on all - items that are subsequently added to the - ZipFile instance. If you set this property after you have added - items to the ZipFile, but before you have called Save(), - those items will not use the specified error handling action. - - - - If you want to handle any errors that occur with any entry in the zip - file in the same way, then set this property once, before adding any - entries to the zip archive. - - - - If you set this property to ZipErrorAction.Skip and you'd like to - learn which files may have been skipped after a Save(), you can - set the on the ZipFile before - calling Save(). A message will be emitted into that writer for - each skipped file, if any. - - - - - - This example shows how to tell DotNetZip to skip any files for which an - error is generated during the Save(). - - Public Sub SaveZipFile() - Dim SourceFolder As String = "fodder" - Dim DestFile As String = "eHandler.zip" - Dim sw as New StringWriter - Using zipArchive As ZipFile = New ZipFile - ' Tell DotNetZip to skip any files for which it encounters an error - zipArchive.ZipErrorAction = ZipErrorAction.Skip - zipArchive.StatusMessageTextWriter = sw - zipArchive.AddDirectory(SourceFolder) - zipArchive.Save(DestFile) - End Using - ' examine sw here to see any messages - End Sub - - - - - - - - - - The Encryption to use for entries added to the ZipFile. - - - - - Set this when creating a zip archive, or when updating a zip archive. The - specified Encryption is applied to the entries subsequently added to the - ZipFile instance. Applications do not need to set the - Encryption property when reading or extracting a zip archive. - - - - If you set this to something other than EncryptionAlgorithm.None, you - will also need to set the . - - - - As with some other properties on the ZipFile class, like and , setting this - property on a ZipFile instance will cause the specified - EncryptionAlgorithm to be used on all items - that are subsequently added to the ZipFile instance. In other - words, if you set this property after you have added items to the - ZipFile, but before you have called Save(), those items will - not be encrypted or protected with a password in the resulting zip - archive. To get a zip archive with encrypted entries, set this property, - along with the property, before calling - AddFile, AddItem, or AddDirectory (etc.) on the - ZipFile instance. - - - - If you read a ZipFile, you can modify the Encryption on an - encrypted entry, only by setting the Encryption property on the - ZipEntry itself. Setting the Encryption property on the - ZipFile, once it has been created via a call to - ZipFile.Read(), does not affect entries that were previously read. - - - - For example, suppose you read a ZipFile, and there is an encrypted - entry. Setting the Encryption property on that ZipFile and - then calling Save() on the ZipFile does not update the - Encryption used for the entries in the archive. Neither is an - exception thrown. Instead, what happens during the Save() is that - all previously existing entries are copied through to the new zip archive, - with whatever encryption and password that was used when originally - creating the zip archive. Upon re-reading that archive, to extract - entries, applications should use the original password or passwords, if - any. - - - - Suppose an application reads a ZipFile, and there is an encrypted - entry. Setting the Encryption property on that ZipFile and - then adding new entries (via AddFile(), AddEntry(), etc) - and then calling Save() on the ZipFile does not update the - Encryption on any of the entries that had previously been in the - ZipFile. The Encryption property applies only to the - newly-added entries. - - - - - - - This example creates a zip archive that uses encryption, and then extracts - entries from the archive. When creating the zip archive, the ReadMe.txt - file is zipped without using a password or encryption. The other files - use encryption. - - - - // Create a zip archive with AES Encryption. - using (ZipFile zip = new ZipFile()) - { - zip.AddFile("ReadMe.txt"); - zip.Encryption= EncryptionAlgorithm.WinZipAes256; - zip.Password= "Top.Secret.No.Peeking!"; - zip.AddFile("7440-N49th.png"); - zip.AddFile("2008-Regional-Sales-Report.pdf"); - zip.Save("EncryptedArchive.zip"); - } - - // Extract a zip archive that uses AES Encryption. - // You do not need to specify the algorithm during extraction. - using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) - { - zip.Password= "Top.Secret.No.Peeking!"; - zip.ExtractAll("extractDirectory"); - } - - - - ' Create a zip that uses Encryption. - Using zip As New ZipFile() - zip.Encryption= EncryptionAlgorithm.WinZipAes256 - zip.Password= "Top.Secret.No.Peeking!" - zip.AddFile("ReadMe.txt") - zip.AddFile("7440-N49th.png") - zip.AddFile("2008-Regional-Sales-Report.pdf") - zip.Save("EncryptedArchive.zip") - End Using - - ' Extract a zip archive that uses AES Encryption. - ' You do not need to specify the algorithm during extraction. - Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) - zip.Password= "Top.Secret.No.Peeking!" - zip.ExtractAll("extractDirectory") - End Using - - - - - ZipFile.Password - ZipEntry.Encryption - - - - A callback that allows the application to specify the compression level - to use for entries subsequently added to the zip archive. - - - - - - With this callback, the DotNetZip library allows the application to - determine whether compression will be used, at the time of the - Save. This may be useful if the application wants to favor - speed over size, and wants to defer the decision until the time of - Save. - - - - Typically applications set the property on - the ZipFile or on each ZipEntry to determine the level of - compression used. This is done at the time the entry is added to the - ZipFile. Setting the property to - Ionic.Zlib.CompressionLevel.None means no compression will be used. - - - - This callback allows the application to defer the decision on the - CompressionLevel to use, until the time of the call to - ZipFile.Save(). The callback is invoked once per ZipEntry, - at the time the data for the entry is being written out as part of a - Save() operation. The application can use whatever criteria it - likes in determining the level to return. For example, an application may - wish that no .mp3 files should be compressed, because they are already - compressed and the extra compression is not worth the CPU time incurred, - and so can return None for all .mp3 entries. - - - - The library determines whether compression will be attempted for an entry - this way: If the entry is a zero length file, or a directory, no - compression is used. Otherwise, if this callback is set, it is invoked - and the CompressionLevel is set to the return value. If this - callback has not been set, then the previously set value for - CompressionLevel is used. - - - - - - - The maximum size of an output segment, when saving a split Zip file. - - - - Make sure you do not read from this field if you've set the value using - - - - Set this to a non-zero value before calling or to specify that the ZipFile should be saved as a - split archive, also sometimes called a spanned archive. Some also - call them multi-file archives. - - - - A split zip archive is saved in a set of discrete filesystem files, - rather than in a single file. This is handy when transmitting the - archive in email or some other mechanism that has a limit to the size of - each file. The first file in a split archive will be named - basename.z01, the second will be named basename.z02, and - so on. The final file is named basename.zip. According to the zip - specification from PKWare, the minimum value is 65536, for a 64k segment - size. The maximum number of segments allows in a split archive is 99. - - - - The value of this property determines the maximum size of a split - segment when writing a split archive. For example, suppose you have a - ZipFile that would save to a single file of 200k. If you set the - MaxOutputSegmentSize to 65536 before calling Save(), you - will get four distinct output files. On the other hand if you set this - property to 256k, then you will get a single-file archive for that - ZipFile. - - - - The size of each split output file will be as large as possible, up to - the maximum size set here. The zip specification requires that some data - fields in a zip archive may not span a split boundary, and an output - segment may be smaller than the maximum if necessary to avoid that - problem. Also, obviously the final segment of the archive may be smaller - than the maximum segment size. Segments will never be larger than the - value set with this property. - - - - You can save a split Zip file only when saving to a regular filesystem - file. It's not possible to save a split zip file as a self-extracting - archive, nor is it possible to save a split zip file to a stream. When - saving to a SFX or to a Stream, this property is ignored. - - - - About interoperability: Split or spanned zip files produced by DotNetZip - can be read by WinZip or PKZip, and vice-versa. Segmented zip files may - not be readable by other tools, if those other tools don't support zip - spanning or splitting. When in doubt, test. I don't believe Windows - Explorer can extract a split archive. - - - - This property has no effect when reading a split archive. You can read - a split archive in the normal way with DotNetZip. - - - - When saving a zip file, if you want a regular zip file rather than a - split zip file, don't set this property, or set it to Zero. - - - - If you read a split archive, with and - then subsequently call ZipFile.Save(), unless you set this - property before calling Save(), you will get a normal, - single-file archive. - - - - - - - - The maximum size of an output segment, when saving a split Zip file. - - - - If you set this value, make sure you do not accidently use in your code - - - - Set this to a non-zero value before calling or to specify that the ZipFile should be saved as a - split archive, also sometimes called a spanned archive. Some also - call them multi-file archives. - - - - A split zip archive is saved in a set of discrete filesystem files, - rather than in a single file. This is handy when transmitting the - archive in email or some other mechanism that has a limit to the size of - each file. The first file in a split archive will be named - basename.z01, the second will be named basename.z02, and - so on. The final file is named basename.zip. According to the zip - specification from PKWare, the minimum value is 65536, for a 64k segment - size. The maximum number of segments allows in a split archive is 99. - - - - The value of this property determines the maximum size of a split - segment when writing a split archive. For example, suppose you have a - ZipFile that would save to a single file of 200k. If you set the - MaxOutputSegmentSize to 65536 before calling Save(), you - will get four distinct output files. On the other hand if you set this - property to 256k, then you will get a single-file archive for that - ZipFile. - - - - The size of each split output file will be as large as possible, up to - the maximum size set here. The zip specification requires that some data - fields in a zip archive may not span a split boundary, and an output - segment may be smaller than the maximum if necessary to avoid that - problem. Also, obviously the final segment of the archive may be smaller - than the maximum segment size. Segments will never be larger than the - value set with this property. - - - - You can save a split Zip file only when saving to a regular filesystem - file. It's not possible to save a split zip file as a self-extracting - archive, nor is it possible to save a split zip file to a stream. When - saving to a SFX or to a Stream, this property is ignored. - - - - About interoperability: Split or spanned zip files produced by DotNetZip - can be read by WinZip or PKZip, and vice-versa. Segmented zip files may - not be readable by other tools, if those other tools don't support zip - spanning or splitting. When in doubt, test. I don't believe Windows - Explorer can extract a split archive. - - - - This property has no effect when reading a split archive. You can read - a split archive in the normal way with DotNetZip. - - - - When saving a zip file, if you want a regular zip file rather than a - split zip file, don't set this property, or set it to Zero. - - - - If you read a split archive, with and - then subsequently call ZipFile.Save(), unless you set this - property before calling Save(), you will get a normal, - single-file archive. - - - - - - - - Returns the number of segments used in the most recent Save() operation. - - - - This is normally zero, unless you have set the property. If you have set , and then you save a file, after the call to - Save() completes, you can read this value to learn the number of segments that - were created. - - - If you call Save("Archive.zip"), and it creates 5 segments, then you - will have filesystem files named Archive.z01, Archive.z02, Archive.z03, - Archive.z04, and Archive.zip, and the value of this property will be 5. - - - - - - - The size threshold for an entry, above which a parallel deflate is used. - - - - - - DotNetZip will use multiple threads to compress any ZipEntry, - if the entry is larger than the given size. Zero means "always - use parallel deflate", while -1 means "never use parallel - deflate". The default value for this property is 512k. Aside - from the special values of 0 and 1, the minimum value is 65536. - - - - If the entry size cannot be known before compression, as with a - read-forward stream, then Parallel deflate will never be - performed, unless the value of this property is zero. - - - - A parallel deflate operations will speed up the compression of - large files, on computers with multiple CPUs or multiple CPU - cores. For files above 1mb, on a dual core or dual-cpu (2p) - machine, the time required to compress the file can be 70% of the - single-threaded deflate. For very large files on 4p machines the - compression can be done in 30% of the normal time. The downside - is that parallel deflate consumes extra memory during the deflate, - and the deflation is not as effective. - - - - Parallel deflate tends to yield slightly less compression when - compared to as single-threaded deflate; this is because the original - data stream is split into multiple independent buffers, each of which - is compressed in parallel. But because they are treated - independently, there is no opportunity to share compression - dictionaries. For that reason, a deflated stream may be slightly - larger when compressed using parallel deflate, as compared to a - traditional single-threaded deflate. Sometimes the increase over the - normal deflate is as much as 5% of the total compressed size. For - larger files it can be as small as 0.1%. - - - - Multi-threaded compression does not give as much an advantage when - using Encryption. This is primarily because encryption tends to slow - down the entire pipeline. Also, multi-threaded compression gives less - of an advantage when using lower compression levels, for example . You may have to - perform some tests to determine the best approach for your situation. - - - - - - - - - - The maximum number of buffer pairs to use when performing - parallel compression. - - - - - This property sets an upper limit on the number of memory - buffer pairs to create when performing parallel - compression. The implementation of the parallel - compression stream allocates multiple buffers to - facilitate parallel compression. As each buffer fills up, - the stream uses - ThreadPool.QueueUserWorkItem() to compress those - buffers in a background threadpool thread. After a buffer - is compressed, it is re-ordered and written to the output - stream. - - - - A higher number of buffer pairs enables a higher degree of - parallelism, which tends to increase the speed of compression on - multi-cpu computers. On the other hand, a higher number of buffer - pairs also implies a larger memory consumption, more active worker - threads, and a higher cpu utilization for any compression. This - property enables the application to limit its memory consumption and - CPU utilization behavior depending on requirements. - - - - For each compression "task" that occurs in parallel, there are 2 - buffers allocated: one for input and one for output. This property - sets a limit for the number of pairs. The total amount of storage - space allocated for buffering will then be (N*S*2), where N is the - number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer - pairs per CPU core, so if your machine has 4 cores, and you retain - the default buffer size of 128k, then the - ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer - memory in total, or 4mb, in blocks of 128kb. If you then set this - property to 8, then the number will be 8 * 2 * 128kb of buffer - memory, or 2mb. - - - - CPU utilization will also go up with additional buffers, because a - larger number of buffer pairs allows a larger number of background - threads to compress in parallel. If you find that parallel - compression is consuming too much memory or CPU, you can adjust this - value downward. - - - - The default value is 16. Different values may deliver better or - worse results, depending on your priorities and the dynamic - performance characteristics of your storage and compute resources. - - - - This property is not the number of buffer pairs to use; it is an - upper limit. An illustration: Suppose you have an application that - uses the default value of this property (which is 16), and it runs - on a machine with 2 CPU cores. In that case, DotNetZip will allocate - 4 buffer pairs per CPU core, for a total of 8 pairs. The upper - limit specified by this property has no effect. - - - - The application can set this value at any time - before calling ZipFile.Save(). - - - - - - - - Provides a string representation of the instance. - a string representation of the instance. - - - - Returns the version number on the DotNetZip assembly. - - - - - This property is exposed as a convenience. Callers could also get the - version value by retrieving GetName().Version on the - System.Reflection.Assembly object pointing to the DotNetZip - assembly. But sometimes it is not clear which assembly is being loaded. - This property makes it clear. - - - This static property is primarily useful for diagnostic purposes. - - - - - - Creates a new ZipFile instance, using the specified filename. - - - - - Applications can use this constructor to create a new ZipFile for writing, - or to slurp in an existing zip archive for read and update purposes. - - - - To create a new zip archive, an application can call this constructor, - passing the name of a file that does not exist. The name may be a fully - qualified path. Then the application can add directories or files to the - ZipFile via AddDirectory(), AddFile(), AddItem() - and then write the zip archive to the disk by calling Save(). The - zip file is not actually opened and written to the disk until the - application calls ZipFile.Save(). At that point the new zip file - with the given name is created. - - - - If you won't know the name of the Zipfile until the time you call - ZipFile.Save(), or if you plan to save to a stream (which has no - name), then you should use the no-argument constructor. - - - - The application can also call this constructor to read an existing zip - archive. passing the name of a valid zip file that does exist. But, it's - better form to use the static method, - passing the name of the zip file, because using ZipFile.Read() in - your code communicates very clearly what you are doing. In either case, - the file is then read into the ZipFile instance. The app can then - enumerate the entries or can modify the zip file, for example adding - entries, removing entries, changing comments, and so on. - - - - One advantage to this parameterized constructor: it allows applications to - use the same code to add items to a zip archive, regardless of whether the - zip file exists. - - - - Instances of the ZipFile class are not multi-thread safe. You may - not party on a single instance with multiple threads. You may have - multiple threads that each use a distinct ZipFile instance, or you - can synchronize multi-thread access to a single instance. - - - - By the way, since DotNetZip is so easy to use, don't you think you should - donate $5 or $10? - - - - - - Thrown if name refers to an existing file that is not a valid zip file. - - - - This example shows how to create a zipfile, and add a few files into it. - - String ZipFileToCreate = "archive1.zip"; - String DirectoryToZip = "c:\\reports"; - using (ZipFile zip = new ZipFile()) - { - // Store all files found in the top level directory, into the zip archive. - String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); - zip.AddFiles(filenames, "files"); - zip.Save(ZipFileToCreate); - } - - - - Dim ZipFileToCreate As String = "archive1.zip" - Dim DirectoryToZip As String = "c:\reports" - Using zip As ZipFile = New ZipFile() - Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) - zip.AddFiles(filenames, "files") - zip.Save(ZipFileToCreate) - End Using - - - - The filename to use for the new zip archive. - - - - - Creates a new ZipFile instance, using the specified name for the - filename, and the specified Encoding. - - - - - See the documentation on the ZipFile - constructor that accepts a single string argument for basic - information on all the ZipFile constructors. - - - - The Encoding is used as the default alternate encoding for entries with - filenames or comments that cannot be encoded with the IBM437 code page. - This is equivalent to setting the property on the ZipFile - instance after construction. - - - - Instances of the ZipFile class are not multi-thread safe. You may - not party on a single instance with multiple threads. You may have - multiple threads that each use a distinct ZipFile instance, or you - can synchronize multi-thread access to a single instance. - - - - - - Thrown if name refers to an existing file that is not a valid zip file. - - - The filename to use for the new zip archive. - The Encoding is used as the default alternate - encoding for entries with filenames or comments that cannot be encoded - with the IBM437 code page. - - - - Create a zip file, without specifying a target filename or stream to save to. - - - - - See the documentation on the ZipFile - constructor that accepts a single string argument for basic - information on all the ZipFile constructors. - - - - After instantiating with this constructor and adding entries to the - archive, the application should call or - to save to a file or a - stream, respectively. The application can also set the - property and then call the no-argument method. (This - is the preferred approach for applications that use the library through - COM interop.) If you call the no-argument method - without having set the Name of the ZipFile, either through - the parameterized constructor or through the explicit property , the - Save() will throw, because there is no place to save the file. - - - Instances of the ZipFile class are not multi-thread safe. You may - have multiple threads that each use a distinct ZipFile instance, or - you can synchronize multi-thread access to a single instance. - - - - - This example creates a Zip archive called Backup.zip, containing all the files - in the directory DirectoryToZip. Files within subdirectories are not zipped up. - - using (ZipFile zip = new ZipFile()) - { - // Store all files found in the top level directory, into the zip archive. - // note: this code does not recurse subdirectories! - String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); - zip.AddFiles(filenames, "files"); - zip.Save("Backup.zip"); - } - - - - Using zip As New ZipFile - ' Store all files found in the top level directory, into the zip archive. - ' note: this code does not recurse subdirectories! - Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) - zip.AddFiles(filenames, "files") - zip.Save("Backup.zip") - End Using - - - - - - Create a zip file, specifying a text Encoding, but without specifying a - target filename or stream to save to. - - - - - See the documentation on the ZipFile - constructor that accepts a single string argument for basic - information on all the ZipFile constructors. - - - - - - The Encoding is used as the default alternate encoding for entries with - filenames or comments that cannot be encoded with the IBM437 code page. - - - - - Creates a new ZipFile instance, using the specified name for the - filename, and the specified status message writer. - - - - - See the documentation on the ZipFile - constructor that accepts a single string argument for basic - information on all the ZipFile constructors. - - - - This version of the constructor allows the caller to pass in a TextWriter, - to which verbose messages will be written during extraction or creation of - the zip archive. A console application may wish to pass - System.Console.Out to get messages on the Console. A graphical or headless - application may wish to capture the messages in a different - TextWriter, for example, a StringWriter, and then display - the messages in a TextBox, or generate an audit log of ZipFile operations. - - - - To encrypt the data for the files added to the ZipFile instance, - set the Password property after creating the ZipFile instance. - - - - Instances of the ZipFile class are not multi-thread safe. You may - not party on a single instance with multiple threads. You may have - multiple threads that each use a distinct ZipFile instance, or you - can synchronize multi-thread access to a single instance. - - - - - - Thrown if name refers to an existing file that is not a valid zip file. - - - - - using (ZipFile zip = new ZipFile("Backup.zip", Console.Out)) - { - // Store all files found in the top level directory, into the zip archive. - // note: this code does not recurse subdirectories! - // Status messages will be written to Console.Out - String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); - zip.AddFiles(filenames); - zip.Save(); - } - - - - Using zip As New ZipFile("Backup.zip", Console.Out) - ' Store all files found in the top level directory, into the zip archive. - ' note: this code does not recurse subdirectories! - ' Status messages will be written to Console.Out - Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) - zip.AddFiles(filenames) - zip.Save() - End Using - - - - The filename to use for the new zip archive. - A TextWriter to use for writing - verbose status messages. - - - - Creates a new ZipFile instance, using the specified name for the - filename, the specified status message writer, and the specified Encoding. - - - - - This constructor works like the ZipFile - constructor that accepts a single string argument. See that - reference for detail on what this constructor does. - - - - This version of the constructor allows the caller to pass in a - TextWriter, and an Encoding. The TextWriter will collect - verbose messages that are generated by the library during extraction or - creation of the zip archive. A console application may wish to pass - System.Console.Out to get messages on the Console. A graphical or - headless application may wish to capture the messages in a different - TextWriter, for example, a StringWriter, and then display - the messages in a TextBox, or generate an audit log of - ZipFile operations. - - - - The Encoding is used as the default alternate encoding for entries - with filenames or comments that cannot be encoded with the IBM437 code - page. This is a equivalent to setting the property on the ZipFile - instance after construction. - - - - To encrypt the data for the files added to the ZipFile instance, - set the Password property after creating the ZipFile - instance. - - - - Instances of the ZipFile class are not multi-thread safe. You may - not party on a single instance with multiple threads. You may have - multiple threads that each use a distinct ZipFile instance, or you - can synchronize multi-thread access to a single instance. - - - - - - Thrown if fileName refers to an existing file that is not a valid zip file. - - - The filename to use for the new zip archive. - A TextWriter to use for writing verbose - status messages. - - The Encoding is used as the default alternate encoding for entries with - filenames or comments that cannot be encoded with the IBM437 code page. - - - - - Initialize a ZipFile instance by reading in a zip file. - - - - - - This method is primarily useful from COM Automation environments, when - reading or extracting zip files. In COM, it is not possible to invoke - parameterized constructors for a class. A COM Automation application can - update a zip file by using the default (no argument) - constructor, then calling Initialize() to read the contents - of an on-disk zip archive into the ZipFile instance. - - - - .NET applications are encouraged to use the ZipFile.Read() methods - for better clarity. - - - - the name of the existing zip file to read in. - - - - This is an integer indexer into the Zip archive. - - - - - This property is read-only. - - - - Internally, the ZipEntry instances that belong to the - ZipFile are stored in a Dictionary. When you use this - indexer the first time, it creates a read-only - List<ZipEntry> from the Dictionary.Values Collection. - If at any time you modify the set of entries in the ZipFile, - either by adding an entry, removing an entry, or renaming an - entry, a new List will be created, and the numeric indexes for the - remaining entries may be different. - - - - This means you cannot rename any ZipEntry from - inside an enumeration of the zip file. - - - - The index value. - - - - - - The ZipEntry within the Zip archive at the specified index. If the - entry does not exist in the archive, this indexer throws. - - - - - - This is a name-based indexer into the Zip archive. - - - - - This property is read-only. - - - - The property on the ZipFile - determines whether retrieval via this indexer is done via case-sensitive - comparisons. By default, retrieval is not case sensitive. This makes - sense on Windows, in which filesystems are not case sensitive. - - - - Regardless of case-sensitivity, it is not always the case that - this[value].FileName == value. In other words, the FileName - property of the ZipEntry retrieved with this indexer, may or may - not be equal to the index value. - - - - This is because DotNetZip performs a normalization of filenames passed to - this indexer, before attempting to retrieve the item. That normalization - includes: removal of a volume letter and colon, swapping backward slashes - for forward slashes. So, zip["dir1\\entry1.txt"].FileName == - "dir1/entry.txt". - - - - Directory entries in the zip file may be retrieved via this indexer only - with names that have a trailing slash. DotNetZip automatically appends a - trailing slash to the names of any directory entries added to a zip. - - - - - - This example extracts only the entries in a zip file that are .txt files. - - using (ZipFile zip = ZipFile.Read("PackedDocuments.zip")) - { - foreach (string s1 in zip.EntryFilenames) - { - if (s1.EndsWith(".txt")) - zip[s1].Extract("textfiles"); - } - } - - - Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip") - Dim s1 As String - For Each s1 In zip.EntryFilenames - If s1.EndsWith(".txt") Then - zip(s1).Extract("textfiles") - End If - Next - End Using - - - - - - Thrown if the caller attempts to assign a non-null value to the indexer. - - - - The name of the file, including any directory path, to retrieve from the - zip. The filename match is not case-sensitive by default; you can use the - property to change this behavior. The - pathname can use forward-slashes or backward slashes. - - - - The ZipEntry within the Zip archive, given by the specified - filename. If the named entry does not exist in the archive, this indexer - returns null (Nothing in VB). - - - - - - The list of filenames for the entries contained within the zip archive. - - - - According to the ZIP specification, the names of the entries use forward - slashes in pathnames. If you are scanning through the list, you may have - to swap forward slashes for backslashes. - - - - - - This example shows one way to test if a filename is already contained - within a zip archive. - - String zipFileToRead= "PackedDocuments.zip"; - string candidate = "DatedMaterial.xps"; - using (ZipFile zip = new ZipFile(zipFileToRead)) - { - if (zip.EntryFilenames.Contains(candidate)) - Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", - candidate, - zipFileName); - else - Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", - candidate, - zipFileName); - Console.WriteLine(); - } - - - Dim zipFileToRead As String = "PackedDocuments.zip" - Dim candidate As String = "DatedMaterial.xps" - Using zip As ZipFile.Read(ZipFileToRead) - If zip.EntryFilenames.Contains(candidate) Then - Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", _ - candidate, _ - zipFileName) - Else - Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", _ - candidate, _ - zipFileName) - End If - Console.WriteLine - End Using - - - - - The list of strings for the filenames contained within the Zip archive. - - - - - - Returns the readonly collection of entries in the Zip archive. - - - - - - If there are no entries in the current ZipFile, the value returned is a - non-null zero-element collection. If there are entries in the zip file, - the elements are returned in no particular order. - - - This is the implied enumerator on the ZipFile class. If you use a - ZipFile instance in a context that expects an enumerator, you will - get this collection. - - - - - - - Returns a readonly collection of entries in the Zip archive, sorted by FileName. - - - - If there are no entries in the current ZipFile, the value returned - is a non-null zero-element collection. If there are entries in the zip - file, the elements are returned sorted by the name of the entry. - - - - - This example fills a Windows Forms ListView with the entries in a zip file. - - - using (ZipFile zip = ZipFile.Read(zipFile)) - { - foreach (ZipEntry entry in zip.EntriesSorted) - { - ListViewItem item = new ListViewItem(n.ToString()); - n++; - string[] subitems = new string[] { - entry.FileName.Replace("/","\\"), - entry.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), - entry.UncompressedSize.ToString(), - String.Format("{0,5:F0}%", entry.CompressionRatio), - entry.CompressedSize.ToString(), - (entry.UsesEncryption) ? "Y" : "N", - String.Format("{0:X8}", entry.Crc)}; - - foreach (String s in subitems) - { - ListViewItem.ListViewSubItem subitem = new ListViewItem.ListViewSubItem(); - subitem.Text = s; - item.SubItems.Add(subitem); - } - - this.listView1.Items.Add(item); - } - } - - - - - - - - Returns the number of entries in the Zip archive. - - - - - Removes the given ZipEntry from the zip archive. - - - - - After calling RemoveEntry, the application must call Save to - make the changes permanent. - - - - - Thrown if the specified ZipEntry does not exist in the ZipFile. - - - - In this example, all entries in the zip archive dating from before - December 31st, 2007, are removed from the archive. This is actually much - easier if you use the RemoveSelectedEntries method. But I needed an - example for RemoveEntry, so here it is. - - String ZipFileToRead = "ArchiveToModify.zip"; - System.DateTime Threshold = new System.DateTime(2007,12,31); - using (ZipFile zip = ZipFile.Read(ZipFileToRead)) - { - var EntriesToRemove = new System.Collections.Generic.List<ZipEntry>(); - foreach (ZipEntry e in zip) - { - if (e.LastModified < Threshold) - { - // We cannot remove the entry from the list, within the context of - // an enumeration of said list. - // So we add the doomed entry to a list to be removed later. - EntriesToRemove.Add(e); - } - } - - // actually remove the doomed entries. - foreach (ZipEntry zombie in EntriesToRemove) - zip.RemoveEntry(zombie); - - zip.Comment= String.Format("This zip archive was updated at {0}.", - System.DateTime.Now.ToString("G")); - - // save with a different name - zip.Save("Archive-Updated.zip"); - } - - - - Dim ZipFileToRead As String = "ArchiveToModify.zip" - Dim Threshold As New DateTime(2007, 12, 31) - Using zip As ZipFile = ZipFile.Read(ZipFileToRead) - Dim EntriesToRemove As New System.Collections.Generic.List(Of ZipEntry) - Dim e As ZipEntry - For Each e In zip - If (e.LastModified < Threshold) Then - ' We cannot remove the entry from the list, within the context of - ' an enumeration of said list. - ' So we add the doomed entry to a list to be removed later. - EntriesToRemove.Add(e) - End If - Next - - ' actually remove the doomed entries. - Dim zombie As ZipEntry - For Each zombie In EntriesToRemove - zip.RemoveEntry(zombie) - Next - zip.Comment = String.Format("This zip archive was updated at {0}.", DateTime.Now.ToString("G")) - 'save as a different name - zip.Save("Archive-Updated.zip") - End Using - - - - - The ZipEntry to remove from the zip. - - - - - - - - Removes the ZipEntry with the given filename from the zip archive. - - - - - After calling RemoveEntry, the application must call Save to - make the changes permanent. - - - - - - Thrown if the ZipFile is not updatable. - - - - Thrown if a ZipEntry with the specified filename does not exist in - the ZipFile. - - - - - This example shows one way to remove an entry with a given filename from - an existing zip archive. - - - String zipFileToRead= "PackedDocuments.zip"; - string candidate = "DatedMaterial.xps"; - using (ZipFile zip = ZipFile.Read(zipFileToRead)) - { - if (zip.EntryFilenames.Contains(candidate)) - { - zip.RemoveEntry(candidate); - zip.Comment= String.Format("The file '{0}' has been removed from this archive.", - Candidate); - zip.Save(); - } - } - - - Dim zipFileToRead As String = "PackedDocuments.zip" - Dim candidate As String = "DatedMaterial.xps" - Using zip As ZipFile = ZipFile.Read(zipFileToRead) - If zip.EntryFilenames.Contains(candidate) Then - zip.RemoveEntry(candidate) - zip.Comment = String.Format("The file '{0}' has been removed from this archive.", Candidate) - zip.Save - End If - End Using - - - - - The name of the file, including any directory path, to remove from the zip. - The filename match is not case-sensitive by default; you can use the - CaseSensitiveRetrieval property to change this behavior. The - pathname can use forward-slashes or backward slashes. - - - - - - Closes the read and write streams associated - to the ZipFile, if necessary. - - - - The Dispose() method is generally employed implicitly, via a using(..) {..} - statement. (Using...End Using in VB) If you do not employ a using - statement, insure that your application calls Dispose() explicitly. For - example, in a Powershell application, or an application that uses the COM - interop interface, you must call Dispose() explicitly. - - - - This example extracts an entry selected by name, from the Zip file to the - Console. - - using (ZipFile zip = ZipFile.Read(zipfile)) - { - foreach (ZipEntry e in zip) - { - if (WantThisEntry(e.FileName)) - zip.Extract(e.FileName, Console.OpenStandardOutput()); - } - } // Dispose() is called implicitly here. - - - - Using zip As ZipFile = ZipFile.Read(zipfile) - Dim e As ZipEntry - For Each e In zip - If WantThisEntry(e.FileName) Then - zip.Extract(e.FileName, Console.OpenStandardOutput()) - End If - Next - End Using ' Dispose is implicity called here - - - - - - Disposes any managed resources, if the flag is set, then marks the - instance disposed. This method is typically not called explicitly from - application code. - - - - Applications should call the no-arg Dispose method. - - - - indicates whether the method should dispose streams or not. - - - - - Default size of the buffer used for IO. - - - - - An event handler invoked when a Save() starts, before and after each - entry has been written to the archive, when a Save() completes, and - during other Save events. - - - - - Depending on the particular event, different properties on the parameter are set. The following - table summarizes the available EventTypes and the conditions under - which this event handler is invoked with a - SaveProgressEventArgs with the given EventType. - - - - - value of EntryType - Meaning and conditions - - - - ZipProgressEventType.Saving_Started - Fired when ZipFile.Save() begins. - - - - - ZipProgressEventType.Saving_BeforeSaveEntry - - Fired within ZipFile.Save(), just before writing data for each - particular entry. - - - - - ZipProgressEventType.Saving_AfterSaveEntry - - Fired within ZipFile.Save(), just after having finished writing data - for each particular entry. - - - - - ZipProgressEventType.Saving_Completed - Fired when ZipFile.Save() has completed. - - - - - ZipProgressEventType.Saving_AfterSaveTempArchive - - Fired after the temporary file has been created. This happens only - when saving to a disk file. This event will not be invoked when - saving to a stream. - - - - - ZipProgressEventType.Saving_BeforeRenameTempArchive - - Fired just before renaming the temporary file to the permanent - location. This happens only when saving to a disk file. This event - will not be invoked when saving to a stream. - - - - - ZipProgressEventType.Saving_AfterRenameTempArchive - - Fired just after renaming the temporary file to the permanent - location. This happens only when saving to a disk file. This event - will not be invoked when saving to a stream. - - - - - ZipProgressEventType.Saving_AfterCompileSelfExtractor - - Fired after a self-extracting archive has finished compiling. This - EventType is used only within SaveSelfExtractor(). - - - - - ZipProgressEventType.Saving_BytesRead - - Set during the save of a particular entry, to update progress of the - Save(). When this EventType is set, the BytesTransferred is the - number of bytes that have been read from the source stream. The - TotalBytesToTransfer is the number of bytes in the uncompressed - file. - - - - - - - - - This example uses an anonymous method to handle the - SaveProgress event, by updating a progress bar. - - - progressBar1.Value = 0; - progressBar1.Max = listbox1.Items.Count; - using (ZipFile zip = new ZipFile()) - { - // listbox1 contains a list of filenames - zip.AddFiles(listbox1.Items); - - // do the progress bar: - zip.SaveProgress += (sender, e) => { - if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) { - progressBar1.PerformStep(); - } - }; - - zip.Save(fs); - } - - - - - This example uses a named method as the - SaveProgress event handler, to update the user, in a - console-based application. - - - static bool justHadByteUpdate= false; - public static void SaveProgress(object sender, SaveProgressEventArgs e) - { - if (e.EventType == ZipProgressEventType.Saving_Started) - Console.WriteLine("Saving: {0}", e.ArchiveName); - - else if (e.EventType == ZipProgressEventType.Saving_Completed) - { - justHadByteUpdate= false; - Console.WriteLine(); - Console.WriteLine("Done: {0}", e.ArchiveName); - } - - else if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) - { - if (justHadByteUpdate) - Console.WriteLine(); - Console.WriteLine(" Writing: {0} ({1}/{2})", - e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal); - justHadByteUpdate= false; - } - - else if (e.EventType == ZipProgressEventType.Saving_EntryBytesRead) - { - if (justHadByteUpdate) - Console.SetCursorPosition(0, Console.CursorTop); - Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, - e.BytesTransferred / (0.01 * e.TotalBytesToTransfer )); - justHadByteUpdate= true; - } - } - - public static ZipUp(string targetZip, string directory) - { - using (var zip = new ZipFile()) { - zip.SaveProgress += SaveProgress; - zip.AddDirectory(directory); - zip.Save(targetZip); - } - } - - - - - Public Sub ZipUp(ByVal targetZip As String, ByVal directory As String) - Using zip As ZipFile = New ZipFile - AddHandler zip.SaveProgress, AddressOf MySaveProgress - zip.AddDirectory(directory) - zip.Save(targetZip) - End Using - End Sub - - Private Shared justHadByteUpdate As Boolean = False - - Public Shared Sub MySaveProgress(ByVal sender As Object, ByVal e As SaveProgressEventArgs) - If (e.EventType Is ZipProgressEventType.Saving_Started) Then - Console.WriteLine("Saving: {0}", e.ArchiveName) - - ElseIf (e.EventType Is ZipProgressEventType.Saving_Completed) Then - justHadByteUpdate = False - Console.WriteLine - Console.WriteLine("Done: {0}", e.ArchiveName) - - ElseIf (e.EventType Is ZipProgressEventType.Saving_BeforeWriteEntry) Then - If justHadByteUpdate Then - Console.WriteLine - End If - Console.WriteLine(" Writing: {0} ({1}/{2})", e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal) - justHadByteUpdate = False - - ElseIf (e.EventType Is ZipProgressEventType.Saving_EntryBytesRead) Then - If justHadByteUpdate Then - Console.SetCursorPosition(0, Console.CursorTop) - End If - Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, _ - e.TotalBytesToTransfer, _ - (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))) - justHadByteUpdate = True - End If - End Sub - - - - - - This is a more complete example of using the SaveProgress - events in a Windows Forms application, with a - Thread object. - - - delegate void SaveEntryProgress(SaveProgressEventArgs e); - delegate void ButtonClick(object sender, EventArgs e); - - public class WorkerOptions - { - public string ZipName; - public string Folder; - public string Encoding; - public string Comment; - public int ZipFlavor; - public Zip64Option Zip64; - } - - private int _progress2MaxFactor; - private bool _saveCanceled; - private long _totalBytesBeforeCompress; - private long _totalBytesAfterCompress; - private Thread _workerThread; - - - private void btnZipup_Click(object sender, EventArgs e) - { - KickoffZipup(); - } - - private void btnCancel_Click(object sender, EventArgs e) - { - if (this.lblStatus.InvokeRequired) - { - this.lblStatus.Invoke(new ButtonClick(this.btnCancel_Click), new object[] { sender, e }); - } - else - { - _saveCanceled = true; - lblStatus.Text = "Canceled..."; - ResetState(); - } - } - - private void KickoffZipup() - { - _folderName = tbDirName.Text; - - if (_folderName == null || _folderName == "") return; - if (this.tbZipName.Text == null || this.tbZipName.Text == "") return; - - // check for existence of the zip file: - if (System.IO.File.Exists(this.tbZipName.Text)) - { - var dlgResult = MessageBox.Show(String.Format("The file you have specified ({0}) already exists." + - " Do you want to overwrite this file?", this.tbZipName.Text), - "Confirmation is Required", MessageBoxButtons.YesNo, MessageBoxIcon.Question); - if (dlgResult != DialogResult.Yes) return; - System.IO.File.Delete(this.tbZipName.Text); - } - - _saveCanceled = false; - _nFilesCompleted = 0; - _totalBytesAfterCompress = 0; - _totalBytesBeforeCompress = 0; - this.btnOk.Enabled = false; - this.btnOk.Text = "Zipping..."; - this.btnCancel.Enabled = true; - lblStatus.Text = "Zipping..."; - - var options = new WorkerOptions - { - ZipName = this.tbZipName.Text, - Folder = _folderName, - Encoding = "ibm437" - }; - - if (this.comboBox1.SelectedIndex != 0) - { - options.Encoding = this.comboBox1.SelectedItem.ToString(); - } - - if (this.radioFlavorSfxCmd.Checked) - options.ZipFlavor = 2; - else if (this.radioFlavorSfxGui.Checked) - options.ZipFlavor = 1; - else options.ZipFlavor = 0; - - if (this.radioZip64AsNecessary.Checked) - options.Zip64 = Zip64Option.AsNecessary; - else if (this.radioZip64Always.Checked) - options.Zip64 = Zip64Option.Always; - else options.Zip64 = Zip64Option.Never; - - options.Comment = String.Format("Encoding:{0} || Flavor:{1} || ZIP64:{2}\r\nCreated at {3} || {4}\r\n", - options.Encoding, - FlavorToString(options.ZipFlavor), - options.Zip64.ToString(), - System.DateTime.Now.ToString("yyyy-MMM-dd HH:mm:ss"), - this.Text); - - if (this.tbComment.Text != TB_COMMENT_NOTE) - options.Comment += this.tbComment.Text; - - _workerThread = new Thread(this.DoSave); - _workerThread.Name = "Zip Saver thread"; - _workerThread.Start(options); - this.Cursor = Cursors.WaitCursor; - } - - - private void DoSave(Object p) - { - WorkerOptions options = p as WorkerOptions; - try - { - using (var zip1 = new ZipFile()) - { - zip1.ProvisionalAlternateEncoding = System.Text.Encoding.GetEncoding(options.Encoding); - zip1.Comment = options.Comment; - zip1.AddDirectory(options.Folder); - _entriesToZip = zip1.EntryFileNames.Count; - SetProgressBars(); - zip1.SaveProgress += this.zip1_SaveProgress; - - zip1.UseZip64WhenSaving = options.Zip64; - - if (options.ZipFlavor == 1) - zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.WinFormsApplication); - else if (options.ZipFlavor == 2) - zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.ConsoleApplication); - else - zip1.Save(options.ZipName); - } - } - catch (System.Exception exc1) - { - MessageBox.Show(String.Format("Exception while zipping: {0}", exc1.Message)); - btnCancel_Click(null, null); - } - } - - - - void zip1_SaveProgress(object sender, SaveProgressEventArgs e) - { - switch (e.EventType) - { - case ZipProgressEventType.Saving_AfterWriteEntry: - StepArchiveProgress(e); - break; - case ZipProgressEventType.Saving_EntryBytesRead: - StepEntryProgress(e); - break; - case ZipProgressEventType.Saving_Completed: - SaveCompleted(); - break; - case ZipProgressEventType.Saving_AfterSaveTempArchive: - // this event only occurs when saving an SFX file - TempArchiveSaved(); - break; - } - if (_saveCanceled) - e.Cancel = true; - } - - - - private void StepArchiveProgress(SaveProgressEventArgs e) - { - if (this.progressBar1.InvokeRequired) - { - this.progressBar1.Invoke(new SaveEntryProgress(this.StepArchiveProgress), new object[] { e }); - } - else - { - if (!_saveCanceled) - { - _nFilesCompleted++; - this.progressBar1.PerformStep(); - _totalBytesAfterCompress += e.CurrentEntry.CompressedSize; - _totalBytesBeforeCompress += e.CurrentEntry.UncompressedSize; - - // reset the progress bar for the entry: - this.progressBar2.Value = this.progressBar2.Maximum = 1; - - this.Update(); - } - } - } - - - private void StepEntryProgress(SaveProgressEventArgs e) - { - if (this.progressBar2.InvokeRequired) - { - this.progressBar2.Invoke(new SaveEntryProgress(this.StepEntryProgress), new object[] { e }); - } - else - { - if (!_saveCanceled) - { - if (this.progressBar2.Maximum == 1) - { - // reset - Int64 max = e.TotalBytesToTransfer; - _progress2MaxFactor = 0; - while (max > System.Int32.MaxValue) - { - max /= 2; - _progress2MaxFactor++; - } - this.progressBar2.Maximum = (int)max; - lblStatus.Text = String.Format("{0} of {1} files...({2})", - _nFilesCompleted + 1, _entriesToZip, e.CurrentEntry.FileName); - } - - int xferred = e.BytesTransferred >> _progress2MaxFactor; - - this.progressBar2.Value = (xferred >= this.progressBar2.Maximum) - ? this.progressBar2.Maximum - : xferred; - - this.Update(); - } - } - } - - private void SaveCompleted() - { - if (this.lblStatus.InvokeRequired) - { - this.lblStatus.Invoke(new MethodInvoker(this.SaveCompleted)); - } - else - { - lblStatus.Text = String.Format("Done, Compressed {0} files, {1:N0}% of original.", - _nFilesCompleted, (100.00 * _totalBytesAfterCompress) / _totalBytesBeforeCompress); - ResetState(); - } - } - - private void ResetState() - { - this.btnCancel.Enabled = false; - this.btnOk.Enabled = true; - this.btnOk.Text = "Zip it!"; - this.progressBar1.Value = 0; - this.progressBar2.Value = 0; - this.Cursor = Cursors.Default; - if (!_workerThread.IsAlive) - _workerThread.Join(); - } - - - - - - - - - - - An event handler invoked before, during, and after the reading of a zip archive. - - - - - Depending on the particular event being signaled, different properties on the - parameter are set. The following table - summarizes the available EventTypes and the conditions under which this - event handler is invoked with a ReadProgressEventArgs with the given EventType. - - - - - value of EntryType - Meaning and conditions - - - - ZipProgressEventType.Reading_Started - Fired just as ZipFile.Read() begins. Meaningful properties: ArchiveName. - - - - - ZipProgressEventType.Reading_Completed - Fired when ZipFile.Read() has completed. Meaningful properties: ArchiveName. - - - - - ZipProgressEventType.Reading_ArchiveBytesRead - Fired while reading, updates the number of bytes read for the entire archive. - Meaningful properties: ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer. - - - - - ZipProgressEventType.Reading_BeforeReadEntry - Indicates an entry is about to be read from the archive. - Meaningful properties: ArchiveName, EntriesTotal. - - - - - ZipProgressEventType.Reading_AfterReadEntry - Indicates an entry has just been read from the archive. - Meaningful properties: ArchiveName, EntriesTotal, CurrentEntry. - - - - - - - - - - - - - An event handler invoked before, during, and after extraction of - entries in the zip archive. - - - - - Depending on the particular event, different properties on the parameter are set. The following - table summarizes the available EventTypes and the conditions under - which this event handler is invoked with a - ExtractProgressEventArgs with the given EventType. - - - - - value of EntryType - Meaning and conditions - - - - ZipProgressEventType.Extracting_BeforeExtractAll - - Set when ExtractAll() begins. The ArchiveName, Overwrite, and - ExtractLocation properties are meaningful. - - - - ZipProgressEventType.Extracting_AfterExtractAll - - Set when ExtractAll() has completed. The ArchiveName, Overwrite, - and ExtractLocation properties are meaningful. - - - - - ZipProgressEventType.Extracting_BeforeExtractEntry - - Set when an Extract() on an entry in the ZipFile has begun. - Properties that are meaningful: ArchiveName, EntriesTotal, - CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted. - - - - - ZipProgressEventType.Extracting_AfterExtractEntry - - Set when an Extract() on an entry in the ZipFile has completed. - Properties that are meaningful: ArchiveName, EntriesTotal, - CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted. - - - - - ZipProgressEventType.Extracting_EntryBytesWritten - - Set within a call to Extract() on an entry in the ZipFile, as data - is extracted for the entry. Properties that are meaningful: - ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer. - - - - - ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite - - Set within a call to Extract() on an entry in the ZipFile, when the - extraction would overwrite an existing file. This event type is used - only when ExtractExistingFileAction on the ZipFile or - ZipEntry is set to InvokeExtractProgressEvent. - - - - - - - - - - private static bool justHadByteUpdate = false; - public static void ExtractProgress(object sender, ExtractProgressEventArgs e) - { - if(e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten) - { - if (justHadByteUpdate) - Console.SetCursorPosition(0, Console.CursorTop); - - Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, - e.BytesTransferred / (0.01 * e.TotalBytesToTransfer )); - justHadByteUpdate = true; - } - else if(e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry) - { - if (justHadByteUpdate) - Console.WriteLine(); - Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName); - justHadByteUpdate= false; - } - } - - public static ExtractZip(string zipToExtract, string directory) - { - string TargetDirectory= "extract"; - using (var zip = ZipFile.Read(zipToExtract)) { - zip.ExtractProgress += ExtractProgress; - foreach (var e in zip1) - { - e.Extract(TargetDirectory, true); - } - } - } - - - - Public Shared Sub Main(ByVal args As String()) - Dim ZipToUnpack As String = "C1P3SML.zip" - Dim TargetDir As String = "ExtractTest_Extract" - Console.WriteLine("Extracting file {0} to {1}", ZipToUnpack, TargetDir) - Using zip1 As ZipFile = ZipFile.Read(ZipToUnpack) - AddHandler zip1.ExtractProgress, AddressOf MyExtractProgress - Dim e As ZipEntry - For Each e In zip1 - e.Extract(TargetDir, True) - Next - End Using - End Sub - - Private Shared justHadByteUpdate As Boolean = False - - Public Shared Sub MyExtractProgress(ByVal sender As Object, ByVal e As ExtractProgressEventArgs) - If (e.EventType = ZipProgressEventType.Extracting_EntryBytesWritten) Then - If ExtractTest.justHadByteUpdate Then - Console.SetCursorPosition(0, Console.CursorTop) - End If - Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))) - ExtractTest.justHadByteUpdate = True - ElseIf (e.EventType = ZipProgressEventType.Extracting_BeforeExtractEntry) Then - If ExtractTest.justHadByteUpdate Then - Console.WriteLine - End If - Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName) - ExtractTest.justHadByteUpdate = False - End If - End Sub - - - - - - - - - - An event handler invoked before, during, and after Adding entries to a zip archive. - - - - Adding a large number of entries to a zip file can take a long - time. For example, when calling on a - directory that contains 50,000 files, it could take 3 minutes or so. - This event handler allws an application to track the progress of the Add - operation, and to optionally cancel a lengthy Add operation. - - - - - - int _numEntriesToAdd= 0; - int _numEntriesAdded= 0; - void AddProgressHandler(object sender, AddProgressEventArgs e) - { - switch (e.EventType) - { - case ZipProgressEventType.Adding_Started: - Console.WriteLine("Adding files to the zip..."); - break; - case ZipProgressEventType.Adding_AfterAddEntry: - _numEntriesAdded++; - Console.WriteLine(String.Format("Adding file {0}/{1} :: {2}", - _numEntriesAdded, _numEntriesToAdd, e.CurrentEntry.FileName)); - break; - case ZipProgressEventType.Adding_Completed: - Console.WriteLine("Added all files"); - break; - } - } - - void CreateTheZip() - { - using (ZipFile zip = new ZipFile()) - { - zip.AddProgress += AddProgressHandler; - zip.AddDirectory(System.IO.Path.GetFileName(DirToZip)); - zip.Save(ZipFileToCreate); - } - } - - - - - - Private Sub AddProgressHandler(ByVal sender As Object, ByVal e As AddProgressEventArgs) - Select Case e.EventType - Case ZipProgressEventType.Adding_Started - Console.WriteLine("Adding files to the zip...") - Exit Select - Case ZipProgressEventType.Adding_AfterAddEntry - Console.WriteLine(String.Format("Adding file {0}", e.CurrentEntry.FileName)) - Exit Select - Case ZipProgressEventType.Adding_Completed - Console.WriteLine("Added all files") - Exit Select - End Select - End Sub - - Sub CreateTheZip() - Using zip as ZipFile = New ZipFile - AddHandler zip.AddProgress, AddressOf AddProgressHandler - zip.AddDirectory(System.IO.Path.GetFileName(DirToZip)) - zip.Save(ZipFileToCreate); - End Using - End Sub - - - - - - - - - - - - An event that is raised when an error occurs during open or read of files - while saving a zip archive. - - - - - Errors can occur as a file is being saved to the zip archive. For - example, the File.Open may fail, or a File.Read may fail, because of - lock conflicts or other reasons. If you add a handler to this event, - you can handle such errors in your own code. If you don't add a - handler, the library will throw an exception if it encounters an I/O - error during a call to Save(). - - - - Setting a handler implicitly sets to - ZipErrorAction.InvokeErrorEvent. - - - - The handler you add applies to all items that are - subsequently added to the ZipFile instance. If you set this - property after you have added items to the ZipFile, but before you - have called Save(), errors that occur while saving those items - will not cause the error handler to be invoked. - - - - If you want to handle any errors that occur with any entry in the zip - file using the same error handler, then add your error handler once, - before adding any entries to the zip archive. - - - - In the error handler method, you need to set the property on the - ZipErrorEventArgs.CurrentEntry. This communicates back to - DotNetZip what you would like to do with this particular error. Within - an error handler, if you set the ZipEntry.ZipErrorAction property - on the ZipEntry to ZipErrorAction.InvokeErrorEvent or if - you don't set it at all, the library will throw the exception. (It is the - same as if you had set the ZipEntry.ZipErrorAction property on the - ZipEntry to ZipErrorAction.Throw.) If you set the - ZipErrorEventArgs.Cancel to true, the entire Save() will be - canceled. - - - - In the case that you use ZipErrorAction.Skip, implying that - you want to skip the entry for which there's been an error, DotNetZip - tries to seek backwards in the output stream, and truncate all bytes - written on behalf of that particular entry. This works only if the - output stream is seekable. It will not work, for example, when using - ASPNET's Response.OutputStream. - - - - - - - This example shows how to use an event handler to handle - errors during save of the zip file. - - - public static void MyZipError(object sender, ZipErrorEventArgs e) - { - Console.WriteLine("Error saving {0}...", e.FileName); - Console.WriteLine(" Exception: {0}", e.exception); - ZipEntry entry = e.CurrentEntry; - string response = null; - // Ask the user whether he wants to skip this error or not - do - { - Console.Write("Retry, Skip, Throw, or Cancel ? (R/S/T/C) "); - response = Console.ReadLine(); - Console.WriteLine(); - - } while (response != null && - response[0]!='S' && response[0]!='s' && - response[0]!='R' && response[0]!='r' && - response[0]!='T' && response[0]!='t' && - response[0]!='C' && response[0]!='c'); - - e.Cancel = (response[0]=='C' || response[0]=='c'); - - if (response[0]=='S' || response[0]=='s') - entry.ZipErrorAction = ZipErrorAction.Skip; - else if (response[0]=='R' || response[0]=='r') - entry.ZipErrorAction = ZipErrorAction.Retry; - else if (response[0]=='T' || response[0]=='t') - entry.ZipErrorAction = ZipErrorAction.Throw; - } - - public void SaveTheFile() - { - string directoryToZip = "fodder"; - string directoryInArchive = "files"; - string zipFileToCreate = "Archive.zip"; - using (var zip = new ZipFile()) - { - // set the event handler before adding any entries - zip.ZipError += MyZipError; - zip.AddDirectory(directoryToZip, directoryInArchive); - zip.Save(zipFileToCreate); - } - } - - - - Private Sub MyZipError(ByVal sender As Object, ByVal e As Ionic.Zip.ZipErrorEventArgs) - ' At this point, the application could prompt the user for an action to take. - ' But in this case, this application will simply automatically skip the file, in case of error. - Console.WriteLine("Zip Error, entry {0}", e.CurrentEntry.FileName) - Console.WriteLine(" Exception: {0}", e.exception) - ' set the desired ZipErrorAction on the CurrentEntry to communicate that to DotNetZip - e.CurrentEntry.ZipErrorAction = Zip.ZipErrorAction.Skip - End Sub - - Public Sub SaveTheFile() - Dim directoryToZip As String = "fodder" - Dim directoryInArchive As String = "files" - Dim zipFileToCreate as String = "Archive.zip" - Using zipArchive As ZipFile = New ZipFile - ' set the event handler before adding any entries - AddHandler zipArchive.ZipError, AddressOf MyZipError - zipArchive.AddDirectory(directoryToZip, directoryInArchive) - zipArchive.Save(zipFileToCreate) - End Using - End Sub - - - - - - - - - Extracts all of the items in the zip archive, to the specified path in the - filesystem. The path can be relative or fully-qualified. - - - - - This method will extract all entries in the ZipFile to the - specified path. - - - - If an extraction of a file from the zip archive would overwrite an - existing file in the filesystem, the action taken is dictated by the - ExtractExistingFile property, which overrides any setting you may have - made on individual ZipEntry instances. By default, if you have not - set that property on the ZipFile instance, the entry will not - be extracted, the existing file will not be overwritten and an - exception will be thrown. To change this, set the property, or use the - overload that allows you to - specify an ExtractExistingFileAction parameter. - - - - The action to take when an extract would overwrite an existing file - applies to all entries. If you want to set this on a per-entry basis, - then you must use one of the ZipEntry.Extract methods. - - - - This method will send verbose output messages to the , if it is set on the ZipFile - instance. - - - - You may wish to take advantage of the ExtractProgress event. - - - - About timestamps: When extracting a file entry from a zip archive, the - extracted file gets the last modified time of the entry as stored in - the archive. The archive may also store extended file timestamp - information, including last accessed and created times. If these are - present in the ZipEntry, then the extracted file will also get - these times. - - - - A Directory entry is somewhat different. It will get the times as - described for a file entry, but, if there are file entries in the zip - archive that, when extracted, appear in the just-created directory, - then when those file entries are extracted, the last modified and last - accessed times of the directory will change, as a side effect. The - result is that after an extraction of a directory and a number of - files within the directory, the last modified and last accessed - timestamps on the directory will reflect the time that the last file - was extracted into the directory, rather than the time stored in the - zip archive for the directory. - - - - To compensate, when extracting an archive with ExtractAll, - DotNetZip will extract all the file and directory entries as described - above, but it will then make a second pass on the directories, and - reset the times on the directories to reflect what is stored in the - zip archive. - - - - This compensation is performed only within the context of an - ExtractAll. If you call ZipEntry.Extract on a directory - entry, the timestamps on directory in the filesystem will reflect the - times stored in the zip. If you then call ZipEntry.Extract on - a file entry, which is extracted into the directory, the timestamps on - the directory will be updated to the current time. - - - - - This example extracts all the entries in a zip archive file, to the - specified target directory. The extraction will overwrite any - existing files silently. - - - String TargetDirectory= "unpack"; - using(ZipFile zip= ZipFile.Read(ZipFileToExtract)) - { - zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently; - zip.ExtractAll(TargetDirectory); - } - - - - Dim TargetDirectory As String = "unpack" - Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) - zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently - zip.ExtractAll(TargetDirectory) - End Using - - - - - - - - The path to which the contents of the zipfile will be extracted. - The path can be relative or fully-qualified. - - - - - - Extracts all of the items in the zip archive, to the specified path in the - filesystem, using the specified behavior when extraction would overwrite an - existing file. - - - - - - This method will extract all entries in the ZipFile to the specified - path. For an extraction that would overwrite an existing file, the behavior - is dictated by , which overrides any - setting you may have made on individual ZipEntry instances. - - - - The action to take when an extract would overwrite an existing file - applies to all entries. If you want to set this on a per-entry basis, - then you must use or one of the similar methods. - - - - Calling this method is equivalent to setting the property and then calling . - - - - This method will send verbose output messages to the - , if it is set on the ZipFile instance. - - - - - This example extracts all the entries in a zip archive file, to the - specified target directory. It does not overwrite any existing files. - - String TargetDirectory= "c:\\unpack"; - using(ZipFile zip= ZipFile.Read(ZipFileToExtract)) - { - zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite); - } - - - - Dim TargetDirectory As String = "c:\unpack" - Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) - zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite) - End Using - - - - - The path to which the contents of the zipfile will be extracted. - The path can be relative or fully-qualified. - - - - The action to take if extraction would overwrite an existing file. - - - - - - Reads a zip file archive and returns the instance. - - - - - The stream is read using the default System.Text.Encoding, which is the - IBM437 codepage. - - - - - Thrown if the ZipFile cannot be read. The implementation of this method - relies on System.IO.File.OpenRead, which can throw a variety of exceptions, - including specific exceptions if a file is not found, an unauthorized access - exception, exceptions for poorly formatted filenames, and so on. - - - - The name of the zip archive to open. This can be a fully-qualified or relative - pathname. - - - . - - The instance read from the zip archive. - - - - - Reads a zip file archive from the named filesystem file using the - specified options. - - - - - This version of the Read() method allows the caller to pass - in a TextWriter an Encoding, via an instance of the - ReadOptions class. The ZipFile is read in using the - specified encoding for entries where UTF-8 encoding is not - explicitly specified. - - - - - - - This example shows how to read a zip file using the Big-5 Chinese - code page (950), and extract each entry in the zip file, while - sending status messages out to the Console. - - - - For this code to work as intended, the zipfile must have been - created using the big5 code page (CP950). This is typical, for - example, when using WinRar on a machine with CP950 set as the - default code page. In that case, the names of entries within the - Zip archive will be stored in that code page, and reading the zip - archive must be done using that code page. If the application did - not use the correct code page in ZipFile.Read(), then names of - entries within the zip archive would not be correctly retrieved. - - - - string zipToExtract = "MyArchive.zip"; - string extractDirectory = "extract"; - var options = new ReadOptions - { - StatusMessageWriter = System.Console.Out, - Encoding = System.Text.Encoding.GetEncoding(950) - }; - using (ZipFile zip = ZipFile.Read(zipToExtract, options)) - { - foreach (ZipEntry e in zip) - { - e.Extract(extractDirectory); - } - } - - - - - Dim zipToExtract as String = "MyArchive.zip" - Dim extractDirectory as String = "extract" - Dim options as New ReadOptions - options.Encoding = System.Text.Encoding.GetEncoding(950) - options.StatusMessageWriter = System.Console.Out - Using zip As ZipFile = ZipFile.Read(zipToExtract, options) - Dim e As ZipEntry - For Each e In zip - e.Extract(extractDirectory) - Next - End Using - - - - - - - - This example shows how to read a zip file using the default - code page, to remove entries that have a modified date before a given threshold, - sending status messages out to a StringWriter. - - - - var options = new ReadOptions - { - StatusMessageWriter = new System.IO.StringWriter() - }; - using (ZipFile zip = ZipFile.Read("PackedDocuments.zip", options)) - { - var Threshold = new DateTime(2007,7,4); - // We cannot remove the entry from the list, within the context of - // an enumeration of said list. - // So we add the doomed entry to a list to be removed later. - // pass 1: mark the entries for removal - var MarkedEntries = new System.Collections.Generic.List<ZipEntry>(); - foreach (ZipEntry e in zip) - { - if (e.LastModified < Threshold) - MarkedEntries.Add(e); - } - // pass 2: actually remove the entry. - foreach (ZipEntry zombie in MarkedEntries) - zip.RemoveEntry(zombie); - zip.Comment = "This archive has been updated."; - zip.Save(); - } - // can now use contents of sw, eg store in an audit log - - - - Dim options as New ReadOptions - options.StatusMessageWriter = New System.IO.StringWriter - Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip", options) - Dim Threshold As New DateTime(2007, 7, 4) - ' We cannot remove the entry from the list, within the context of - ' an enumeration of said list. - ' So we add the doomed entry to a list to be removed later. - ' pass 1: mark the entries for removal - Dim MarkedEntries As New System.Collections.Generic.List(Of ZipEntry) - Dim e As ZipEntry - For Each e In zip - If (e.LastModified < Threshold) Then - MarkedEntries.Add(e) - End If - Next - ' pass 2: actually remove the entry. - Dim zombie As ZipEntry - For Each zombie In MarkedEntries - zip.RemoveEntry(zombie) - Next - zip.Comment = "This archive has been updated." - zip.Save - End Using - ' can now use contents of sw, eg store in an audit log - - - - - Thrown if the zipfile cannot be read. The implementation of - this method relies on System.IO.File.OpenRead, which - can throw a variety of exceptions, including specific - exceptions if a file is not found, an unauthorized access - exception, exceptions for poorly formatted filenames, and so - on. - - - - The name of the zip archive to open. - This can be a fully-qualified or relative pathname. - - - - The set of options to use when reading the zip file. - - - The ZipFile instance read from the zip archive. - - - - - - - Reads a zip file archive using the specified text encoding, the specified - TextWriter for status messages, and the specified ReadProgress event handler, - and returns the instance. - - - - The name of the zip archive to open. - This can be a fully-qualified or relative pathname. - - - - An event handler for Read operations. - - - - The System.IO.TextWriter to use for writing verbose status messages - during operations on the zip archive. A console application may wish to - pass System.Console.Out to get messages on the Console. A graphical - or headless application may wish to capture the messages in a different - TextWriter, such as a System.IO.StringWriter. - - - - The System.Text.Encoding to use when reading in the zip archive. Be - careful specifying the encoding. If the value you use here is not the same - as the Encoding used when the zip archive was created (possibly by a - different archiver) you will get unexpected results and possibly exceptions. - - - The instance read from the zip archive. - - - - - Reads a zip archive from a stream. - - - - - - When reading from a file, it's probably easier to just use - ZipFile.Read(String, ReadOptions). This - overload is useful when when the zip archive content is - available from an already-open stream. The stream must be - open and readable and seekable when calling this method. The - stream is left open when the reading is completed. - - - - Using this overload, the stream is read using the default - System.Text.Encoding, which is the IBM437 - codepage. If you want to specify the encoding to use when - reading the zipfile content, see - ZipFile.Read(Stream, ReadOptions). This - - - - Reading of zip content begins at the current position in the - stream. This means if you have a stream that concatenates - regular data and zip data, if you position the open, readable - stream at the start of the zip data, you will be able to read - the zip archive using this constructor, or any of the ZipFile - constructors that accept a as - input. Some examples of where this might be useful: the zip - content is concatenated at the end of a regular EXE file, as - some self-extracting archives do. (Note: SFX files produced - by DotNetZip do not work this way; they can be read as normal - ZIP files). Another example might be a stream being read from - a database, where the zip content is embedded within an - aggregate stream of data. - - - - - - - This example shows how to Read zip content from a stream, and - extract one entry into a different stream. In this example, - the filename "NameOfEntryInArchive.doc", refers only to the - name of the entry within the zip archive. A file by that - name is not created in the filesystem. The I/O is done - strictly with the given streams. - - - - using (ZipFile zip = ZipFile.Read(InputStream)) - { - zip.Extract("NameOfEntryInArchive.doc", OutputStream); - } - - - - Using zip as ZipFile = ZipFile.Read(InputStream) - zip.Extract("NameOfEntryInArchive.doc", OutputStream) - End Using - - - - the stream containing the zip data. - - The ZipFile instance read from the stream - - - - - Reads a zip file archive from the given stream using the - specified options. - - - - - - When reading from a file, it's probably easier to just use - ZipFile.Read(String, ReadOptions). This - overload is useful when when the zip archive content is - available from an already-open stream. The stream must be - open and readable and seekable when calling this method. The - stream is left open when the reading is completed. - - - - Reading of zip content begins at the current position in the - stream. This means if you have a stream that concatenates - regular data and zip data, if you position the open, readable - stream at the start of the zip data, you will be able to read - the zip archive using this constructor, or any of the ZipFile - constructors that accept a as - input. Some examples of where this might be useful: the zip - content is concatenated at the end of a regular EXE file, as - some self-extracting archives do. (Note: SFX files produced - by DotNetZip do not work this way; they can be read as normal - ZIP files). Another example might be a stream being read from - a database, where the zip content is embedded within an - aggregate stream of data. - - - - the stream containing the zip data. - - - The set of options to use when reading the zip file. - - - - Thrown if the zip archive cannot be read. - - - The ZipFile instance read from the stream. - - - - - - - Reads a zip archive from a stream, using the specified text Encoding, the - specified TextWriter for status messages, - and the specified ReadProgress event handler. - - - - - Reading of zip content begins at the current position in the stream. This - means if you have a stream that concatenates regular data and zip data, if - you position the open, readable stream at the start of the zip data, you - will be able to read the zip archive using this constructor, or any of the - ZipFile constructors that accept a as - input. Some examples of where this might be useful: the zip content is - concatenated at the end of a regular EXE file, as some self-extracting - archives do. (Note: SFX files produced by DotNetZip do not work this - way). Another example might be a stream being read from a database, where - the zip content is embedded within an aggregate stream of data. - - - - the stream containing the zip data. - - - The System.IO.TextWriter to which verbose status messages are written - during operations on the ZipFile. For example, in a console - application, System.Console.Out works, and will get a message for each entry - added to the ZipFile. If the TextWriter is null, no verbose messages - are written. - - - - The text encoding to use when reading entries that do not have the UTF-8 - encoding bit set. Be careful specifying the encoding. If the value you use - here is not the same as the Encoding used when the zip archive was created - (possibly by a different archiver) you will get unexpected results and - possibly exceptions. See the - property for more information. - - - - An event handler for Read operations. - - - an instance of ZipFile - - - - Checks the given file to see if it appears to be a valid zip file. - - - - - Calling this method is equivalent to calling with the testExtract parameter set to false. - - - - The file to check. - true if the file appears to be a zip file. - - - - Checks a file to see if it is a valid zip file. - - - - - This method opens the specified zip file, reads in the zip archive, - verifying the ZIP metadata as it reads. - - - - If everything succeeds, then the method returns true. If anything fails - - for example if an incorrect signature or CRC is found, indicating a - corrupt file, the the method returns false. This method also returns - false for a file that does not exist. - - - - If is true, as part of its check, this - method reads in the content for each entry, expands it, and checks CRCs. - This provides an additional check beyond verifying the zip header and - directory data. - - - - If is true, and if any of the zip entries - are protected with a password, this method will return false. If you want - to verify a ZipFile that has entries which are protected with a - password, you will need to do that manually. - - - - - The zip file to check. - true if the caller wants to extract each entry. - true if the file contains a valid zip file. - - - - Checks a stream to see if it contains a valid zip archive. - - - - - This method reads the zip archive contained in the specified stream, verifying - the ZIP metadata as it reads. If testExtract is true, this method also extracts - each entry in the archive, dumping all the bits into . - - - - If everything succeeds, then the method returns true. If anything fails - - for example if an incorrect signature or CRC is found, indicating a corrupt - file, the the method returns false. This method also returns false for a - file that does not exist. - - - - If testExtract is true, this method reads in the content for each - entry, expands it, and checks CRCs. This provides an additional check - beyond verifying the zip header data. - - - - If testExtract is true, and if any of the zip entries are protected - with a password, this method will return false. If you want to verify a - ZipFile that has entries which are protected with a password, you will need - to do that manually. - - - - - - The stream to check. - true if the caller wants to extract each entry. - true if the stream contains a valid zip archive. - - - - Delete file with retry on UnauthorizedAccessException. - - - - - When calling File.Delete() on a file that has been "recently" - created, the call sometimes fails with - UnauthorizedAccessException. This method simply retries the Delete 3 - times with a sleep between tries. - - - - the name of the file to be deleted - - - - Saves the Zip archive to a file, specified by the Name property of the - ZipFile. - - - - - The ZipFile instance is written to storage, typically a zip file - in a filesystem, only when the caller calls Save. In the typical - case, the Save operation writes the zip content to a temporary file, and - then renames the temporary file to the desired name. If necessary, this - method will delete a pre-existing file before the rename. - - - - The property is specified either explicitly, - or implicitly using one of the parameterized ZipFile constructors. For - COM Automation clients, the Name property must be set explicitly, - because COM Automation clients cannot call parameterized constructors. - - - - When using a filesystem file for the Zip output, it is possible to call - Save multiple times on the ZipFile instance. With each - call the zip content is re-written to the same output file. - - - - Data for entries that have been added to the ZipFile instance is - written to the output when the Save method is called. This means - that the input streams for those entries must be available at the time - the application calls Save. If, for example, the application - adds entries with AddEntry using a dynamically-allocated - MemoryStream, the memory stream must not have been disposed - before the call to Save. See the property for more discussion of the - availability requirements of the input stream for an entry, and an - approach for providing just-in-time stream lifecycle management. - - - - - - - - Thrown if you haven't specified a location or stream for saving the zip, - either in the constructor or by setting the Name property, or if you try - to save a regular zip archive to a filename with a .exe extension. - - - - Thrown if or is non-zero, and the number - of segments that would be generated for the spanned zip file during the - save operation exceeds 99. If this happens, you need to increase the - segment size. - - - - - - Save the file to a new zipfile, with the given name. - - - - - This method allows the application to explicitly specify the name of the zip - file when saving. Use this when creating a new zip file, or when - updating a zip archive. - - - - An application can also save a zip archive in several places by calling this - method multiple times in succession, with different filenames. - - - - The ZipFile instance is written to storage, typically a zip file in a - filesystem, only when the caller calls Save. The Save operation writes - the zip content to a temporary file, and then renames the temporary file - to the desired name. If necessary, this method will delete a pre-existing file - before the rename. - - - - - - Thrown if you specify a directory for the filename. - - - - The name of the zip archive to save to. Existing files will - be overwritten with great prejudice. - - - - This example shows how to create and Save a zip file. - - using (ZipFile zip = new ZipFile()) - { - zip.AddDirectory(@"c:\reports\January"); - zip.Save("January.zip"); - } - - - - Using zip As New ZipFile() - zip.AddDirectory("c:\reports\January") - zip.Save("January.zip") - End Using - - - - - - This example shows how to update a zip file. - - using (ZipFile zip = ZipFile.Read("ExistingArchive.zip")) - { - zip.AddFile("NewData.csv"); - zip.Save("UpdatedArchive.zip"); - } - - - - Using zip As ZipFile = ZipFile.Read("ExistingArchive.zip") - zip.AddFile("NewData.csv") - zip.Save("UpdatedArchive.zip") - End Using - - - - - - - Save the zip archive to the specified stream. - - - - - The ZipFile instance is written to storage - typically a zip file - in a filesystem, but using this overload, the storage can be anything - accessible via a writable stream - only when the caller calls Save. - - - - Use this method to save the zip content to a stream directly. A common - scenario is an ASP.NET application that dynamically generates a zip file - and allows the browser to download it. The application can call - Save(Response.OutputStream) to write a zipfile directly to the - output stream, without creating a zip file on the disk on the ASP.NET - server. - - - - Be careful when saving a file to a non-seekable stream, including - Response.OutputStream. When DotNetZip writes to a non-seekable - stream, the zip archive is formatted in such a way that may not be - compatible with all zip tools on all platforms. It's a perfectly legal - and compliant zip file, but some people have reported problems opening - files produced this way using the Mac OS archive utility. - - - - - - - This example saves the zipfile content into a MemoryStream, and - then gets the array of bytes from that MemoryStream. - - - using (var zip = new Ionic.Zip.ZipFile()) - { - zip.CompressionLevel= Ionic.Zlib.CompressionLevel.BestCompression; - zip.Password = "VerySecret."; - zip.Encryption = EncryptionAlgorithm.WinZipAes128; - zip.AddFile(sourceFileName); - MemoryStream output = new MemoryStream(); - zip.Save(output); - - byte[] zipbytes = output.ToArray(); - } - - - - - - This example shows a pitfall you should avoid. DO NOT read - from a stream, then try to save to the same stream. DO - NOT DO THIS: - - - - using (var fs = new FileStream(filename, FileMode.Open)) - { - using (var zip = Ionic.Zip.ZipFile.Read(inputStream)) - { - zip.AddEntry("Name1.txt", "this is the content"); - zip.Save(inputStream); // NO NO NO!! - } - } - - - - Better like this: - - - - using (var zip = Ionic.Zip.ZipFile.Read(filename)) - { - zip.AddEntry("Name1.txt", "this is the content"); - zip.Save(); // YES! - } - - - - - - The System.IO.Stream to write to. It must be - writable. If you created the ZipFile instance by calling - ZipFile.Read(), this stream must not be the same stream - you passed to ZipFile.Read(). - - - - - Adds to the ZipFile a set of files from the current working directory on - disk, that conform to the specified criteria. - - - - - This method selects files from the the current working directory matching - the specified criteria, and adds them to the ZipFile. - - - - Specify the criteria in statements of 3 elements: a noun, an operator, and - a value. Consider the string "name != *.doc" . The noun is "name". The - operator is "!=", implying "Not Equal". The value is "*.doc". That - criterion, in English, says "all files with a name that does not end in - the .doc extension." - - - - Supported nouns include "name" (or "filename") for the filename; "atime", - "mtime", and "ctime" for last access time, last modfied time, and created - time of the file, respectively; "attributes" (or "attrs") for the file - attributes; "size" (or "length") for the file length (uncompressed), and - "type" for the type of object, either a file or a directory. The - "attributes", "name" and "type" nouns both support = and != as operators. - The "size", "atime", "mtime", and "ctime" nouns support = and !=, and - >, >=, <, <= as well. The times are taken to be expressed in - local time. - - - - Specify values for the file attributes as a string with one or more of the - characters H,R,S,A,I,L in any order, implying file attributes of Hidden, - ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint (symbolic - link) respectively. - - - - To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as the - format. If you omit the HH:mm:ss portion, it is assumed to be 00:00:00 - (midnight). - - - - The value for a size criterion is expressed in integer quantities of bytes, - kilobytes (use k or kb after the number), megabytes (m or mb), or gigabytes - (g or gb). - - - - The value for a name is a pattern to match against the filename, potentially - including wildcards. The pattern follows CMD.exe glob rules: * implies one - or more of any character, while ? implies one character. If the name - pattern contains any slashes, it is matched to the entire filename, - including the path; otherwise, it is matched against only the filename - without the path. This means a pattern of "*\*.*" matches all files one - directory level deep, while a pattern of "*.*" matches all files in all - directories. - - - - To specify a name pattern that includes spaces, use single quotes around the - pattern. A pattern of "'* *.*'" will match all files that have spaces in - the filename. The full criteria string for that would be "name = '* *.*'" . - - - - The value for a type criterion is either F (implying a file) or D (implying - a directory). - - - - Some examples: - - - - - criteria - Files retrieved - - - - name != *.xls - any file with an extension that is not .xls - - - - - name = *.mp3 - any file with a .mp3 extension. - - - - - *.mp3 - (same as above) any file with a .mp3 extension. - - - - - attributes = A - all files whose attributes include the Archive bit. - - - - - attributes != H - all files whose attributes do not include the Hidden bit. - - - - - mtime > 2009-01-01 - all files with a last modified time after January 1st, 2009. - - - - - size > 2gb - all files whose uncompressed size is greater than 2gb. - - - - - type = D - all directories in the filesystem. - - - - - - You can combine criteria with the conjunctions AND or OR. Using a string - like "name = *.txt AND size >= 100k" for the selectionCriteria retrieves - entries whose names end in .txt, and whose uncompressed size is greater than - or equal to 100 kilobytes. - - - - For more complex combinations of criteria, you can use parenthesis to group - clauses in the boolean logic. Without parenthesis, the precedence of the - criterion atoms is determined by order of appearance. Unlike the C# - language, the AND conjunction does not take precendence over the logical OR. - This is important only in strings that contain 3 or more criterion atoms. - In other words, "name = *.txt and size > 1000 or attributes = H" implies - "((name = *.txt AND size > 1000) OR attributes = H)" while "attributes = - H OR name = *.txt and size > 1000" evaluates to "((attributes = H OR name - = *.txt) AND size > 1000)". When in doubt, use parenthesis. - - - - Using time properties requires some extra care. If you want to retrieve all - entries that were last updated on 2009 February 14, specify a time range - like so:"mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this to - say: all files updated after 12:00am on February 14th, until 12:00am on - February 15th. You can use the same bracketing approach to specify any time - period - a year, a month, a week, and so on. - - - - The syntax allows one special case: if you provide a string with no spaces, it is - treated as a pattern to match for the filename. Therefore a string like "*.xls" - will be equivalent to specifying "name = *.xls". - - - - There is no logic in this method that insures that the file inclusion - criteria are internally consistent. For example, it's possible to specify - criteria that says the file must have a size of less than 100 bytes, as well - as a size that is greater than 1000 bytes. Obviously no file will ever - satisfy such criteria, but this method does not detect such logical - inconsistencies. The caller is responsible for insuring the criteria are - sensible. - - - - Using this method, the file selection does not recurse into - subdirectories, and the full path of the selected files is included in the - entries added into the zip archive. If you don't like these behaviors, - see the other overloads of this method. - - - - - This example zips up all *.csv files in the current working directory. - - using (ZipFile zip = new ZipFile()) - { - // To just match on filename wildcards, - // use the shorthand form of the selectionCriteria string. - zip.AddSelectedFiles("*.csv"); - zip.Save(PathToZipArchive); - } - - - Using zip As ZipFile = New ZipFile() - zip.AddSelectedFiles("*.csv") - zip.Save(PathToZipArchive) - End Using - - - - The criteria for file selection - - - - Adds to the ZipFile a set of files from the disk that conform to the - specified criteria, optionally recursing into subdirectories. - - - - - This method selects files from the the current working directory matching - the specified criteria, and adds them to the ZipFile. If - recurseDirectories is true, files are also selected from - subdirectories, and the directory structure in the filesystem is - reproduced in the zip archive, rooted at the current working directory. - - - - Using this method, the full path of the selected files is included in the - entries added into the zip archive. If you don't want this behavior, use - one of the overloads of this method that allows the specification of a - directoryInArchive. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - - - - This example zips up all *.xml files in the current working directory, or any - subdirectory, that are larger than 1mb. - - - using (ZipFile zip = new ZipFile()) - { - // Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.xml and size > 1024kb", true); - zip.Save(PathToZipArchive); - } - - - Using zip As ZipFile = New ZipFile() - ' Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.xml and size > 1024kb", true) - zip.Save(PathToZipArchive) - End Using - - - - The criteria for file selection - - - If true, the file selection will recurse into subdirectories. - - - - - Adds to the ZipFile a set of files from a specified directory in the - filesystem, that conform to the specified criteria. - - - - - This method selects files that conform to the specified criteria, from the - the specified directory on disk, and adds them to the ZipFile. The search - does not recurse into subdirectores. - - - - Using this method, the full filesystem path of the files on disk is - reproduced on the entries added to the zip file. If you don't want this - behavior, use one of the other overloads of this method. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - - - - This example zips up all *.xml files larger than 1mb in the directory - given by "d:\rawdata". - - - using (ZipFile zip = new ZipFile()) - { - // Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\\rawdata"); - zip.Save(PathToZipArchive); - } - - - - Using zip As ZipFile = New ZipFile() - ' Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\rawdata) - zip.Save(PathToZipArchive) - End Using - - - - The criteria for file selection - - - The name of the directory on the disk from which to select files. - - - - - Adds to the ZipFile a set of files from the specified directory on disk, - that conform to the specified criteria. - - - - - - This method selects files from the the specified disk directory matching - the specified selection criteria, and adds them to the ZipFile. If - recurseDirectories is true, files are also selected from - subdirectories. - - - - The full directory structure in the filesystem is reproduced on the - entries added to the zip archive. If you don't want this behavior, use - one of the overloads of this method that allows the specification of a - directoryInArchive. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - - - This example zips up all *.csv files in the "files" directory, or any - subdirectory, that have been saved since 2009 February 14th. - - - using (ZipFile zip = new ZipFile()) - { - // Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true); - zip.Save(PathToZipArchive); - } - - - Using zip As ZipFile = New ZipFile() - ' Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true) - zip.Save(PathToZipArchive) - End Using - - - - - This example zips up all files in the current working - directory, and all its child directories, except those in - the excludethis subdirectory. - - Using Zip As ZipFile = New ZipFile(zipfile) - Zip.AddSelectedFfiles("name != 'excludethis\*.*'", datapath, True) - Zip.Save() - End Using - - - - The criteria for file selection - - - The filesystem path from which to select files. - - - - If true, the file selection will recurse into subdirectories. - - - - - Adds to the ZipFile a selection of files from the specified directory on - disk, that conform to the specified criteria, and using a specified root - path for entries added to the zip archive. - - - - - This method selects files from the specified disk directory matching the - specified selection criteria, and adds those files to the ZipFile, using - the specified directory path in the archive. The search does not recurse - into subdirectories. For details on the syntax for the selectionCriteria - parameter, see . - - - - - - - This example zips up all *.psd files in the "photos" directory that have - been saved since 2009 February 14th, and puts them all in a zip file, - using the directory name of "content" in the zip archive itself. When the - zip archive is unzipped, the folder containing the .psd files will be - named "content". - - - using (ZipFile zip = new ZipFile()) - { - // Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content"); - zip.Save(PathToZipArchive); - } - - - Using zip As ZipFile = New ZipFile - zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content") - zip.Save(PathToZipArchive) - End Using - - - - - The criteria for selection of files to add to the ZipFile. - - - - The path to the directory in the filesystem from which to select files. - - - - Specifies a directory path to use to in place of the - directoryOnDisk. This path may, or may not, correspond to a real - directory in the current filesystem. If the files within the zip are - later extracted, this is the path used for the extracted file. Passing - null (nothing in VB) will use the path on the file name, if any; in other - words it would use directoryOnDisk, plus any subdirectory. Passing - the empty string ("") will insert the item at the root path within the - archive. - - - - - Adds to the ZipFile a selection of files from the specified directory on - disk, that conform to the specified criteria, optionally recursing through - subdirectories, and using a specified root path for entries added to the - zip archive. - - - - This method selects files from the specified disk directory that match the - specified selection criteria, and adds those files to the ZipFile, using - the specified directory path in the archive. If recurseDirectories - is true, files are also selected from subdirectories, and the directory - structure in the filesystem is reproduced in the zip archive, rooted at - the directory specified by directoryOnDisk. For details on the - syntax for the selectionCriteria parameter, see . - - - - - This example zips up all files that are NOT *.pst files, in the current - working directory and any subdirectories. - - - using (ZipFile zip = new ZipFile()) - { - zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true); - zip.Save(PathToZipArchive); - } - - - Using zip As ZipFile = New ZipFile - zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true) - zip.Save(PathToZipArchive) - End Using - - - - - The criteria for selection of files to add to the ZipFile. - - - - The path to the directory in the filesystem from which to select files. - - - - Specifies a directory path to use to in place of the - directoryOnDisk. This path may, or may not, correspond to a real - directory in the current filesystem. If the files within the zip are - later extracted, this is the path used for the extracted file. Passing - null (nothing in VB) will use the path on the file name, if any; in other - words it would use directoryOnDisk, plus any subdirectory. Passing - the empty string ("") will insert the item at the root path within the - archive. - - - - If true, the method also scans subdirectories for files matching the - criteria. - - - - - Updates the ZipFile with a selection of files from the disk that conform - to the specified criteria. - - - - This method selects files from the specified disk directory that match the - specified selection criteria, and Updates the ZipFile with those - files, using the specified directory path in the archive. If - recurseDirectories is true, files are also selected from - subdirectories, and the directory structure in the filesystem is - reproduced in the zip archive, rooted at the directory specified by - directoryOnDisk. For details on the syntax for the - selectionCriteria parameter, see . - - - - The criteria for selection of files to add to the ZipFile. - - - - The path to the directory in the filesystem from which to select files. - - - - Specifies a directory path to use to in place of the - directoryOnDisk. This path may, or may not, correspond to a - real directory in the current filesystem. If the files within the zip - are later extracted, this is the path used for the extracted file. - Passing null (nothing in VB) will use the path on the file name, if - any; in other words it would use directoryOnDisk, plus any - subdirectory. Passing the empty string ("") will insert the item at - the root path within the archive. - - - - If true, the method also scans subdirectories for files matching the criteria. - - - - - - - Retrieve entries from the zipfile by specified criteria. - - - - - This method allows callers to retrieve the collection of entries from the zipfile - that fit the specified criteria. The criteria are described in a string format, and - can include patterns for the filename; constraints on the size of the entry; - constraints on the last modified, created, or last accessed time for the file - described by the entry; or the attributes of the entry. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - This method is intended for use with a ZipFile that has been read from storage. - When creating a new ZipFile, this method will work only after the ZipArchive has - been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip - archive from storage.) Calling SelectEntries on a ZipFile that has not yet been - saved will deliver undefined results. - - - - - Thrown if selectionCriteria has an invalid syntax. - - - - This example selects all the PhotoShop files from within an archive, and extracts them - to the current working directory. - - using (ZipFile zip1 = ZipFile.Read(ZipFileName)) - { - var PhotoShopFiles = zip1.SelectEntries("*.psd"); - foreach (ZipEntry psd in PhotoShopFiles) - { - psd.Extract(); - } - } - - - Using zip1 As ZipFile = ZipFile.Read(ZipFileName) - Dim PhotoShopFiles as ICollection(Of ZipEntry) - PhotoShopFiles = zip1.SelectEntries("*.psd") - Dim psd As ZipEntry - For Each psd In PhotoShopFiles - psd.Extract - Next - End Using - - - the string that specifies which entries to select - a collection of ZipEntry objects that conform to the inclusion spec - - - - Retrieve entries from the zipfile by specified criteria. - - - - - This method allows callers to retrieve the collection of entries from the zipfile - that fit the specified criteria. The criteria are described in a string format, and - can include patterns for the filename; constraints on the size of the entry; - constraints on the last modified, created, or last accessed time for the file - described by the entry; or the attributes of the entry. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - This method is intended for use with a ZipFile that has been read from storage. - When creating a new ZipFile, this method will work only after the ZipArchive has - been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip - archive from storage.) Calling SelectEntries on a ZipFile that has not yet been - saved will deliver undefined results. - - - - - Thrown if selectionCriteria has an invalid syntax. - - - - - using (ZipFile zip1 = ZipFile.Read(ZipFileName)) - { - var UpdatedPhotoShopFiles = zip1.SelectEntries("*.psd", "UpdatedFiles"); - foreach (ZipEntry e in UpdatedPhotoShopFiles) - { - // prompt for extract here - if (WantExtract(e.FileName)) - e.Extract(); - } - } - - - Using zip1 As ZipFile = ZipFile.Read(ZipFileName) - Dim UpdatedPhotoShopFiles As ICollection(Of ZipEntry) = zip1.SelectEntries("*.psd", "UpdatedFiles") - Dim e As ZipEntry - For Each e In UpdatedPhotoShopFiles - ' prompt for extract here - If Me.WantExtract(e.FileName) Then - e.Extract - End If - Next - End Using - - - the string that specifies which entries to select - - - the directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - - a collection of ZipEntry objects that conform to the inclusion spec - - - - Remove entries from the zipfile by specified criteria. - - - - - This method allows callers to remove the collection of entries from the zipfile - that fit the specified criteria. The criteria are described in a string format, and - can include patterns for the filename; constraints on the size of the entry; - constraints on the last modified, created, or last accessed time for the file - described by the entry; or the attributes of the entry. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - This method is intended for use with a ZipFile that has been read from storage. - When creating a new ZipFile, this method will work only after the ZipArchive has - been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip - archive from storage.) Calling SelectEntries on a ZipFile that has not yet been - saved will deliver undefined results. - - - - - Thrown if selectionCriteria has an invalid syntax. - - - - This example removes all entries in a zip file that were modified prior to January 1st, 2008. - - using (ZipFile zip1 = ZipFile.Read(ZipFileName)) - { - // remove all entries from prior to Jan 1, 2008 - zip1.RemoveEntries("mtime < 2008-01-01"); - // don't forget to save the archive! - zip1.Save(); - } - - - Using zip As ZipFile = ZipFile.Read(ZipFileName) - ' remove all entries from prior to Jan 1, 2008 - zip1.RemoveEntries("mtime < 2008-01-01") - ' do not forget to save the archive! - zip1.Save - End Using - - - the string that specifies which entries to select - the number of entries removed - - - - Remove entries from the zipfile by specified criteria, and within the specified - path in the archive. - - - - - This method allows callers to remove the collection of entries from the zipfile - that fit the specified criteria. The criteria are described in a string format, and - can include patterns for the filename; constraints on the size of the entry; - constraints on the last modified, created, or last accessed time for the file - described by the entry; or the attributes of the entry. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - This method is intended for use with a ZipFile that has been read from storage. - When creating a new ZipFile, this method will work only after the ZipArchive has - been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip - archive from storage.) Calling SelectEntries on a ZipFile that has not yet been - saved will deliver undefined results. - - - - - Thrown if selectionCriteria has an invalid syntax. - - - - - using (ZipFile zip1 = ZipFile.Read(ZipFileName)) - { - // remove all entries from prior to Jan 1, 2008 - zip1.RemoveEntries("mtime < 2008-01-01", "documents"); - // a call to ZipFile.Save will make the modifications permanent - zip1.Save(); - } - - - Using zip As ZipFile = ZipFile.Read(ZipFileName) - ' remove all entries from prior to Jan 1, 2008 - zip1.RemoveEntries("mtime < 2008-01-01", "documents") - ' a call to ZipFile.Save will make the modifications permanent - zip1.Save - End Using - - - - the string that specifies which entries to select - - the directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - the number of entries removed - - - - Selects and Extracts a set of Entries from the ZipFile. - - - - - The entries are extracted into the current working directory. - - - - If any of the files to be extracted already exist, then the action taken is as - specified in the property on the - corresponding ZipEntry instance. By default, the action taken in this case is to - throw an exception. - - - - For information on the syntax of the selectionCriteria string, - see . - - - - - This example shows how extract all XML files modified after 15 January 2009. - - using (ZipFile zip = ZipFile.Read(zipArchiveName)) - { - zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15"); - } - - - the selection criteria for entries to extract. - - - - - - Selects and Extracts a set of Entries from the ZipFile. - - - - - The entries are extracted into the current working directory. When extraction would would - overwrite an existing filesystem file, the action taken is as specified in the - parameter. - - - - For information on the syntax of the string describing the entry selection criteria, - see . - - - - - This example shows how extract all XML files modified after 15 January 2009, - overwriting any existing files. - - using (ZipFile zip = ZipFile.Read(zipArchiveName)) - { - zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15", - ExtractExistingFileAction.OverwriteSilently); - } - - - - the selection criteria for entries to extract. - - - The action to take if extraction would overwrite an existing file. - - - - - Selects and Extracts a set of Entries from the ZipFile. - - - - - The entries are selected from the specified directory within the archive, and then - extracted into the current working directory. - - - - If any of the files to be extracted already exist, then the action taken is as - specified in the property on the - corresponding ZipEntry instance. By default, the action taken in this case is to - throw an exception. - - - - For information on the syntax of the string describing the entry selection criteria, - see . - - - - - This example shows how extract all XML files modified after 15 January 2009, - and writes them to the "unpack" directory. - - using (ZipFile zip = ZipFile.Read(zipArchiveName)) - { - zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15","unpack"); - } - - - - the selection criteria for entries to extract. - - - the directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - - - - - - Selects and Extracts a set of Entries from the ZipFile. - - - - - The entries are extracted into the specified directory. If any of the files to be - extracted already exist, an exception will be thrown. - - - For information on the syntax of the string describing the entry selection criteria, - see . - - - - the selection criteria for entries to extract. - - - the directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - - - the directory on the disk into which to extract. It will be created - if it does not exist. - - - - - Selects and Extracts a set of Entries from the ZipFile. - - - - - The entries are extracted into the specified directory. When extraction would would - overwrite an existing filesystem file, the action taken is as specified in the - parameter. - - - - For information on the syntax of the string describing the entry selection criteria, - see . - - - - - This example shows how extract all files with an XML extension or with a size larger than 100,000 bytes, - and puts them in the unpack directory. For any files that already exist in - that destination directory, they will not be overwritten. - - using (ZipFile zip = ZipFile.Read(zipArchiveName)) - { - zip.ExtractSelectedEntries("name = *.xml or size > 100000", - null, - "unpack", - ExtractExistingFileAction.DontOverwrite); - } - - - - the selection criteria for entries to extract. - - - The directory on the disk into which to extract. It will be created if it does not exist. - - - - The directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - - - The action to take if extraction would overwrite an existing file. - - - - - - - - Static constructor for ZipFile - - - Code Pages 437 and 1252 for English are same - Code Page 1252 Windows Latin 1 (ANSI) - - Code Page 437 MS-DOS Latin US - - - - - - The default text encoding used in zip archives. It is numeric 437, also - known as IBM437. - - - - - - Generic IEnumerator support, for use of a ZipFile in an enumeration. - - - - You probably do not want to call GetEnumerator explicitly. Instead - it is implicitly called when you use a loop in C#, or a - For Each loop in VB.NET. - - - - This example reads a zipfile of a given name, then enumerates the - entries in that zip file, and displays the information about each - entry on the Console. - - using (ZipFile zip = ZipFile.Read(zipfile)) - { - bool header = true; - foreach (ZipEntry e in zip) - { - if (header) - { - System.Console.WriteLine("Zipfile: {0}", zip.Name); - System.Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded); - System.Console.WriteLine("BitField: 0x{0:X2}", e.BitField); - System.Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod); - System.Console.WriteLine("\n{1,-22} {2,-6} {3,4} {4,-8} {0}", - "Filename", "Modified", "Size", "Ratio", "Packed"); - System.Console.WriteLine(new System.String('-', 72)); - header = false; - } - - System.Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}", - e.FileName, - e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), - e.UncompressedSize, - e.CompressionRatio, - e.CompressedSize); - - e.Extract(); - } - } - - - - Dim ZipFileToExtract As String = "c:\foo.zip" - Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) - Dim header As Boolean = True - Dim e As ZipEntry - For Each e In zip - If header Then - Console.WriteLine("Zipfile: {0}", zip.Name) - Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded) - Console.WriteLine("BitField: 0x{0:X2}", e.BitField) - Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod) - Console.WriteLine(ChrW(10) & "{1,-22} {2,-6} {3,4} {4,-8} {0}", _ - "Filename", "Modified", "Size", "Ratio", "Packed" ) - Console.WriteLine(New String("-"c, 72)) - header = False - End If - Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}", _ - e.FileName, _ - e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), _ - e.UncompressedSize, _ - e.CompressionRatio, _ - e.CompressedSize ) - e.Extract - Next - End Using - - - - A generic enumerator suitable for use within a foreach loop. - - - - An IEnumerator, for use of a ZipFile in a foreach construct. - - - - This method is included for COM support. An application generally does not call - this method directly. It is called implicitly by COM clients when enumerating - the entries in the ZipFile instance. In VBScript, this is done with a For Each - statement. In Javascript, this is done with new Enumerator(zipfile). - - - - The IEnumerator over the entries in the ZipFile. - - - - - This class exposes a set of COM-accessible wrappers for static - methods available on the ZipFile class. You don't need this - class unless you are using DotNetZip from a COM environment. - - - - - A wrapper for ZipFile.IsZipFile(string) - - The filename to of the zip file to check. - true if the file contains a valid zip file. - - - - A wrapper for ZipFile.IsZipFile(string, bool) - - - We cannot use "overloaded" Method names in COM interop. - So, here, we use a unique name. - - The filename to of the zip file to check. - true if the file contains a valid zip file. - - - - A wrapper for ZipFile.CheckZip(string) - - The filename to of the zip file to check. - - true if the named zip file checks OK. Otherwise, false. - - - - A COM-friendly wrapper for the static method . - - - The filename to of the zip file to check. - - The password to check. - - true if the named zip file checks OK. Otherwise, false. - - - - A wrapper for ZipFile.FixZipDirectory(string) - - The filename to of the zip file to fix. - - - - A wrapper for ZipFile.LibraryVersion - - - the version number on the DotNetZip assembly, formatted as a string. - - - - - An enum that provides the various encryption algorithms supported by this - library. - - - - - - PkzipWeak implies the use of Zip 2.0 encryption, which is known to be - weak and subvertible. - - - - A note on interoperability: Values of PkzipWeak and None are - specified in PKWARE's zip - specification, and are considered to be "standard". Zip archives - produced using these options will be interoperable with many other zip tools - and libraries, including Windows Explorer. - - - - Values of WinZipAes128 and WinZipAes256 are not part of the Zip - specification, but rather imply the use of a vendor-specific extension from - WinZip. If you want to produce interoperable Zip archives, do not use these - values. For example, if you produce a zip archive using WinZipAes256, you - will be able to open it in Windows Explorer on Windows XP and Vista, but you - will not be able to extract entries; trying this will lead to an "unspecified - error". For this reason, some people have said that a zip archive that uses - WinZip's AES encryption is not actually a zip archive at all. A zip archive - produced this way will be readable with the WinZip tool (Version 11 and - beyond). - - - - There are other third-party tools and libraries, both commercial and - otherwise, that support WinZip's AES encryption. These will be able to read - AES-encrypted zip archives produced by DotNetZip, and conversely applications - that use DotNetZip to read zip archives will be able to read AES-encrypted - archives produced by those tools or libraries. Consult the documentation for - those other tools and libraries to find out if WinZip's AES encryption is - supported. - - - - In case you care: According to the WinZip specification, the - actual AES key used is derived from the via an - algorithm that complies with RFC 2898, using an iteration - count of 1000. The algorithm is sometimes referred to as PBKDF2, which stands - for "Password Based Key Derivation Function #2". - - - - A word about password strength and length: The AES encryption technology is - very good, but any system is only as secure as the weakest link. If you want - to secure your data, be sure to use a password that is hard to guess. To make - it harder to guess (increase its "entropy"), you should make it longer. If - you use normal characters from an ASCII keyboard, a password of length 20 will - be strong enough that it will be impossible to guess. For more information on - that, I'd encourage you to read this - article. - - - - - - - No encryption at all. - - - - - Traditional or Classic pkzip encryption. - - - - - WinZip AES encryption (128 key bits). - - - - - WinZip AES encryption (256 key bits). - - - - - An encryption algorithm that is not supported by DotNetZip. - - - - - Delegate in which the application writes the ZipEntry content for the named entry. - - - The name of the entry that must be written. - The stream to which the entry data should be written. - - - When you add an entry and specify a WriteDelegate, via , the application - code provides the logic that writes the entry data directly into the zip file. - - - - - This example shows how to define a WriteDelegate that obtains a DataSet, and then - writes the XML for the DataSet into the zip archive. There's no need to - save the XML to a disk file first. - - - private void WriteEntry (String filename, Stream output) - { - DataSet ds1 = ObtainDataSet(); - ds1.WriteXml(output); - } - - private void Run() - { - using (var zip = new ZipFile()) - { - zip.AddEntry(zipEntryName, WriteEntry); - zip.Save(zipFileName); - } - } - - - - Private Sub WriteEntry (ByVal filename As String, ByVal output As Stream) - DataSet ds1 = ObtainDataSet() - ds1.WriteXml(stream) - End Sub - - Public Sub Run() - Using zip = New ZipFile - zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry)) - zip.Save(zipFileName) - End Using - End Sub - - - - - - - Delegate in which the application opens the stream, just-in-time, for the named entry. - - - - The name of the ZipEntry that the application should open the stream for. - - - - When you add an entry via , the application code provides the logic that - opens and closes the stream for the given ZipEntry. - - - - - - - Delegate in which the application closes the stream, just-in-time, for the named entry. - - - - The name of the ZipEntry that the application should close the stream for. - - - The stream to be closed. - - - When you add an entry via , the application code provides the logic that - opens and closes the stream for the given ZipEntry. - - - - - - - Delegate for the callback by which the application tells the - library the CompressionLevel to use for a file. - - - - - Using this callback, the application can, for example, specify that - previously-compressed files (.mp3, .png, .docx, etc) should use a - CompressionLevel of None, or can set the compression level based - on any other factor. - - - - - - - In an EventArgs type, indicates which sort of progress event is being - reported. - - - There are events for reading, events for saving, and events for - extracting. This enumeration allows a single EventArgs type to be sued to - describe one of multiple subevents. For example, a SaveProgress event is - invoked before, after, and during the saving of a single entry. The value - of an enum with this type, specifies which event is being triggered. The - same applies to Extraction, Reading and Adding events. - - - - - Indicates that a Add() operation has started. - - - - - Indicates that an individual entry in the archive has been added. - - - - - Indicates that a Add() operation has completed. - - - - - Indicates that a Read() operation has started. - - - - - Indicates that an individual entry in the archive is about to be read. - - - - - Indicates that an individual entry in the archive has just been read. - - - - - Indicates that a Read() operation has completed. - - - - - The given event reports the number of bytes read so far - during a Read() operation. - - - - - Indicates that a Save() operation has started. - - - - - Indicates that an individual entry in the archive is about to be written. - - - - - Indicates that an individual entry in the archive has just been saved. - - - - - Indicates that a Save() operation has completed. - - - - - Indicates that the zip archive has been created in a - temporary location during a Save() operation. - - - - - Indicates that the temporary file is about to be renamed to the final archive - name during a Save() operation. - - - - - Indicates that the temporary file is has just been renamed to the final archive - name during a Save() operation. - - - - - Indicates that the self-extracting archive has been compiled - during a Save() operation. - - - - - The given event is reporting the number of source bytes that have run through the compressor so far - during a Save() operation. - - - - - Indicates that an entry is about to be extracted. - - - - - Indicates that an entry has just been extracted. - - - - - Indicates that extraction of an entry would overwrite an existing - filesystem file. You must use - - ExtractExistingFileAction.InvokeExtractProgressEvent in the call - to ZipEntry.Extract() in order to receive this event. - - - - - The given event is reporting the number of bytes written so far for - the current entry during an Extract() operation. - - - - - Indicates that an ExtractAll operation is about to begin. - - - - - Indicates that an ExtractAll operation has completed. - - - - - Indicates that an error has occurred while saving a zip file. - This generally means the file cannot be opened, because it has been - removed, or because it is locked by another process. It can also - mean that the file cannot be Read, because of a range lock conflict. - - - - - Provides information about the progress of a save, read, or extract operation. - This is a base class; you will probably use one of the classes derived from this one. - - - - - The total number of entries to be saved or extracted. - - - - - The name of the last entry saved or extracted. - - - - - In an event handler, set this to cancel the save or extract - operation that is in progress. - - - - - The type of event being reported. - - - - - Returns the archive name associated to this event. - - - - - The number of bytes read or written so far for this entry. - - - - - Total number of bytes that will be read or written for this entry. - This number will be -1 if the value cannot be determined. - - - - - Provides information about the progress of a Read operation. - - - - - Provides information about the progress of a Add operation. - - - - - Provides information about the progress of a save operation. - - - - - Constructor for the SaveProgressEventArgs. - - the name of the zip archive. - whether this is before saving the entry, or after - The total number of entries in the zip archive. - Number of entries that have been saved. - The entry involved in the event. - - - - Number of entries saved so far. - - - - - Provides information about the progress of the extract operation. - - - - - Constructor for the ExtractProgressEventArgs. - - the name of the zip archive. - whether this is before saving the entry, or after - The total number of entries in the zip archive. - Number of entries that have been extracted. - The entry involved in the event. - The location to which entries are extracted. - - - - Number of entries extracted so far. This is set only if the - EventType is Extracting_BeforeExtractEntry or Extracting_AfterExtractEntry, and - the Extract() is occurring witin the scope of a call to ExtractAll(). - - - - - Returns the extraction target location, a filesystem path. - - - - - Provides information about the an error that occurred while zipping. - - - - - Returns the exception that occurred, if any. - - - - - Returns the name of the file that caused the exception, if any. - - - - - Issued when an ZipEntry.ExtractWithPassword() method is invoked - with an incorrect password. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - The innerException for this exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - Indicates that a read was attempted on a stream, and bad or incomplete data was - received. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - The innerException for this exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - Issued when an CRC check fails upon extracting an entry from a zip archive. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - Issued when errors occur saving a self-extracting archive. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - Indicates that an operation was attempted on a ZipFile which was not possible - given the state of the instance. For example, if you call Save() on a ZipFile - which has no filename set, you can get this exception. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - The innerException for this exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - Base class for all exceptions defined by and throw by the Zip library. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - The innerException for this exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - An enum for the options when extracting an entry would overwrite an existing file. - - - - - This enum describes the actions that the library can take when an - Extract() or ExtractWithPassword() method is called to extract an - entry to a filesystem, and the extraction would overwrite an existing filesystem - file. - - - - - - - Throw an exception when extraction would overwrite an existing file. (For - COM clients, this is a 0 (zero).) - - - - - When extraction would overwrite an existing file, overwrite the file silently. - The overwrite will happen even if the target file is marked as read-only. - (For COM clients, this is a 1.) - - - - - When extraction would overwrite an existing file, don't overwrite the file, silently. - (For COM clients, this is a 2.) - - - - - When extraction would overwrite an existing file, invoke the ExtractProgress - event, using an event type of . In - this way, the application can decide, just-in-time, whether to overwrite the - file. For example, a GUI application may wish to pop up a dialog to allow - the user to choose. You may want to examine the property before making - the decision. If, after your processing in the Extract progress event, you - want to NOT extract the file, set - on the ZipProgressEventArgs.CurrentEntry to DoNotOverwrite. - If you do want to extract the file, set ZipEntry.ExtractExistingFile - to OverwriteSilently. If you want to cancel the Extraction, set - ZipProgressEventArgs.Cancel to true. Cancelling differs from using - DoNotOverwrite in that a cancel will not extract any further entries, if - there are any. (For COM clients, the value of this enum is a 3.) - - - - - Collects general purpose utility methods. - - - - private null constructor - - - - Utility routine for transforming path names from filesystem format (on Windows that means backslashes) to - a format suitable for use within zipfiles. This means trimming the volume letter and colon (if any) And - swapping backslashes for forward slashes. - - source path. - transformed path - - - - Sanitize paths in zip files. This means making sure that relative paths in a zip file don't go outside - the top directory. Entries like something/../../../../Temp/evil.txt get sanitized to Temp/evil.txt - when extracting - - A path with forward slashes as directory separator - sanitized path - - - - Finds a signature in the zip stream. This is useful for finding - the end of a zip entry, for example, or the beginning of the next ZipEntry. - - - - - Scans through 64k at a time. - - - - If the method fails to find the requested signature, the stream Position - after completion of this method is unchanged. If the method succeeds in - finding the requested signature, the stream position after completion is - direct AFTER the signature found in the stream. - - - - The stream to search - The 4-byte signature to find - The number of bytes read - - - - Create a pseudo-random filename, suitable for use as a temporary - file, and open it. - - - - This method produces a filename of the form - DotNetZip-xxxxxxxx.tmp, where xxxxxxxx is replaced by randomly - chosen characters, and creates that file. - - - - - - Workitem 7889: handle ERROR_LOCK_VIOLATION during read - - - This could be gracefully handled with an extension attribute, but - This assembly used to be built for .NET 2.0, so could not use - extension methods. - - - - - A decorator stream. It wraps another stream, and performs bookkeeping - to keep track of the stream Position. - - - - In some cases, it is not possible to get the Position of a stream, let's - say, on a write-only output stream like ASP.NET's - Response.OutputStream, or on a different write-only stream - provided as the destination for the zip by the application. In this - case, programmers can use this counting stream to count the bytes read - or written. - - - Consider the scenario of an application that saves a self-extracting - archive (SFX), that uses a custom SFX stub. - - - Saving to a filesystem file, the application would open the - filesystem file (getting a FileStream), save the custom sfx stub - into it, and then call ZipFile.Save(), specifying the same - FileStream. ZipFile.Save() does the right thing for the zipentry - offsets, by inquiring the Position of the FileStream before writing - any data, and then adding that initial offset into any ZipEntry - offsets in the zip directory. Everything works fine. - - - Now suppose the application is an ASPNET application and it saves - directly to Response.OutputStream. It's not possible for DotNetZip to - inquire the Position, so the offsets for the SFX will be wrong. - - - The workaround is for the application to use this class to wrap - HttpResponse.OutputStream, then write the SFX stub and the ZipFile - into that wrapper stream. Because ZipFile.Save() can inquire the - Position, it will then do the right thing with the offsets. - - - - - - The constructor. - - The underlying stream - - - - Gets the wrapped stream. - - - - - The count of bytes written out to the stream. - - - - - the count of bytes that have been read from the stream. - - - - - Adjust the byte count on the stream. - - - - the number of bytes to subtract from the count. - - - - - Subtract delta from the count of bytes written to the stream. - This is necessary when seeking back, and writing additional data, - as happens in some cases when saving Zip files. - - - - - - The read method. - - The buffer to hold the data read from the stream. - the offset within the buffer to copy the first byte read. - the number of bytes to read. - the number of bytes read, after decryption and decompression. - - - - Write data into the stream. - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Whether the stream can be read. - - - - - Whether it is possible to call Seek() on the stream. - - - - - Whether it is possible to call Write() on the stream. - - - - - Flushes the underlying stream. - - - - - The length of the underlying stream. - - - - - Returns the sum of number of bytes written, plus the initial - offset before writing. - - - - - The Position of the stream. - - - - - Seek in the stream. - - the offset point to seek to - the reference point from which to seek - The new position - - - - Set the length of the underlying stream. Be careful with this! - - - the length to set on the underlying stream. - - - - This is a helper class supporting WinZip AES encryption. - This class is intended for use only by the DotNetZip library. - - - - Most uses of the DotNetZip library will not involve direct calls into - the WinZipAesCrypto class. Instead, the WinZipAesCrypto class is - instantiated and used by the ZipEntry() class when WinZip AES - encryption or decryption on an entry is employed. - - - - - A stream that encrypts as it writes, or decrypts as it reads. The - Crypto is AES in CTR (counter) mode, which is compatible with the AES - encryption employed by WinZip 12.0. - - - - The AES/CTR encryption protocol used by WinZip works like this: - - - start with a counter, initialized to zero. - - - to encrypt, take the data by 16-byte blocks. For each block: - - apply the transform to the counter - - increement the counter - - XOR the result of the transform with the plaintext to - get the ciphertext. - - compute the mac on the encrypted bytes - - when finished with all blocks, store the computed MAC. - - - to decrypt, take the data by 16-byte blocks. For each block: - - compute the mac on the encrypted bytes, - - apply the transform to the counter - - increement the counter - - XOR the result of the transform with the ciphertext to - get the plaintext. - - when finished with all blocks, compare the computed MAC against - the stored MAC - - - - - - - The constructor. - - The underlying stream - To either encrypt or decrypt. - The pre-initialized WinZipAesCrypto object. - The maximum number of bytes to read from the stream. - - - - Returns the final HMAC-SHA1-80 for the data that was encrypted. - - - - - Close the stream. - - - - - Returns true if the stream can be read. - - - - - Always returns false. - - - - - Returns true if the CryptoMode is Encrypt. - - - - - Flush the content in the stream. - - - - - Getting this property throws a NotImplementedException. - - - - - Getting or Setting this property throws a NotImplementedException. - - - - - This method throws a NotImplementedException. - - - - - This method throws a NotImplementedException. - - - - - This class implements the "traditional" or "classic" PKZip encryption, - which today is considered to be weak. On the other hand it is - ubiquitous. This class is intended for use only by the DotNetZip - library. - - - - Most uses of the DotNetZip library will not involve direct calls into - the ZipCrypto class. Instead, the ZipCrypto class is instantiated and - used by the ZipEntry() class when encryption or decryption on an entry - is employed. If for some reason you really wanted to use a weak - encryption algorithm in some other application, you might use this - library. But you would be much better off using one of the built-in - strong encryption libraries in the .NET Framework, like the AES - algorithm or SHA. - - - - - The default constructor for ZipCrypto. - - - - This class is intended for internal use by the library only. It's - probably not useful to you. Seriously. Stop reading this - documentation. It's a waste of your time. Go do something else. - Check the football scores. Go get an ice cream with a friend. - Seriously. - - - - - - From AppNote.txt: - unsigned char decrypt_byte() - local unsigned short temp - temp :=- Key(2) | 2 - decrypt_byte := (temp * (temp ^ 1)) bitshift-right 8 - end decrypt_byte - - - - - Call this method on a cipher text to render the plaintext. You must - first initialize the cipher with a call to InitCipher. - - - - - var cipher = new ZipCrypto(); - cipher.InitCipher(Password); - // Decrypt the header. This has a side effect of "further initializing the - // encryption keys" in the traditional zip encryption. - byte[] DecryptedMessage = cipher.DecryptMessage(EncryptedMessage); - - - - The encrypted buffer. - - The number of bytes to encrypt. - Should be less than or equal to CipherText.Length. - - - The plaintext. - - - - This is the converse of DecryptMessage. It encrypts the plaintext - and produces a ciphertext. - - - The plain text buffer. - - - The number of bytes to encrypt. - Should be less than or equal to plainText.Length. - - - The ciphertext. - - - - This initializes the cipher with the given password. - See AppNote.txt for details. - - - - The passphrase for encrypting or decrypting with this cipher. - - - - - Step 1 - Initializing the encryption keys - ----------------------------------------- - Start with these keys: - Key(0) := 305419896 (0x12345678) - Key(1) := 591751049 (0x23456789) - Key(2) := 878082192 (0x34567890) - - Then, initialize the keys with a password: - - loop for i from 0 to length(password)-1 - update_keys(password(i)) - end loop - - Where update_keys() is defined as: - - update_keys(char): - Key(0) := crc32(key(0),char) - Key(1) := Key(1) + (Key(0) bitwiseAND 000000ffH) - Key(1) := Key(1) * 134775813 + 1 - Key(2) := crc32(key(2),key(1) rightshift 24) - end update_keys - - Where crc32(old_crc,char) is a routine that given a CRC value and a - character, returns an updated CRC value after applying the CRC-32 - algorithm described elsewhere in this document. - - - - - After the keys are initialized, then you can use the cipher to - encrypt the plaintext. - - - - Essentially we encrypt the password with the keys, then discard the - ciphertext for the password. This initializes the keys for later use. - - - - - - - A Stream for reading and concurrently decrypting data from a zip file, - or for writing and concurrently encrypting data to a zip file. - - - - The constructor. - The underlying stream - To either encrypt or decrypt. - The pre-initialized ZipCrypto object. - - - - Represents a single entry in a ZipFile. Typically, applications get a ZipEntry - by enumerating the entries within a ZipFile, or by adding an entry to a ZipFile. - - - - - True if the referenced entry is a directory. - - - - - Provides a human-readable string with information about the ZipEntry. - - - - - Reads one entry from the zip directory structure in the zip file. - - - - The zipfile for which a directory entry will be read. From this param, the - method gets the ReadStream and the expected text encoding - (ProvisionalAlternateEncoding) which is used if the entry is not marked - UTF-8. - - - - a list of previously seen entry names; used to prevent duplicates. - - - the entry read from the archive. - - - - Returns true if the passed-in value is a valid signature for a ZipDirEntry. - - the candidate 4-byte signature value. - true, if the signature is valid according to the PKWare spec. - - - - Default constructor. - - - Applications should never need to call this directly. It is exposed to - support COM Automation environments. - - - - - The time and date at which the file indicated by the ZipEntry was - last modified. - - - - - The DotNetZip library sets the LastModified value for an entry, equal to - the Last Modified time of the file in the filesystem. If an entry is - added from a stream, the library uses System.DateTime.Now for this - value, for the given entry. - - - - This property allows the application to retrieve and possibly set the - LastModified value on an entry, to an arbitrary value. values with a - setting of DateTimeKind.Unspecified are taken to be expressed as - DateTimeKind.Local. - - - - Be aware that because of the way PKWare's - Zip specification describes how times are stored in the zip file, - the full precision of the System.DateTime datatype is not stored - for the last modified time when saving zip files. For more information on - how times are formatted, see the PKZip specification. - - - - The actual last modified time of a file can be stored in multiple ways in - the zip file, and they are not mutually exclusive: - - - - - In the so-called "DOS" format, which has a 2-second precision. Values - are rounded to the nearest even second. For example, if the time on the - file is 12:34:43, then it will be stored as 12:34:44. This first value - is accessible via the LastModified property. This value is always - present in the metadata for each zip entry. In some cases the value is - invalid, or zero. - - - - In the so-called "Windows" or "NTFS" format, as an 8-byte integer - quantity expressed as the number of 1/10 milliseconds (in other words - the number of 100 nanosecond units) since January 1, 1601 (UTC). This - format is how Windows represents file times. This time is accessible - via the ModifiedTime property. - - - - In the "Unix" format, a 4-byte quantity specifying the number of seconds since - January 1, 1970 UTC. - - - - In an older format, now deprecated but still used by some current - tools. This format is also a 4-byte quantity specifying the number of - seconds since January 1, 1970 UTC. - - - - - - Zip tools and libraries will always at least handle (read or write) the - DOS time, and may also handle the other time formats. Keep in mind that - while the names refer to particular operating systems, there is nothing in - the time formats themselves that prevents their use on other operating - systems. - - - - When reading ZIP files, the DotNetZip library reads the Windows-formatted - time, if it is stored in the entry, and sets both LastModified and - ModifiedTime to that value. When writing ZIP files, the DotNetZip - library by default will write both time quantities. It can also emit the - Unix-formatted time if desired (See .) - - - - The last modified time of the file created upon a call to - ZipEntry.Extract() may be adjusted during extraction to compensate - for differences in how the .NET Base Class Library deals with daylight - saving time (DST) versus how the Windows filesystem deals with daylight - saving time. Raymond Chen provides - some good context. - - - - In a nutshell: Daylight savings time rules change regularly. In 2007, for - example, the inception week of DST changed. In 1977, DST was in place all - year round. In 1945, likewise. And so on. Win32 does not attempt to - guess which time zone rules were in effect at the time in question. It - will render a time as "standard time" and allow the app to change to DST - as necessary. .NET makes a different choice. - - - - Compare the output of FileInfo.LastWriteTime.ToString("f") with what you - see in the Windows Explorer property sheet for a file that was last - written to on the other side of the DST transition. For example, suppose - the file was last modified on October 17, 2003, during DST but DST is not - currently in effect. Explorer's file properties reports Thursday, October - 17, 2003, 8:45:38 AM, but .NETs FileInfo reports Thursday, October 17, - 2003, 9:45 AM. - - - - Win32 says, "Thursday, October 17, 2002 8:45:38 AM PST". Note: Pacific - STANDARD Time. Even though October 17 of that year occurred during Pacific - Daylight Time, Win32 displays the time as standard time because that's - what time it is NOW. - - - - .NET BCL assumes that the current DST rules were in place at the time in - question. So, .NET says, "Well, if the rules in effect now were also in - effect on October 17, 2003, then that would be daylight time" so it - displays "Thursday, October 17, 2003, 9:45 AM PDT" - daylight time. - - - - So .NET gives a value which is more intuitively correct, but is also - potentially incorrect, and which is not invertible. Win32 gives a value - which is intuitively incorrect, but is strictly correct. - - - - Because of this funkiness, this library adds one hour to the LastModified - time on the extracted file, if necessary. That is to say, if the time in - question had occurred in what the .NET Base Class Library assumed to be - DST. This assumption may be wrong given the constantly changing DST rules, - but it is the best we can do. - - - - - - - - Ability to set Last Modified DOS time to zero - (for using with EmitTimesInWindowsFormatWhenSaving+EmitTimesInUnixFormatWhenSaving setted to false) - some flasher hardware use as marker of first binary - - - - - Last Modified time for the file represented by the entry. - - - - - - This value corresponds to the "last modified" time in the NTFS file times - as described in the Zip - specification. When getting this property, the value may be - different from . When setting the property, - the property also gets set, but with a lower - precision. - - - - Let me explain. It's going to take a while, so get - comfortable. Originally, waaaaay back in 1989 when the ZIP specification - was originally described by the esteemed Mr. Phil Katz, the dominant - operating system of the time was MS-DOS. MSDOS stored file times with a - 2-second precision, because, c'mon, who is ever going to need better - resolution than THAT? And so ZIP files, regardless of the platform on - which the zip file was created, store file times in exactly the same format that DOS used - in 1989. - - - - Since then, the ZIP spec has evolved, but the internal format for file - timestamps remains the same. Despite the fact that the way times are - stored in a zip file is rooted in DOS heritage, any program on any - operating system can format a time in this way, and most zip tools and - libraries DO - they round file times to the nearest even second and store - it just like DOS did 25+ years ago. - - - - PKWare extended the ZIP specification to allow a zip file to store what - are called "NTFS Times" and "Unix(tm) times" for a file. These are the - last write, last access, and file creation - times of a particular file. These metadata are not actually specific - to NTFS or Unix. They are tracked for each file by NTFS and by various - Unix filesystems, but they are also tracked by other filesystems, too. - The key point is that the times are formatted in the zip file - in the same way that NTFS formats the time (ticks since win32 epoch), - or in the same way that Unix formats the time (seconds since Unix - epoch). As with the DOS time, any tool or library running on any - operating system is capable of formatting a time in one of these ways - and embedding it into the zip file. - - - - These extended times are higher precision quantities than the DOS time. - As described above, the (DOS) LastModified has a precision of 2 seconds. - The Unix time is stored with a precision of 1 second. The NTFS time is - stored with a precision of 0.0000001 seconds. The quantities are easily - convertible, except for the loss of precision you may incur. - - - - A zip archive can store the {C,A,M} times in NTFS format, in Unix format, - or not at all. Often a tool running on Unix or Mac will embed the times - in Unix format (1 second precision), while WinZip running on Windows might - embed the times in NTFS format (precision of of 0.0000001 seconds). When - reading a zip file with these "extended" times, in either format, - DotNetZip represents the values with the - ModifiedTime, AccessedTime and CreationTime - properties on the ZipEntry. - - - - While any zip application or library, regardless of the platform it - runs on, could use any of the time formats allowed by the ZIP - specification, not all zip tools or libraries do support all these - formats. Storing the higher-precision times for each entry is - optional for zip files, and many tools and libraries don't use the - higher precision quantities at all. The old DOS time, represented by - , is guaranteed to be present, though it - sometimes unset. - - - - Ok, getting back to the question about how the LastModified - property relates to this ModifiedTime - property... LastModified is always set, while - ModifiedTime is not. (The other times stored in the NTFS - times extension, CreationTime and AccessedTime also - may not be set on an entry that is read from an existing zip file.) - When reading a zip file, then LastModified takes the DOS time - that is stored with the file. If the DOS time has been stored as zero - in the zipfile, then this library will use DateTime.Now for the - LastModified value. If the ZIP file was created by an evolved - tool, then there will also be higher precision NTFS or Unix times in - the zip file. In that case, this library will read those times, and - set LastModified and ModifiedTime to the same value, the - one corresponding to the last write time of the file. If there are no - higher precision times stored for the entry, then ModifiedTime - remains unset (likewise AccessedTime and CreationTime), - and LastModified keeps its DOS time. - - - - When creating zip files with this library, by default the extended time - properties (ModifiedTime, AccessedTime, and - CreationTime) are set on the ZipEntry instance, and these data are - stored in the zip archive for each entry, in NTFS format. If you add an - entry from an actual filesystem file, then the entry gets the actual file - times for that file, to NTFS-level precision. If you add an entry from a - stream, or a string, then the times get the value DateTime.Now. In - this case LastModified and ModifiedTime will be identical, - to 2 seconds of precision. You can explicitly set the - CreationTime, AccessedTime, and ModifiedTime of an - entry using the property setters. If you want to set all of those - quantities, it's more efficient to use the method. Those - changes are not made permanent in the zip file until you call or one of its cousins. - - - - When creating a zip file, you can override the default behavior of - this library for formatting times in the zip file, disabling the - embedding of file times in NTFS format or enabling the storage of file - times in Unix format, or both. You may want to do this, for example, - when creating a zip file on Windows, that will be consumed on a Mac, - by an application that is not hip to the "NTFS times" format. To do - this, use the and - properties. A valid zip - file may store the file times in both formats. But, there are no - guarantees that a program running on Mac or Linux will gracefully - handle the NTFS-formatted times when Unix times are present, or that a - non-DotNetZip-powered application running on Windows will be able to - handle file times in Unix format. DotNetZip will always do something - reasonable; other libraries or tools may not. When in doubt, test. - - - - I'll bet you didn't think one person could type so much about time, eh? - And reading it was so enjoyable, too! Well, in appreciation, maybe you - should donate? - - - - - - - - - - - Last Access time for the file represented by the entry. - - - This value may or may not be meaningful. If the ZipEntry was read from an existing - Zip archive, this information may not be available. For an explanation of why, see - . - - - - - - - - The file creation time for the file represented by the entry. - - - - This value may or may not be meaningful. If the ZipEntry was read - from an existing zip archive, and the creation time was not set on the entry - when the zip file was created, then this property may be meaningless. For an - explanation of why, see . - - - - - - - - Sets the NTFS Creation, Access, and Modified times for the given entry. - - - - - When adding an entry from a file or directory, the Creation, Access, and - Modified times for the given entry are automatically set from the - filesystem values. When adding an entry from a stream or string, the - values are implicitly set to DateTime.Now. The application may wish to - set these values to some arbitrary value, before saving the archive, and - can do so using the various setters. If you want to set all of the times, - this method is more efficient. - - - - The values you set here will be retrievable with the , and properties. - - - - When this method is called, if both and are false, then the - EmitTimesInWindowsFormatWhenSaving flag is automatically set. - - - - DateTime values provided here without a DateTimeKind are assumed to be Local Time. - - - - the creation time of the entry. - the last access time of the entry. - the last modified time of the entry. - - - - - - - - - - Specifies whether the Creation, Access, and Modified times for the given - entry will be emitted in "Windows format" when the zip archive is saved. - - - - - An application creating a zip archive can use this flag to explicitly - specify that the file times for the entry should or should not be stored - in the zip archive in the format used by Windows. The default value of - this property is true. - - - - When adding an entry from a file or directory, the Creation (), Access (), and Modified - () times for the given entry are automatically - set from the filesystem values. When adding an entry from a stream or - string, all three values are implicitly set to DateTime.Now. Applications - can also explicitly set those times by calling . - - - - PKWARE's - zip specification describes multiple ways to format these times in a - zip file. One is the format Windows applications normally use: 100ns ticks - since Jan 1, 1601 UTC. The other is a format Unix applications typically - use: seconds since January 1, 1970 UTC. Each format can be stored in an - "extra field" in the zip entry when saving the zip archive. The former - uses an extra field with a Header Id of 0x000A, while the latter uses a - header ID of 0x5455. - - - - Not all zip tools and libraries can interpret these fields. Windows - compressed folders is one that can read the Windows Format timestamps, - while I believe the Infozip - tools can read the Unix format timestamps. Although the time values are - easily convertible, subject to a loss of precision, some tools and - libraries may be able to read only one or the other. DotNetZip can read or - write times in either or both formats. - - - - The times stored are taken from , , and . - - - - This property is not mutually exclusive from the property. It is - possible that a zip entry can embed the timestamps in both forms, one - form, or neither. But, there are no guarantees that a program running on - Mac or Linux will gracefully handle NTFS Formatted times, or that a - non-DotNetZip-powered application running on Windows will be able to - handle file times in Unix format. When in doubt, test. - - - - Normally you will use the ZipFile.EmitTimesInWindowsFormatWhenSaving - property, to specify the behavior for all entries in a zip, rather than - the property on each individual entry. - - - - - - - - - - - - - Specifies whether the Creation, Access, and Modified times for the given - entry will be emitted in "Unix(tm) format" when the zip archive is saved. - - - - - An application creating a zip archive can use this flag to explicitly - specify that the file times for the entry should or should not be stored - in the zip archive in the format used by Unix. By default this flag is - false, meaning the Unix-format times are not stored in the zip - archive. - - - - When adding an entry from a file or directory, the Creation (), Access (), and Modified - () times for the given entry are automatically - set from the filesystem values. When adding an entry from a stream or - string, all three values are implicitly set to DateTime.Now. Applications - can also explicitly set those times by calling . - - - - PKWARE's - zip specification describes multiple ways to format these times in a - zip file. One is the format Windows applications normally use: 100ns ticks - since Jan 1, 1601 UTC. The other is a format Unix applications typically - use: seconds since Jan 1, 1970 UTC. Each format can be stored in an - "extra field" in the zip entry when saving the zip archive. The former - uses an extra field with a Header Id of 0x000A, while the latter uses a - header ID of 0x5455. - - - - Not all tools and libraries can interpret these fields. Windows - compressed folders is one that can read the Windows Format timestamps, - while I believe the Infozip - tools can read the Unix format timestamps. Although the time values are - easily convertible, subject to a loss of precision, some tools and - libraries may be able to read only one or the other. DotNetZip can read or - write times in either or both formats. - - - - The times stored are taken from , , and . - - - - This property is not mutually exclusive from the property. It is - possible that a zip entry can embed the timestamps in both forms, one - form, or neither. But, there are no guarantees that a program running on - Mac or Linux will gracefully handle NTFS Formatted times, or that a - non-DotNetZip-powered application running on Windows will be able to - handle file times in Unix format. When in doubt, test. - - - - Normally you will use the ZipFile.EmitTimesInUnixFormatWhenSaving - property, to specify the behavior for all entries, rather than the - property on each individual entry. - - - - - - - - - - - - - The type of timestamp attached to the ZipEntry. - - - - This property is valid only for a ZipEntry that was read from a zip archive. - It indicates the type of timestamp attached to the entry. - - - - - - - - The file attributes for the entry. - - - - - - The attributes in NTFS include - ReadOnly, Archive, Hidden, System, and Indexed. When adding a - ZipEntry to a ZipFile, these attributes are set implicitly when - adding an entry from the filesystem. When adding an entry from a stream - or string, the Attributes are not set implicitly. Regardless of the way - an entry was added to a ZipFile, you can set the attributes - explicitly if you like. - - - - When reading a ZipEntry from a ZipFile, the attributes are - set according to the data stored in the ZipFile. If you extract the - entry from the archive to a filesystem file, DotNetZip will set the - attributes on the resulting file accordingly. - - - - The attributes can be set explicitly by the application. For example the - application may wish to set the FileAttributes.ReadOnly bit for all - entries added to an archive, so that on unpack, this attribute will be set - on the extracted file. Any changes you make to this property are made - permanent only when you call a Save() method on the ZipFile - instance that contains the ZipEntry. - - - - For example, an application may wish to zip up a directory and set the - ReadOnly bit on every file in the archive, so that upon later extraction, - the resulting files will be marked as ReadOnly. Not every extraction tool - respects these attributes, but if you unpack with DotNetZip, as for - example in a self-extracting archive, then the attributes will be set as - they are stored in the ZipFile. - - - - These attributes may not be interesting or useful if the resulting archive - is extracted on a non-Windows platform. How these attributes get used - upon extraction depends on the platform and tool used. - - - - - - - The name of the filesystem file, referred to by the ZipEntry. - - - - - This property specifies the thing-to-be-zipped on disk, and is set only - when the ZipEntry is being created from a filesystem file. If the - ZipFile is instantiated by reading an existing .zip archive, then - the LocalFileName will be null (Nothing in VB). - - - - When it is set, the value of this property may be different than , which is the path used in the archive itself. If you - call Zip.AddFile("foop.txt", AlternativeDirectory), then the path - used for the ZipEntry within the zip archive will be different - than this path. - - - - If the entry is being added from a stream, then this is null (Nothing in VB). - - - - - - - - The name of the file contained in the ZipEntry. - - - - - - This is the name of the entry in the ZipFile itself. When creating - a zip archive, if the ZipEntry has been created from a filesystem - file, via a call to or , or a related overload, the value - of this property is derived from the name of that file. The - FileName property does not include drive letters, and may include a - different directory path, depending on the value of the - directoryPathInArchive parameter used when adding the entry into - the ZipFile. - - - - In some cases there is no related filesystem file - for example when a - ZipEntry is created using or one of the similar overloads. In this case, the value of - this property is derived from the fileName and the directory path passed - to that method. - - - - When reading a zip file, this property takes the value of the entry name - as stored in the zip file. If you extract such an entry, the extracted - file will take the name given by this property. - - - - Applications can set this property when creating new zip archives or when - reading existing archives. When setting this property, the actual value - that is set will replace backslashes with forward slashes, in accordance - with the Zip - specification, for compatibility with Unix(tm) and ... get - this.... Amiga! - - - - If an application reads a ZipFile via or a related overload, and then explicitly - sets the FileName on an entry contained within the ZipFile, and - then calls , the application will effectively - rename the entry within the zip archive. - - - - If an application sets the value of FileName, then calls - Extract() on the entry, the entry is extracted to a file using the - newly set value as the filename. The FileName value is made - permanent in the zip archive only after a call to one of the - ZipFile.Save() methods on the ZipFile that contains the - ZipEntry. - - - - If an application attempts to set the FileName to a value that - would result in a duplicate entry in the ZipFile, an exception is - thrown. - - - - When a ZipEntry is contained within a ZipFile, applications - cannot rename the entry within the context of a foreach (For - Each in VB) loop, because of the way the ZipFile stores - entries. If you need to enumerate through all the entries and rename one - or more of them, use ZipFile.EntriesSorted as the - collection. See also, ZipFile.GetEnumerator(). - - - - - - - The stream that provides content for the ZipEntry. - - - - - - The application can use this property to set the input stream for an - entry on a just-in-time basis. Imagine a scenario where the application - creates a ZipFile comprised of content obtained from hundreds of - files, via calls to AddFile(). The DotNetZip library opens streams - on these files on a just-in-time basis, only when writing the entry out to - an external store within the scope of a ZipFile.Save() call. Only - one input stream is opened at a time, as each entry is being written out. - - - - Now imagine a different application that creates a ZipFile - with content obtained from hundreds of streams, added through . Normally the - application would supply an open stream to that call. But when large - numbers of streams are being added, this can mean many open streams at one - time, unnecessarily. - - - - To avoid this, call and specify delegates that open and close the stream at - the time of Save. - - - - - Setting the value of this property when the entry was not added from a - stream (for example, when the ZipEntry was added with or , or when the entry was added by - reading an existing zip archive) will throw an exception. - - - - - - - - A flag indicating whether the InputStream was provided Just-in-time. - - - - - - When creating a zip archive, an application can obtain content for one or - more of the ZipEntry instances from streams, using the method. At the time - of calling that method, the application can supply null as the value of - the stream parameter. By doing so, the application indicates to the - library that it will provide a stream for the entry on a just-in-time - basis, at the time one of the ZipFile.Save() methods is called and - the data for the various entries are being compressed and written out. - - - - In this case, the application can set the - property, typically within the SaveProgress event (event type: ) for that entry. - - - - The application will later want to call Close() and Dispose() on that - stream. In the SaveProgress event, when the event type is , the application can - do so. This flag indicates that the stream has been provided by the - application on a just-in-time basis and that it is the application's - responsibility to call Close/Dispose on that stream. - - - - - - - - An enum indicating the source of the ZipEntry. - - - - - The version of the zip engine needed to read the ZipEntry. - - - - - This is a readonly property, indicating the version of the Zip - specification that the extracting tool or library must support to - extract the given entry. Generally higher versions indicate newer - features. Older zip engines obviously won't know about new features, and - won't be able to extract entries that depend on those newer features. - - - - - value - Features - - - - 20 - a basic Zip Entry, potentially using PKZIP encryption. - - - - - 45 - The ZIP64 extension is used on the entry. - - - - - 46 - File is compressed using BZIP2 compression* - - - - 50 - File is encrypted using PkWare's DES, 3DES, (broken) RC2 or RC4 - - - - 51 - File is encrypted using PKWare's AES encryption or corrected RC2 encryption. - - - - 52 - File is encrypted using corrected RC2-64 encryption** - - - - 61 - File is encrypted using non-OAEP key wrapping*** - - - - 63 - File is compressed using LZMA, PPMd+, Blowfish, or Twofish - - - - - - There are other values possible, not listed here. DotNetZip supports - regular PKZip encryption, and ZIP64 extensions. DotNetZip cannot extract - entries that require a zip engine higher than 45. - - - - This value is set upon reading an existing zip file, or after saving a zip - archive. - - - - - - The comment attached to the ZipEntry. - - - - - Each entry in a zip file can optionally have a comment associated to - it. The comment might be displayed by a zip tool during extraction, for - example. - - - - By default, the Comment is encoded in IBM437 code page. You can - specify an alternative with and - . - - - - - - - - Indicates whether the entry requires ZIP64 extensions. - - - - - - This property is null (Nothing in VB) until a Save() method on the - containing instance has been called. The property is - non-null (HasValue is true) only after a Save() method has - been called. - - - - After the containing ZipFile has been saved, the Value of this - property is true if any of the following three conditions holds: the - uncompressed size of the entry is larger than 0xFFFFFFFF; the compressed - size of the entry is larger than 0xFFFFFFFF; the relative offset of the - entry within the zip archive is larger than 0xFFFFFFFF. These quantities - are not known until a Save() is attempted on the zip archive and - the compression is applied. - - - - If none of the three conditions holds, then the Value is false. - - - - A Value of false does not indicate that the entry, as saved in the - zip archive, does not use ZIP64. It merely indicates that ZIP64 is - not required. An entry may use ZIP64 even when not required if - the property on the containing - ZipFile instance is set to , or if - the property on the containing - ZipFile instance is set to - and the output stream was not seekable. - - - - - - - - Indicates whether the entry actually used ZIP64 extensions, as it was most - recently written to the output file or stream. - - - - - - This Nullable property is null (Nothing in VB) until a Save() - method on the containing instance has been - called. HasValue is true only after a Save() method has been - called. - - - - The value of this property for a particular ZipEntry may change - over successive calls to Save() methods on the containing ZipFile, - even if the file that corresponds to the ZipEntry does not. This - may happen if other entries contained in the ZipFile expand, - causing the offset for this particular entry to exceed 0xFFFFFFFF. - - - - - - - The bitfield for the entry as defined in the zip spec. You probably - never need to look at this. - - - - - You probably do not need to concern yourself with the contents of this - property, but in case you do: - - - - - bit - meaning - - - - 0 - set if encryption is used. - - - - 1-2 - - set to determine whether normal, max, fast deflation. DotNetZip library - always leaves these bits unset when writing (indicating "normal" - deflation"), but can read an entry with any value here. - - - - - 3 - - Indicates that the Crc32, Compressed and Uncompressed sizes are zero in the - local header. This bit gets set on an entry during writing a zip file, when - it is saved to a non-seekable output stream. - - - - - - 4 - reserved for "enhanced deflating". This library doesn't do enhanced deflating. - - - - 5 - set to indicate the zip is compressed patched data. This library doesn't do that. - - - - 6 - - set if PKWare's strong encryption is used (must also set bit 1 if bit 6 is - set). This bit is not set if WinZip's AES encryption is set. - - - - 7 - not used - - - - 8 - not used - - - - 9 - not used - - - - 10 - not used - - - - 11 - - Language encoding flag (EFS). If this bit is set, the filename and comment - fields for this file must be encoded using UTF-8. This library currently - does not support UTF-8. - - - - - 12 - Reserved by PKWARE for enhanced compression. - - - - 13 - - Used when encrypting the Central Directory to indicate selected data - values in the Local Header are masked to hide their actual values. See - the section in the Zip - specification describing the Strong Encryption Specification for - details. - - - - - 14 - Reserved by PKWARE. - - - - 15 - Reserved by PKWARE. - - - - - - - - - The compression method employed for this ZipEntry. - - - - - - The - Zip specification allows a variety of compression methods. This - library supports just two: 0x08 = Deflate. 0x00 = Store (no compression), - for reading or writing. - - - - When reading an entry from an existing zipfile, the value you retrieve - here indicates the compression method used on the entry by the original - creator of the zip. When writing a zipfile, you can specify either 0x08 - (Deflate) or 0x00 (None). If you try setting something else, you will get - an exception. - - - - You may wish to set CompressionMethod to CompressionMethod.None (0) - when zipping already-compressed data like a jpg, png, or mp3 file. - This can save time and cpu cycles. - - - - When setting this property on a ZipEntry that is read from an - existing zip file, calling ZipFile.Save() will cause the new - CompressionMethod to be used on the entry in the newly saved zip file. - - - - Setting this property may have the side effect of modifying the - CompressionLevel property. If you set the CompressionMethod to a - value other than None, and CompressionLevel is previously - set to None, then CompressionLevel will be set to - Default. - - - - - - - In this example, the first entry added to the zip archive uses the default - behavior - compression is used where it makes sense. The second entry, - the MP3 file, is added to the archive without being compressed. - - using (ZipFile zip = new ZipFile(ZipFileToCreate)) - { - ZipEntry e1= zip.AddFile(@"notes\Readme.txt"); - ZipEntry e2= zip.AddFile(@"music\StopThisTrain.mp3"); - e2.CompressionMethod = CompressionMethod.None; - zip.Save(); - } - - - - Using zip As New ZipFile(ZipFileToCreate) - zip.AddFile("notes\Readme.txt") - Dim e2 as ZipEntry = zip.AddFile("music\StopThisTrain.mp3") - e2.CompressionMethod = CompressionMethod.None - zip.Save - End Using - - - - - - Sets the compression level to be used for the entry when saving the zip - archive. This applies only for CompressionMethod = DEFLATE. - - - - - When using the DEFLATE compression method, Varying the compression - level used on entries can affect the size-vs-speed tradeoff when - compression and decompressing data streams or files. - - - - If you do not set this property, the default compression level is used, - which normally gives a good balance of compression efficiency and - compression speed. In some tests, using BestCompression can - double the time it takes to compress, while delivering just a small - increase in compression efficiency. This behavior will vary with the - type of data you compress. If you are in doubt, just leave this setting - alone, and accept the default. - - - - When setting this property on a ZipEntry that is read from an - existing zip file, calling ZipFile.Save() will cause the new - CompressionLevel to be used on the entry in the newly saved zip file. - - - - Setting this property may have the side effect of modifying the - CompressionMethod property. If you set the CompressionLevel - to a value other than None, CompressionMethod will be set - to Deflate, if it was previously None. - - - - Setting this property has no effect if the CompressionMethod is something - other than Deflate or None. - - - - - - - - The compressed size of the file, in bytes, within the zip archive. - - - - When reading a ZipFile, this value is read in from the existing - zip file. When creating or updating a ZipFile, the compressed - size is computed during compression. Therefore the value on a - ZipEntry is valid after a call to Save() (or one of its - overloads) in that case. - - - - - - - The size of the file, in bytes, before compression, or after extraction. - - - - When reading a ZipFile, this value is read in from the existing - zip file. When creating or updating a ZipFile, the uncompressed - size is computed during compression. Therefore the value on a - ZipEntry is valid after a call to Save() (or one of its - overloads) in that case. - - - - - - - The ratio of compressed size to uncompressed size of the ZipEntry. - - - - - This is a ratio of the compressed size to the uncompressed size of the - entry, expressed as a double in the range of 0 to 100+. A value of 100 - indicates no compression at all. It could be higher than 100 when the - compression algorithm actually inflates the data, as may occur for small - files, or uncompressible data that is encrypted. - - - - You could format it for presentation to a user via a format string of - "{3,5:F0}%" to see it as a percentage. - - - - If the size of the original uncompressed file is 0, implying a - denominator of 0, the return value will be zero. - - - - This property is valid after reading in an existing zip file, or after - saving the ZipFile that contains the ZipEntry. You cannot know the - effect of a compression transform until you try it. - - - - - - - The 32-bit CRC (Cyclic Redundancy Check) on the contents of the ZipEntry. - - - - - You probably don't need to concern yourself with this. It is used - internally by DotNetZip to verify files or streams upon extraction. - - The value is a 32-bit - CRC using 0xEDB88320 for the polynomial. This is the same CRC-32 used in - PNG, MPEG-2, and other protocols and formats. It is a read-only property; when - creating a Zip archive, the CRC for each entry is set only after a call to - Save() on the containing ZipFile. When reading an existing zip file, the value - of this property reflects the stored CRC for the entry. - - - - - - True if the entry is a directory (not a file). - This is a readonly property on the entry. - - - - - A derived property that is true if the entry uses encryption. - - - - - This is a readonly property on the entry. When reading a zip file, - the value for the ZipEntry is determined by the data read - from the zip file. After saving a ZipFile, the value of this - property for each ZipEntry indicates whether encryption was - actually used (which will have been true if the was set and the property - was something other than . - - - - - - Set this to specify which encryption algorithm to use for the entry when - saving it to a zip archive. - - - - - - Set this property in order to encrypt the entry when the ZipFile is - saved. When setting this property, you must also set a on the entry. If you set a value other than on this property and do not set a - Password then the entry will not be encrypted. The ZipEntry - data is encrypted as the ZipFile is saved, when you call or one of its cousins on the containing - ZipFile instance. You do not need to specify the Encryption - when extracting entries from an archive. - - - - The Zip specification from PKWare defines a set of encryption algorithms, - and the data formats for the zip archive that support them, and PKWare - supports those algorithms in the tools it produces. Other vendors of tools - and libraries, such as WinZip or Xceed, typically support a - subset of the algorithms specified by PKWare. These tools can - sometimes support additional different encryption algorithms and data - formats, not specified by PKWare. The AES Encryption specified and - supported by WinZip is the most popular example. This library supports a - subset of the complete set of algorithms specified by PKWare and other - vendors. - - - - There is no common, ubiquitous multi-vendor standard for strong encryption - within zip files. There is broad support for so-called "traditional" Zip - encryption, sometimes called Zip 2.0 encryption, as specified - by PKWare, but this encryption is considered weak and - breakable. This library currently supports the Zip 2.0 "weak" encryption, - and also a stronger WinZip-compatible AES encryption, using either 128-bit - or 256-bit key strength. If you want DotNetZip to support an algorithm - that is not currently supported, call the author of this library and maybe - we can talk business. - - - - The class also has a property. In most cases you will use - that property when setting encryption. This property takes - precedence over any Encryption set on the ZipFile itself. - Typically, you would use the per-entry Encryption when most entries in the - zip archive use one encryption algorithm, and a few entries use a - different one. If all entries in the zip file use the same Encryption, - then it is simpler to just set this property on the ZipFile itself, when - creating a zip archive. - - - - Some comments on updating archives: If you read a ZipFile, you can - modify the Encryption on an encrypted entry: you can remove encryption - from an entry that was encrypted; you can encrypt an entry that was not - encrypted previously; or, you can change the encryption algorithm. The - changes in encryption are not made permanent until you call Save() on the - ZipFile. To effect changes in encryption, the entry content is - streamed through several transformations, depending on the modification - the application has requested. For example if the entry is not encrypted - and the application sets Encryption to PkzipWeak, then at - the time of Save(), the original entry is read and decompressed, - then re-compressed and encrypted. Conversely, if the original entry is - encrypted with PkzipWeak encryption, and the application sets the - Encryption property to WinZipAes128, then at the time of - Save(), the original entry is decrypted via PKZIP encryption and - decompressed, then re-compressed and re-encrypted with AES. This all - happens automatically within the library, but it can be time-consuming for - large entries. - - - - Additionally, when updating archives, it is not possible to change the - password when changing the encryption algorithm. To change both the - algorithm and the password, you need to Save() the zipfile twice. First - set the Encryption to None, then call Save(). Then set the - Encryption to the new value (not "None"), then call Save() - once again. - - - - The WinZip AES encryption algorithms are not supported on the .NET Compact - Framework. - - - - - - This example creates a zip archive that uses encryption, and then extracts - entries from the archive. When creating the zip archive, the ReadMe.txt - file is zipped without using a password or encryption. The other file - uses encryption. - - - // Create a zip archive with AES Encryption. - using (ZipFile zip = new ZipFile()) - { - zip.AddFile("ReadMe.txt") - ZipEntry e1= zip.AddFile("2008-Regional-Sales-Report.pdf"); - e1.Encryption= EncryptionAlgorithm.WinZipAes256; - e1.Password= "Top.Secret.No.Peeking!"; - zip.Save("EncryptedArchive.zip"); - } - - // Extract a zip archive that uses AES Encryption. - // You do not need to specify the algorithm during extraction. - using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) - { - // Specify the password that is used during extraction, for - // all entries that require a password: - zip.Password= "Top.Secret.No.Peeking!"; - zip.ExtractAll("extractDirectory"); - } - - - - ' Create a zip that uses Encryption. - Using zip As New ZipFile() - zip.AddFile("ReadMe.txt") - Dim e1 as ZipEntry - e1= zip.AddFile("2008-Regional-Sales-Report.pdf") - e1.Encryption= EncryptionAlgorithm.WinZipAes256 - e1.Password= "Top.Secret.No.Peeking!" - zip.Save("EncryptedArchive.zip") - End Using - - ' Extract a zip archive that uses AES Encryption. - ' You do not need to specify the algorithm during extraction. - Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) - ' Specify the password that is used during extraction, for - ' all entries that require a password: - zip.Password= "Top.Secret.No.Peeking!" - zip.ExtractAll("extractDirectory") - End Using - - - - - - Thrown in the setter if EncryptionAlgorithm.Unsupported is specified. - - - ZipEntry.Password - ZipFile.Encryption - - - - The Password to be used when encrypting a ZipEntry upon - ZipFile.Save(), or when decrypting an entry upon Extract(). - - - - - This is a write-only property on the entry. Set this to request that the - entry be encrypted when writing the zip archive, or set it to specify the - password to be used when extracting an existing entry that is encrypted. - - - - The password set here is implicitly used to encrypt the entry during the - operation, or to decrypt during the or operation. If you set - the Password on a ZipEntry after calling Save(), there is no - effect. - - - - Consider setting the property when using a - password. Answering concerns that the standard password protection - supported by all zip tools is weak, WinZip has extended the ZIP - specification with a way to use AES Encryption to protect entries in the - Zip file. Unlike the "PKZIP 2.0" encryption specified in the PKZIP - specification, AES - Encryption uses a standard, strong, tested, encryption - algorithm. DotNetZip can create zip archives that use WinZip-compatible - AES encryption, if you set the property. But, - archives created that use AES encryption may not be readable by all other - tools and libraries. For example, Windows Explorer cannot read a - "compressed folder" (a zip file) that uses AES encryption, though it can - read a zip file that uses "PKZIP encryption." - - - - The class also has a - property. This property takes precedence over any password set on the - ZipFile itself. Typically, you would use the per-entry Password when most - entries in the zip archive use one password, and a few entries use a - different password. If all entries in the zip file use the same password, - then it is simpler to just set this property on the ZipFile itself, - whether creating a zip archive or extracting a zip archive. - - - - Some comments on updating archives: If you read a ZipFile, you - cannot modify the password on any encrypted entry, except by extracting - the entry with the original password (if any), removing the original entry - via , and then adding a new - entry with a new Password. - - - - For example, suppose you read a ZipFile, and there is an encrypted - entry. Setting the Password property on that ZipEntry and then - calling Save() on the ZipFile does not update the password - on that entry in the archive. Neither is an exception thrown. Instead, - what happens during the Save() is the existing entry is copied - through to the new zip archive, in its original encrypted form. Upon - re-reading that archive, the entry can be decrypted with its original - password. - - - - If you read a ZipFile, and there is an un-encrypted entry, you can set the - Password on the entry and then call Save() on the ZipFile, and get - encryption on that entry. - - - - - - - This example creates a zip file with two entries, and then extracts the - entries from the zip file. When creating the zip file, the two files are - added to the zip file using password protection. Each entry uses a - different password. During extraction, each file is extracted with the - appropriate password. - - - // create a file with encryption - using (ZipFile zip = new ZipFile()) - { - ZipEntry entry; - entry= zip.AddFile("Declaration.txt"); - entry.Password= "123456!"; - entry = zip.AddFile("Report.xls"); - entry.Password= "1Secret!"; - zip.Save("EncryptedArchive.zip"); - } - - // extract entries that use encryption - using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) - { - ZipEntry entry; - entry = zip["Declaration.txt"]; - entry.Password = "123456!"; - entry.Extract("extractDir"); - entry = zip["Report.xls"]; - entry.Password = "1Secret!"; - entry.Extract("extractDir"); - } - - - - - Using zip As New ZipFile - Dim entry as ZipEntry - entry= zip.AddFile("Declaration.txt") - entry.Password= "123456!" - entry = zip.AddFile("Report.xls") - entry.Password= "1Secret!" - zip.Save("EncryptedArchive.zip") - End Using - - - ' extract entries that use encryption - Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) - Dim entry as ZipEntry - entry = zip("Declaration.txt") - entry.Password = "123456!" - entry.Extract("extractDir") - entry = zip("Report.xls") - entry.Password = "1Secret!" - entry.Extract("extractDir") - End Using - - - - - - - ZipFile.Password - - - - The action the library should take when extracting a file that already exists. - - - - - This property affects the behavior of the Extract methods (one of the - Extract() or ExtractWithPassword() overloads), when - extraction would would overwrite an existing filesystem file. If you do - not set this property, the library throws an exception when extracting - an entry would overwrite an existing file. - - - - This property has no effect when extracting to a stream, or when the file to be - extracted does not already exist. - - - - - - - This example shows how to set the ExtractExistingFile property in - an ExtractProgress event, in response to user input. The - ExtractProgress event is invoked if and only if the - ExtractExistingFile property was previously set to - ExtractExistingFileAction.InvokeExtractProgressEvent. - - public static void ExtractProgress(object sender, ExtractProgressEventArgs e) - { - if (e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry) - Console.WriteLine("extract {0} ", e.CurrentEntry.FileName); - - else if (e.EventType == ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite) - { - ZipEntry entry = e.CurrentEntry; - string response = null; - // Ask the user if he wants overwrite the file - do - { - Console.Write("Overwrite {0} in {1} ? (y/n/C) ", entry.FileName, e.ExtractLocation); - response = Console.ReadLine(); - Console.WriteLine(); - - } while (response != null && response[0]!='Y' && - response[0]!='N' && response[0]!='C'); - - if (response[0]=='C') - e.Cancel = true; - else if (response[0]=='Y') - entry.ExtractExistingFile = ExtractExistingFileAction.OverwriteSilently; - else - entry.ExtractExistingFile= ExtractExistingFileAction.DoNotOverwrite; - } - } - - - - - - The action to take when an error is encountered while - opening or reading files as they are saved into a zip archive. - - - - - Errors can occur within a call to ZipFile.Save, as the various files contained - in a ZipFile are being saved into the zip archive. During the - Save, DotNetZip will perform a File.Open on the file - associated to the ZipEntry, and then will read the entire contents of - the file as it is zipped. Either the open or the Read may fail, because - of lock conflicts or other reasons. Using this property, you can - specify the action to take when such errors occur. - - - - Typically you will NOT set this property on individual ZipEntry - instances. Instead, you will set the ZipFile.ZipErrorAction property on - the ZipFile instance, before adding any entries to the - ZipFile. If you do this, errors encountered on behalf of any of - the entries in the ZipFile will be handled the same way. - - - - But, if you use a handler, you will want - to set this property on the ZipEntry within the handler, to - communicate back to DotNetZip what you would like to do with the - particular error. - - - - - - - - - Indicates whether the entry was included in the most recent save. - - - An entry can be excluded or skipped from a save if there is an error - opening or reading the entry. - - - - - - A callback that allows the application to specify the compression to use - for a given entry that is about to be added to the zip archive. - - - - - See - - - - - - Set to indicate whether to use UTF-8 encoding for filenames and comments. - - - - - - If this flag is set, the comment and filename for the entry will be - encoded with UTF-8, as described in the Zip - specification, if necessary. "Necessary" means, the filename or - entry comment (if any) cannot be reflexively encoded and decoded using the - default code page, IBM437. - - - - Setting this flag to true is equivalent to setting to System.Text.Encoding.UTF8. - - - - This flag has no effect or relation to the text encoding used within the - file itself. - - - - - - - The text encoding to use for the FileName and Comment on this ZipEntry, - when the default encoding is insufficient. - - - - - - Don't use this property. See . - - - - - - - Specifies the alternate text encoding used by this ZipEntry - - - - The default text encoding used in Zip files for encoding filenames and - comments is IBM437, which is something like a superset of ASCII. In - cases where this is insufficient, applications can specify an - alternate encoding. - - - When creating a zip file, the usage of the alternate encoding is - governed by the property. - Typically you would set both properties to tell DotNetZip to employ an - encoding that is not IBM437 in the zipfile you are creating. - - - Keep in mind that because the ZIP specification states that the only - valid encodings to use are IBM437 and UTF-8, if you use something - other than that, then zip tools and libraries may not be able to - successfully read the zip archive you generate. - - - The zip specification states that applications should presume that - IBM437 is in use, except when a special bit is set, which indicates - UTF-8. There is no way to specify an arbitrary code page, within the - zip file itself. When you create a zip file encoded with gb2312 or - ibm861 or anything other than IBM437 or UTF-8, then the application - that reads the zip file needs to "know" which code page to use. In - some cases, the code page used when reading is chosen implicitly. For - example, WinRar uses the ambient code page for the host desktop - operating system. The pitfall here is that if you create a zip in - Copenhagen and send it to Tokyo, the reader of the zipfile may not be - able to decode successfully. - - - - This example shows how to create a zipfile encoded with a - language-specific encoding: - - using (var zip = new ZipFile()) - { - zip.AlternateEnoding = System.Text.Encoding.GetEncoding("ibm861"); - zip.AlternateEnodingUsage = ZipOption.Always; - zip.AddFileS(arrayOfFiles); - zip.Save("Myarchive-Encoded-in-IBM861.zip"); - } - - - - - - - Describes if and when this instance should apply - AlternateEncoding to encode the FileName and Comment, when - saving. - - - - - - Indicates whether an entry is marked as a text file. Be careful when - using on this property. Unless you have a good reason, you should - probably ignore this property. - - - - - The ZIP format includes a provision for specifying whether an entry in - the zip archive is a text or binary file. This property exposes that - metadata item. Be careful when using this property: It's not clear - that this property as a firm meaning, across tools and libraries. - - - - To be clear, when reading a zip file, the property value may or may - not be set, and its value may or may not be valid. Not all entries - that you may think of as "text" entries will be so marked, and entries - marked as "text" are not guaranteed in any way to be text entries. - Whether the value is set and set correctly depends entirely on the - application that produced the zip file. - - - - There are many zip tools available, and when creating zip files, some - of them "respect" the IsText metadata field, and some of them do not. - Unfortunately, even when an application tries to do "the right thing", - it's not always clear what "the right thing" is. - - - - There's no firm definition of just what it means to be "a text file", - and the zip specification does not help in this regard. Twenty years - ago, text was ASCII, each byte was less than 127. IsText meant, all - bytes in the file were less than 127. These days, it is not the case - that all text files have all bytes less than 127. Any unicode file - may have bytes that are above 0x7f. The zip specification has nothing - to say on this topic. Therefore, it's not clear what IsText really - means. - - - - This property merely tells a reading application what is stored in the - metadata for an entry, without guaranteeing its validity or its - meaning. - - - - When DotNetZip is used to create a zipfile, it attempts to set this - field "correctly." For example, if a file ends in ".txt", this field - will be set. Your application may override that default setting. When - writing a zip file, you must set the property before calling - Save() on the ZipFile. - - - - When reading a zip file, a more general way to decide just what kind - of file is contained in a particular entry is to use the file type - database stored in the operating system. The operating system stores - a table that says, a file with .jpg extension is a JPG image file, a - file with a .xml extension is an XML document, a file with a .txt is a - pure ASCII text document, and so on. To get this information on - Windows, you - need to read and parse the registry. - - - - - using (var zip = new ZipFile()) - { - var e = zip.UpdateFile("Descriptions.mme", ""); - e.IsText = true; - zip.Save(zipPath); - } - - - - Using zip As New ZipFile - Dim e2 as ZipEntry = zip.AddFile("Descriptions.mme", "") - e.IsText= True - zip.Save(zipPath) - End Using - - - - - Provides a string representation of the instance. - a string representation of the instance. - - - - Extract the entry to the filesystem, starting at the current - working directory. - - - - This method has a bunch of overloads! One of them is sure to - be the right one for you... If you don't like these, check - out the ExtractWithPassword() methods. - - - - - - - - - This method extracts an entry from a zip file into the current - working directory. The path of the entry as extracted is the full - path as specified in the zip archive, relative to the current - working directory. After the file is extracted successfully, the - file attributes and timestamps are set. - - - - The action taken when extraction an entry would overwrite an - existing file is determined by the property. - - - - Within the call to Extract(), the content for the entry is - written into a filesystem file, and then the last modified time of the - file is set according to the property on - the entry. See the remarks the property for - some details about the last modified time. - - - - - - - Extract the entry to a file in the filesystem, using the specified - behavior when extraction would overwrite an existing file. - - - - - See the remarks on the property, for some - details about how the last modified time of the file is set after - extraction. - - - - - The action to take if extraction would overwrite an existing file. - - - - - Extracts the entry to the specified stream. - - - - - The caller can specify any write-able stream, for example a , a , or ASP.NET's - Response.OutputStream. The content will be decrypted and - decompressed as necessary. If the entry is encrypted and no password - is provided, this method will throw. - - - The position on the stream is not reset by this method before it extracts. - You may want to call stream.Seek() before calling ZipEntry.Extract(). - - - - - the stream to which the entry should be extracted. - - - - - - Extract the entry to the filesystem, starting at the specified base - directory. - - - the pathname of the base directory - - - - - - This example extracts only the entries in a zip file that are .txt files, - into a directory called "textfiles". - - using (ZipFile zip = ZipFile.Read("PackedDocuments.zip")) - { - foreach (string s1 in zip.EntryFilenames) - { - if (s1.EndsWith(".txt")) - { - zip[s1].Extract("textfiles"); - } - } - } - - - Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip") - Dim s1 As String - For Each s1 In zip.EntryFilenames - If s1.EndsWith(".txt") Then - zip(s1).Extract("textfiles") - End If - Next - End Using - - - - - - - Using this method, existing entries in the filesystem will not be - overwritten. If you would like to force the overwrite of existing - files, see the property, or call - . - - - - See the remarks on the property, for some - details about how the last modified time of the created file is set. - - - - - - Extract the entry to the filesystem, starting at the specified base - directory, and using the specified behavior when extraction would - overwrite an existing file. - - - - - See the remarks on the property, for some - details about how the last modified time of the created file is set. - - - - - - String sZipPath = "Airborne.zip"; - String sFilePath = "Readme.txt"; - String sRootFolder = "Digado"; - using (ZipFile zip = ZipFile.Read(sZipPath)) - { - if (zip.EntryFileNames.Contains(sFilePath)) - { - // use the string indexer on the zip file - zip[sFileName].Extract(sRootFolder, - ExtractExistingFileAction.OverwriteSilently); - } - } - - - - Dim sZipPath as String = "Airborne.zip" - Dim sFilePath As String = "Readme.txt" - Dim sRootFolder As String = "Digado" - Using zip As ZipFile = ZipFile.Read(sZipPath) - If zip.EntryFileNames.Contains(sFilePath) - ' use the string indexer on the zip file - zip(sFilePath).Extract(sRootFolder, _ - ExtractExistingFileAction.OverwriteSilently) - End If - End Using - - - - the pathname of the base directory - - The action to take if extraction would overwrite an existing file. - - - - - Extract the entry to the filesystem, using the current working directory - and the specified password. - - - - This method has a bunch of overloads! One of them is sure to be - the right one for you... - - - - - - - - - Existing entries in the filesystem will not be overwritten. If you - would like to force the overwrite of existing files, see the property, or call - . - - - - See the remarks on the property for some - details about how the "last modified" time of the created file is - set. - - - - - In this example, entries that use encryption are extracted using a - particular password. - - using (var zip = ZipFile.Read(FilePath)) - { - foreach (ZipEntry e in zip) - { - if (e.UsesEncryption) - e.ExtractWithPassword("Secret!"); - else - e.Extract(); - } - } - - - Using zip As ZipFile = ZipFile.Read(FilePath) - Dim e As ZipEntry - For Each e In zip - If (e.UsesEncryption) - e.ExtractWithPassword("Secret!") - Else - e.Extract - End If - Next - End Using - - - The Password to use for decrypting the entry. - - - - Extract the entry to the filesystem, starting at the specified base - directory, and using the specified password. - - - - - - - - Existing entries in the filesystem will not be overwritten. If you - would like to force the overwrite of existing files, see the property, or call - . - - - - See the remarks on the property, for some - details about how the last modified time of the created file is set. - - - - The pathname of the base directory. - The Password to use for decrypting the entry. - - - - Extract the entry to a file in the filesystem, relative to the - current directory, using the specified behavior when extraction - would overwrite an existing file. - - - - - See the remarks on the property, for some - details about how the last modified time of the created file is set. - - - - The Password to use for decrypting the entry. - - - The action to take if extraction would overwrite an existing file. - - - - - Extract the entry to the filesystem, starting at the specified base - directory, and using the specified behavior when extraction would - overwrite an existing file. - - - - See the remarks on the property, for some - details about how the last modified time of the created file is set. - - - the pathname of the base directory - - The action to take if extraction would - overwrite an existing file. - - The Password to use for decrypting the entry. - - - - Extracts the entry to the specified stream, using the specified - Password. For example, the caller could extract to Console.Out, or - to a MemoryStream. - - - - - The caller can specify any write-able stream, for example a , a , or ASP.NET's - Response.OutputStream. The content will be decrypted and - decompressed as necessary. If the entry is encrypted and no password - is provided, this method will throw. - - - The position on the stream is not reset by this method before it extracts. - You may want to call stream.Seek() before calling ZipEntry.Extract(). - - - - - - the stream to which the entry should be extracted. - - - The password to use for decrypting the entry. - - - - - Opens a readable stream corresponding to the zip entry in the - archive. The stream decompresses and decrypts as necessary, as it - is read. - - - - - - DotNetZip offers a variety of ways to extract entries from a zip - file. This method allows an application to extract an entry by - reading a . - - - - The return value is of type . Use it as you would any - stream for reading. When an application calls on that stream, it will - receive data from the zip entry that is decrypted and decompressed - as necessary. - - - - CrcCalculatorStream adds one additional feature: it keeps a - CRC32 checksum on the bytes of the stream as it is read. The CRC - value is available in the property on the - CrcCalculatorStream. When the read is complete, your - application - should check this CRC against the - property on the ZipEntry to validate the content of the - ZipEntry. You don't have to validate the entry using the CRC, but - you should, to verify integrity. Check the example for how to do - this. - - - - If the entry is protected with a password, then you need to provide - a password prior to calling , either by - setting the property on the entry, or the - property on the ZipFile - itself. Or, you can use , the - overload of OpenReader that accepts a password parameter. - - - - If you want to extract entry data into a write-able stream that is - already opened, like a , do not - use this method. Instead, use . - - - - Your application may use only one stream created by OpenReader() at - a time, and you should not call other Extract methods before - completing your reads on a stream obtained from OpenReader(). This - is because there is really only one source stream for the compressed - content. A call to OpenReader() seeks in the source stream, to the - beginning of the compressed content. A subsequent call to - OpenReader() on a different entry will seek to a different position - in the source stream, as will a call to Extract() or one of its - overloads. This will corrupt the state for the decompressing stream - from the original call to OpenReader(). - - - - The OpenReader() method works only when the ZipEntry is - obtained from an instance of ZipFile. This method will throw - an exception if the ZipEntry is obtained from a . - - - - - This example shows how to open a zip archive, then read in a named - entry via a stream. After the read loop is complete, the code - compares the calculated during the read loop with the expected CRC - on the ZipEntry, to verify the extraction. - - using (ZipFile zip = new ZipFile(ZipFileToRead)) - { - ZipEntry e1= zip["Elevation.mp3"]; - using (Ionic.Zlib.CrcCalculatorStream s = e1.OpenReader()) - { - byte[] buffer = new byte[4096]; - int n, totalBytesRead= 0; - do { - n = s.Read(buffer,0, buffer.Length); - totalBytesRead+=n; - } while (n>0); - if (s.Crc32 != e1.Crc32) - throw new Exception(string.Format("The Zip Entry failed the CRC Check. (0x{0:X8}!=0x{1:X8})", s.Crc32, e1.Crc32)); - if (totalBytesRead != e1.UncompressedSize) - throw new Exception(string.Format("We read an unexpected number of bytes. ({0}!={1})", totalBytesRead, e1.UncompressedSize)); - } - } - - - Using zip As New ZipFile(ZipFileToRead) - Dim e1 As ZipEntry = zip.Item("Elevation.mp3") - Using s As Ionic.Zlib.CrcCalculatorStream = e1.OpenReader - Dim n As Integer - Dim buffer As Byte() = New Byte(4096) {} - Dim totalBytesRead As Integer = 0 - Do - n = s.Read(buffer, 0, buffer.Length) - totalBytesRead = (totalBytesRead + n) - Loop While (n > 0) - If (s.Crc32 <> e1.Crc32) Then - Throw New Exception(String.Format("The Zip Entry failed the CRC Check. (0x{0:X8}!=0x{1:X8})", s.Crc32, e1.Crc32)) - End If - If (totalBytesRead <> e1.UncompressedSize) Then - Throw New Exception(String.Format("We read an unexpected number of bytes. ({0}!={1})", totalBytesRead, e1.UncompressedSize)) - End If - End Using - End Using - - - - The Stream for reading. - - - - Opens a readable stream for an encrypted zip entry in the archive. - The stream decompresses and decrypts as necessary, as it is read. - - - - - See the documentation on the method for - full details. This overload allows the application to specify a - password for the ZipEntry to be read. - - - - The password to use for decrypting the entry. - The Stream for reading. - - - - Pass in either basedir or s, but not both. - In other words, you can extract to a stream or to a directory (filesystem), but not both! - The Password param is required for encrypted entries. - - - - - Extract to a stream - In other words, you can extract to a stream or to a directory (filesystem), but not both! - The Password param is required for encrypted entries. - - - - - Validates that the args are consistent; returning whether the caller can return - because it's done, or not (caller should continue) - - - - - Validates that the args are consistent; returning whether the caller can return - because it's done, or not (caller should continue) - - - - - Reads one ZipEntry from the given stream. The content for - the entry does not get decompressed or decrypted. This method - basically reads metadata, and seeks. - - the ZipContainer this entry belongs to. - - true of this is the first entry being read from the stream. - - the ZipEntry read from the stream. - - - - Finds a particular segment in the given extra field. - This is used when modifying a previously-generated - extra field, in particular when removing the AES crypto - segment in the extra field. - - - - - At current cursor position in the stream, read the extra - field, and set the properties on the ZipEntry instance - appropriately. This can be called when processing the - Extra field in the Central Directory, or in the local - header. - - - - - generate and return a byte array that encodes the filename - for the entry. - - - - side effects: generate and store into _CommentBytes the - byte array for any comment attached to the entry. Also - sets _actualEncoding to indicate the actual encoding - used. The same encoding is used for both filename and - comment. - - - - - - Stores the position of the entry source stream, or, if the position is - already stored, seeks to that position. - - - - - This method is called in prep for reading the source stream. If PKZIP - encryption is used, then we need to calc the CRC32 before doing the - encryption, because the CRC is used in the 12th byte of the PKZIP - encryption header. So, we need to be able to seek backward in the source - when saving the ZipEntry. This method is called from the place that - calculates the CRC, and also from the method that does the encryption of - the file data. - - - - The first time through, this method sets the _sourceStreamOriginalPosition - field. Subsequent calls to this method seek to that position. - - - - - - Copy metadata that may have been changed by the app. We do this when - resetting the zipFile instance. If the app calls Save() on a ZipFile, then - tries to party on that file some more, we may need to Reset() it , which - means re-reading the entries and then copying the metadata. I think. - - - - - Set the input stream and get its length, if possible. The length is - used for progress updates, AND, to allow an optimization in case of - a stream/file of zero length. In that case we skip the Encrypt and - compression Stream. (like DeflateStream or BZip2OutputStream) - - - - - Prepare the given stream for output - wrap it in a CountingStream, and - then in a CRC stream, and an encryptor and deflator as appropriate. - - - - Previously this was used in ZipEntry.Write(), but in an effort to - introduce some efficiencies in that method I've refactored to put the - code inline. This method still gets called by ZipOutputStream. - - - - - - An enum that specifies the type of timestamp available on the ZipEntry. - - - - - - The last modified time of a file can be stored in multiple ways in - a zip file, and they are not mutually exclusive: - - - - - In the so-called "DOS" format, which has a 2-second precision. Values - are rounded to the nearest even second. For example, if the time on the - file is 12:34:43, then it will be stored as 12:34:44. This first value - is accessible via the LastModified property. This value is always - present in the metadata for each zip entry. In some cases the value is - invalid, or zero. - - - - In the so-called "Windows" or "NTFS" format, as an 8-byte integer - quantity expressed as the number of 1/10 milliseconds (in other words - the number of 100 nanosecond units) since January 1, 1601 (UTC). This - format is how Windows represents file times. This time is accessible - via the ModifiedTime property. - - - - In the "Unix" format, a 4-byte quantity specifying the number of seconds since - January 1, 1970 UTC. - - - - In an older format, now deprecated but still used by some current - tools. This format is also a 4-byte quantity specifying the number of - seconds since January 1, 1970 UTC. - - - - - - This bit field describes which of the formats were found in a ZipEntry that was read. - - - - - - - Default value. - - - - - A DOS timestamp with 2-second precision. - - - - - A Windows timestamp with 100-ns precision. - - - - - A Unix timestamp with 1-second precision. - - - - - A Unix timestamp with 1-second precision, stored in InfoZip v1 format. This - format is outdated and is supported for reading archives only. - - - - - The method of compression to use for a particular ZipEntry. - - - - PKWare's - ZIP Specification describes a number of distinct - cmopression methods that can be used within a zip - file. DotNetZip supports a subset of them. - - - - - No compression at all. For COM environments, the value is 0 (zero). - - - - - DEFLATE compression, as described in IETF RFC - 1951. This is the "normal" compression used in zip - files. For COM environments, the value is 8. - - - - - BZip2 compression, a compression algorithm developed by Julian Seward. - For COM environments, the value is 12. - - - - - An enum that specifies the source of the ZipEntry. - - - - - Default value. Invalid on a bonafide ZipEntry. - - - - - The entry was instantiated by calling AddFile() or another method that - added an entry from the filesystem. - - - - - The entry was instantiated via or - . - - - - - The ZipEntry was instantiated by reading a zipfile. - - - - - The content for the ZipEntry will be or was provided by the WriteDelegate. - - - - - The content for the ZipEntry will be obtained from the stream dispensed by the OpenDelegate. - The entry was instantiated via . - - - - - The content for the ZipEntry will be or was obtained from a ZipOutputStream. - - - - - An enum providing the options when an error occurs during opening or reading - of a file or directory that is being saved to a zip file. - - - - - This enum describes the actions that the library can take when an error occurs - opening or reading a file, as it is being saved into a Zip archive. - - - - In some cases an error will occur when DotNetZip tries to open a file to be - added to the zip archive. In other cases, an error might occur after the - file has been successfully opened, while DotNetZip is reading the file. - - - - The first problem might occur when calling AddDirectory() on a directory - that contains a Clipper .dbf file; the file is locked by Clipper and - cannot be opened by another process. An example of the second problem is - the ERROR_LOCK_VIOLATION that results when a file is opened by another - process, but not locked, and a range lock has been taken on the file. - Microsoft Outlook takes range locks on .PST files. - - - - - - Throw an exception when an error occurs while zipping. This is the default - behavior. (For COM clients, this is a 0 (zero).) - - - - - When an error occurs during zipping, for example a file cannot be opened, - skip the file causing the error, and continue zipping. (For COM clients, - this is a 1.) - - - - - When an error occurs during zipping, for example a file cannot be opened, - retry the operation that caused the error. Be careful with this option. If - the error is not temporary, the library will retry forever. (For COM - clients, this is a 2.) - - - - - When an error occurs, invoke the zipError event. The event type used is - . A typical use of this option: - a GUI application may wish to pop up a dialog to allow the user to view the - error that occurred, and choose an appropriate action. After your - processing in the error event, if you want to skip the file, set on the - ZipProgressEventArgs.CurrentEntry to Skip. If you want the - exception to be thrown, set ZipErrorAction on the CurrentEntry - to Throw. If you want to cancel the zip, set - ZipProgressEventArgs.Cancel to true. Cancelling differs from using - Skip in that a cancel will not save any further entries, if there are any. - (For COM clients, the value of this enum is a 3.) - - - - - Options for using ZIP64 extensions when saving zip archives. - - - - - - Designed many years ago, the original zip - specification from PKWARE allowed for 32-bit quantities for the - compressed and uncompressed sizes of zip entries, as well as a 32-bit quantity - for specifying the length of the zip archive itself, and a maximum of 65535 - entries. These limits are now regularly exceeded in many backup and archival - scenarios. Recently, PKWare added extensions to the original zip spec, called - "ZIP64 extensions", to raise those limitations. This property governs whether - DotNetZip will use those extensions when writing zip archives. The use of - these extensions is optional and explicit in DotNetZip because, despite the - status of ZIP64 as a bona fide standard, many other zip tools and libraries do - not support ZIP64, and therefore a zip file with ZIP64 extensions may be - unreadable by some of those other tools. - - - - Set this property to to always use ZIP64 - extensions when saving, regardless of whether your zip archive needs it. - Suppose you add 5 files, each under 100k, to a ZipFile. If you specify Always - for this flag, you will get a ZIP64 archive, though the archive does not need - to use ZIP64 because none of the original zip limits had been exceeded. - - - - Set this property to to tell the DotNetZip - library to never use ZIP64 extensions. This is useful for maximum - compatibility and interoperability, at the expense of the capability of - handling large files or large archives. NB: Windows Explorer in Windows XP - and Windows Vista cannot currently extract files from a zip64 archive, so if - you want to guarantee that a zip archive produced by this library will work in - Windows Explorer, use Never. If you set this property to , and your application creates a zip that would - exceed one of the Zip limits, the library will throw an exception while saving - the zip file. - - - - Set this property to to tell the - DotNetZip library to use the ZIP64 extensions when required by the - entry. After the file is compressed, the original and compressed sizes are - checked, and if they exceed the limits described above, then zip64 can be - used. That is the general idea, but there is an additional wrinkle when saving - to a non-seekable device, like the ASP.NET Response.OutputStream, or - Console.Out. When using non-seekable streams for output, the entry - header - which indicates whether zip64 is in use - is emitted before it is - known if zip64 is necessary. It is only after all entries have been saved - that it can be known if ZIP64 will be required. On seekable output streams, - after saving all entries, the library can seek backward and re-emit the zip - file header to be consistent with the actual ZIP64 requirement. But using a - non-seekable output stream, the library cannot seek backward, so the header - can never be changed. In other words, the archive's use of ZIP64 extensions is - not alterable after the header is emitted. Therefore, when saving to - non-seekable streams, using is the same - as using : it will always produce a zip - archive that uses ZIP64 extensions. - - - - - - - The default behavior, which is "Never". - (For COM clients, this is a 0 (zero).) - - - - - Do not use ZIP64 extensions when writing zip archives. - (For COM clients, this is a 0 (zero).) - - - - - Use ZIP64 extensions when writing zip archives, as necessary. - For example, when a single entry exceeds 0xFFFFFFFF in size, or when the archive as a whole - exceeds 0xFFFFFFFF in size, or when there are more than 65535 entries in an archive. - (For COM clients, this is a 1.) - - - - - Always use ZIP64 extensions when writing zip archives, even when unnecessary. - (For COM clients, this is a 2.) - - - - - An enum representing the values on a three-way toggle switch - for various options in the library. This might be used to - specify whether to employ a particular text encoding, or to use - ZIP64 extensions, or some other option. - - - - - The default behavior. This is the same as "Never". - (For COM clients, this is a 0 (zero).) - - - - - Never use the associated option. - (For COM clients, this is a 0 (zero).) - - - - - Use the associated behavior "as necessary." - (For COM clients, this is a 1.) - - - - - Use the associated behavior Always, whether necessary or not. - (For COM clients, this is a 2.) - - - - - A class for collecting the various options that can be used when - Reading zip files for extraction or update. - - - - - When reading a zip file, there are several options an - application can set, to modify how the file is read, or what - the library does while reading. This class collects those - options into one container. - - - - Pass an instance of the ReadOptions class into the - ZipFile.Read() method. - - - . - . - - - - - An event handler for Read operations. When opening large zip - archives, you may want to display a progress bar or other - indicator of status progress while reading. This parameter - allows you to specify a ReadProgress Event Handler directly. - When you call Read(), the progress event is invoked as - necessary. - - - - - The System.IO.TextWriter to use for writing verbose status messages - during operations on the zip archive. A console application may wish to - pass System.Console.Out to get messages on the Console. A graphical - or headless application may wish to capture the messages in a different - TextWriter, such as a System.IO.StringWriter. - - - - - The System.Text.Encoding to use when reading in the zip archive. Be - careful specifying the encoding. If the value you use here is not the same - as the Encoding used when the zip archive was created (possibly by a - different archiver) you will get unexpected results and possibly exceptions. - - - - - - - - Provides a stream metaphor for reading zip files. - - - - - This class provides an alternative programming model for reading zip files to - the one enabled by the class. Use this when reading zip - files, as an alternative to the class, when you would - like to use a Stream class to read the file. - - - - Some application designs require a readable stream for input. This stream can - be used to read a zip file, and extract entries. - - - - Both the ZipInputStream class and the ZipFile class can be used - to read and extract zip files. Both of them support many of the common zip - features, including Unicode, different compression levels, and ZIP64. The - programming models differ. For example, when extracting entries via calls to - the GetNextEntry() and Read() methods on the - ZipInputStream class, the caller is responsible for creating the file, - writing the bytes into the file, setting the attributes on the file, and - setting the created, last modified, and last accessed timestamps on the - file. All of these things are done automatically by a call to ZipEntry.Extract(). For this reason, the - ZipInputStream is generally recommended for when your application wants - to extract the data, without storing that data into a file. - - - - Aside from the obvious differences in programming model, there are some - differences in capability between the ZipFile class and the - ZipInputStream class. - - - - - ZipFile can be used to create or update zip files, or read and - extract zip files. ZipInputStream can be used only to read and - extract zip files. If you want to use a stream to create zip files, check - out the . - - - - ZipInputStream cannot read segmented or spanned - zip files. - - - - ZipInputStream will not read Zip file comments. - - - - When reading larger files, ZipInputStream will always underperform - ZipFile. This is because the ZipInputStream does a full scan on the - zip file, while the ZipFile class reads the central directory of the - zip file. - - - - - - - - - Create a ZipInputStream, wrapping it around an existing stream. - - - - - - While the class is generally easier - to use, this class provides an alternative to those - applications that want to read from a zipfile directly, - using a . - - - - Both the ZipInputStream class and the ZipFile class can be used - to read and extract zip files. Both of them support many of the common zip - features, including Unicode, different compression levels, and ZIP64. The - programming models differ. For example, when extracting entries via calls to - the GetNextEntry() and Read() methods on the - ZipInputStream class, the caller is responsible for creating the file, - writing the bytes into the file, setting the attributes on the file, and - setting the created, last modified, and last accessed timestamps on the - file. All of these things are done automatically by a call to ZipEntry.Extract(). For this reason, the - ZipInputStream is generally recommended for when your application wants - to extract the data, without storing that data into a file. - - - - Aside from the obvious differences in programming model, there are some - differences in capability between the ZipFile class and the - ZipInputStream class. - - - - - ZipFile can be used to create or update zip files, or read and extract - zip files. ZipInputStream can be used only to read and extract zip - files. If you want to use a stream to create zip files, check out the . - - - - ZipInputStream cannot read segmented or spanned - zip files. - - - - ZipInputStream will not read Zip file comments. - - - - When reading larger files, ZipInputStream will always underperform - ZipFile. This is because the ZipInputStream does a full scan on the - zip file, while the ZipFile class reads the central directory of the - zip file. - - - - - - - - The stream to read. It must be readable. This stream will be closed at - the time the ZipInputStream is closed. - - - - - This example shows how to read a zip file, and extract entries, using the - ZipInputStream class. - - - private void Unzip() - { - byte[] buffer= new byte[2048]; - int n; - using (var raw = File.Open(inputFileName, FileMode.Open, FileAccess.Read)) - { - using (var input= new ZipInputStream(raw)) - { - ZipEntry e; - while (( e = input.GetNextEntry()) != null) - { - if (e.IsDirectory) continue; - string outputPath = Path.Combine(extractDir, e.FileName); - using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) - { - while ((n= input.Read(buffer, 0, buffer.Length)) > 0) - { - output.Write(buffer,0,n); - } - } - } - } - } - } - - - - Private Sub UnZip() - Dim inputFileName As String = "MyArchive.zip" - Dim extractDir As String = "extract" - Dim buffer As Byte() = New Byte(2048) {} - Using raw As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read) - Using input As ZipInputStream = New ZipInputStream(raw) - Dim e As ZipEntry - Do While (Not e = input.GetNextEntry Is Nothing) - If Not e.IsDirectory Then - Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _ - FileMode.Create, FileAccess.ReadWrite) - Dim n As Integer - Do While (n = input.Read(buffer, 0, buffer.Length) > 0) - output.Write(buffer, 0, n) - Loop - End Using - End If - Loop - End Using - End Using - End Sub - - - - - - Create a ZipInputStream, given the name of an existing zip file. - - - - - - This constructor opens a FileStream for the given zipfile, and - wraps a ZipInputStream around that. See the documentation for the - constructor for full details. - - - - While the class is generally easier - to use, this class provides an alternative to those - applications that want to read from a zipfile directly, - using a . - - - - - - The name of the filesystem file to read. - - - - - This example shows how to read a zip file, and extract entries, using the - ZipInputStream class. - - - private void Unzip() - { - byte[] buffer= new byte[2048]; - int n; - using (var input= new ZipInputStream(inputFileName)) - { - ZipEntry e; - while (( e = input.GetNextEntry()) != null) - { - if (e.IsDirectory) continue; - string outputPath = Path.Combine(extractDir, e.FileName); - using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) - { - while ((n= input.Read(buffer, 0, buffer.Length)) > 0) - { - output.Write(buffer,0,n); - } - } - } - } - } - - - - Private Sub UnZip() - Dim inputFileName As String = "MyArchive.zip" - Dim extractDir As String = "extract" - Dim buffer As Byte() = New Byte(2048) {} - Using input As ZipInputStream = New ZipInputStream(inputFileName) - Dim e As ZipEntry - Do While (Not e = input.GetNextEntry Is Nothing) - If Not e.IsDirectory Then - Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _ - FileMode.Create, FileAccess.ReadWrite) - Dim n As Integer - Do While (n = input.Read(buffer, 0, buffer.Length) > 0) - output.Write(buffer, 0, n) - Loop - End Using - End If - Loop - End Using - End Sub - - - - - - Create a ZipInputStream, explicitly specifying whether to - keep the underlying stream open. - - - - See the documentation for the ZipInputStream(Stream) - constructor for a discussion of the class, and an example of how to use the class. - - - - The stream to read from. It must be readable. - - - - true if the application would like the stream - to remain open after the ZipInputStream has been closed. - - - - Provides a string representation of the instance. - - - This can be useful for debugging purposes. - - - a string representation of the instance. - - - - The text encoding to use when reading entries into the zip archive, for - those entries whose filenames or comments cannot be encoded with the - default (IBM437) encoding. - - - - - In its - zip specification, PKWare describes two options for encoding - filenames and comments: using IBM437 or UTF-8. But, some archiving tools - or libraries do not follow the specification, and instead encode - characters using the system default code page. For example, WinRAR when - run on a machine in Shanghai may encode filenames with the Big-5 Chinese - (950) code page. This behavior is contrary to the Zip specification, but - it occurs anyway. - - - - When using DotNetZip to read zip archives that use something other than - UTF-8 or IBM437, set this property to specify the code page to use when - reading encoded filenames and comments for each ZipEntry in the zip - file. - - - - This property is "provisional". When the entry in the zip archive is not - explicitly marked as using UTF-8, then IBM437 is used to decode filenames - and comments. If a loss of data would result from using IBM436 - - specifically when encoding and decoding is not reflexive - the codepage - specified here is used. It is possible, therefore, to have a given entry - with a Comment encoded in IBM437 and a FileName encoded with - the specified "provisional" codepage. - - - - When a zip file uses an arbitrary, non-UTF8 code page for encoding, there - is no standard way for the reader application - whether DotNetZip, WinZip, - WinRar, or something else - to know which codepage has been used for the - entries. Readers of zip files are not able to inspect the zip file and - determine the codepage that was used for the entries contained within it. - It is left to the application or user to determine the necessary codepage - when reading zip files encoded this way. If you use an incorrect codepage - when reading a zipfile, you will get entries with filenames that are - incorrect, and the incorrect filenames may even contain characters that - are not legal for use within filenames in Windows. Extracting entries with - illegal characters in the filenames will lead to exceptions. It's too bad, - but this is just the way things are with code pages in zip files. Caveat - Emptor. - - - - - - - Size of the work buffer to use for the ZLIB codec during decompression. - - - - Setting this affects the performance and memory efficiency of compression - and decompression. For larger files, setting this to a larger size may - improve performance, but the exact numbers vary depending on available - memory, and a bunch of other variables. I don't have good firm - recommendations on how to set it. You'll have to test it yourself. Or - just leave it alone and accept the default. - - - - - Sets the password to be used on the ZipInputStream instance. - - - - - - When reading a zip archive, this password is used to read and decrypt the - entries that are encrypted within the zip file. When entries within a zip - file use different passwords, set the appropriate password for the entry - before the first call to Read() for each entry. - - - - When reading an entry that is not encrypted, the value of this property is - ignored. - - - - - - - This example uses the ZipInputStream to read and extract entries from a - zip file, using a potentially different password for each entry. - - - byte[] buffer= new byte[2048]; - int n; - using (var raw = File.Open(_inputFileName, FileMode.Open, FileAccess.Read )) - { - using (var input= new ZipInputStream(raw)) - { - ZipEntry e; - while (( e = input.GetNextEntry()) != null) - { - input.Password = PasswordForEntry(e.FileName); - if (e.IsDirectory) continue; - string outputPath = Path.Combine(_extractDir, e.FileName); - using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) - { - while ((n= input.Read(buffer,0,buffer.Length)) > 0) - { - output.Write(buffer,0,n); - } - } - } - } - } - - - - - - - Read the data from the stream into the buffer. - - - - - The data for the zipentry will be decrypted and uncompressed, as - necessary, before being copied into the buffer. - - - - You must set the property before calling - Read() the first time for an encrypted entry. To determine if an - entry is encrypted and requires a password, check the ZipEntry.Encryption property. - - - - The buffer to hold the data read from the stream. - the offset within the buffer to copy the first byte read. - the number of bytes to read. - the number of bytes read, after decryption and decompression. - - - - Read the next entry from the zip file. - - - - - Call this method just before calling , - to position the pointer in the zip file to the next entry that can be - read. Subsequent calls to Read(), will decrypt and decompress the - data in the zip file, until Read() returns 0. - - - - Each time you call GetNextEntry(), the pointer in the wrapped - stream is moved to the next entry in the zip file. If you call , and thus re-position the pointer within - the file, you will need to call GetNextEntry() again, to insure - that the file pointer is positioned at the beginning of a zip entry. - - - - This method returns the ZipEntry. Using a stream approach, you will - read the raw bytes for an entry in a zip file via calls to Read(). - Alternatively, you can extract an entry into a file, or a stream, by - calling , or one of its siblings. - - - - - - The ZipEntry read. Returns null (or Nothing in VB) if there are no more - entries in the zip file. - - - - - - Dispose the stream. - - - - - This method disposes the ZipInputStream. It may also close the - underlying stream, depending on which constructor was used. - - - - Typically the application will call Dispose() implicitly, via - a using statement in C#, or a Using statement in VB. - - - - Application code won't call this code directly. This method may - be invoked in two distinct scenarios. If disposing == true, the - method has been called directly or indirectly by a user's code, - for example via the public Dispose() method. In this case, both - managed and unmanaged resources can be referenced and disposed. - If disposing == false, the method has been called by the runtime - from inside the object finalizer and this method should not - reference other objects; in that case only unmanaged resources - must be referenced or disposed. - - - - - true if the Dispose method was invoked by user code. - - - - - Always returns true. - - - - - Returns the value of CanSeek for the underlying (wrapped) stream. - - - - - Always returns false. - - - - - Returns the length of the underlying stream. - - - - - Gets or sets the position of the underlying stream. - - - Setting the position is equivalent to calling Seek(value, SeekOrigin.Begin). - - - - - This is a no-op. - - - - - This method always throws a NotSupportedException. - - ignored - ignored - ignored - - - - This method seeks in the underlying stream. - - - - - Call this method if you want to seek around within the zip file for random access. - - - - Applications can intermix calls to Seek() with calls to . After a call to Seek(), - GetNextEntry() will get the next ZipEntry that falls after - the current position in the input stream. You're on your own for finding - out just where to seek in the stream, to get to the various entries. - - - - - the offset point to seek to - the reference point from which to seek - The new position - - - - This method always throws a NotSupportedException. - - ignored - - - - Provides a stream metaphor for generating zip files. - - - - - This class writes zip files, as defined in the specification - for zip files described by PKWare. The compression for this - implementation is provided by a managed-code version of Zlib, included with - DotNetZip in the classes in the Ionic.Zlib namespace. - - - - This class provides an alternative programming model to the one enabled by the - class. Use this when creating zip files, as an - alternative to the class, when you would like to use a - Stream type to write the zip file. - - - - Both the ZipOutputStream class and the ZipFile class can be used - to create zip files. Both of them support many of the common zip features, - including Unicode, different compression levels, and ZIP64. They provide - very similar performance when creating zip files. - - - - The ZipFile class is generally easier to use than - ZipOutputStream and should be considered a higher-level interface. For - example, when creating a zip file via calls to the PutNextEntry() and - Write() methods on the ZipOutputStream class, the caller is - responsible for opening the file, reading the bytes from the file, writing - those bytes into the ZipOutputStream, setting the attributes on the - ZipEntry, and setting the created, last modified, and last accessed - timestamps on the zip entry. All of these things are done automatically by a - call to ZipFile.AddFile(). - For this reason, the ZipOutputStream is generally recommended for use - only when your application emits arbitrary data, not necessarily data from a - filesystem file, directly into a zip file, and does so using a Stream - metaphor. - - - - Aside from the differences in programming model, there are other - differences in capability between the two classes. - - - - - ZipFile can be used to read and extract zip files, in addition to - creating zip files. ZipOutputStream cannot read zip files. If you want - to use a stream to read zip files, check out the class. - - - - ZipOutputStream does not support the creation of segmented or spanned - zip files. - - - - ZipOutputStream cannot produce a self-extracting archive. - - - - - Be aware that the ZipOutputStream class implements the interface. In order for - ZipOutputStream to produce a valid zip file, you use use it within - a using clause (Using in VB), or call the Dispose() method - explicitly. See the examples for how to employ a using clause. - - - - Also, a note regarding compression performance: On the desktop .NET - Framework, DotNetZip can use a multi-threaded compression implementation - that provides significant speed increases on large files, over 300k or so, - at the cost of increased memory use at runtime. (The output of the - compression is almost exactly the same size). But, the multi-threaded - approach incurs a performance hit on smaller files. There's no way for the - ZipOutputStream to know whether parallel compression will be beneficial, - because the ZipOutputStream does not know how much data you will write - through the stream. You may wish to set the property to zero, if you are compressing - large files through ZipOutputStream. This will cause parallel - compression to be used, always. - - - - - - Create a ZipOutputStream, wrapping an existing stream. - - - - - The class is generally easier to use when creating - zip files. The ZipOutputStream offers a different metaphor for creating a - zip file, based on the class. - - - - - - The stream to wrap. It must be writable. This stream will be closed at - the time the ZipOutputStream is closed. - - - - - This example shows how to create a zip file, using the - ZipOutputStream class. - - - private void Zipup() - { - if (filesToZip.Count == 0) - { - System.Console.WriteLine("Nothing to do."); - return; - } - - using (var raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite )) - { - using (var output= new ZipOutputStream(raw)) - { - output.Password = "VerySecret!"; - output.Encryption = EncryptionAlgorithm.WinZipAes256; - - foreach (string inputFileName in filesToZip) - { - System.Console.WriteLine("file: {0}", inputFileName); - - output.PutNextEntry(inputFileName); - using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Write )) - { - byte[] buffer= new byte[2048]; - int n; - while ((n= input.Read(buffer,0,buffer.Length)) > 0) - { - output.Write(buffer,0,n); - } - } - } - } - } - } - - - - Private Sub Zipup() - Dim outputFileName As String = "XmlData.zip" - Dim filesToZip As String() = Directory.GetFiles(".", "*.xml") - If (filesToZip.Length = 0) Then - Console.WriteLine("Nothing to do.") - Else - Using raw As FileStream = File.Open(outputFileName, FileMode.Create, FileAccess.ReadWrite) - Using output As ZipOutputStream = New ZipOutputStream(raw) - output.Password = "VerySecret!" - output.Encryption = EncryptionAlgorithm.WinZipAes256 - Dim inputFileName As String - For Each inputFileName In filesToZip - Console.WriteLine("file: {0}", inputFileName) - output.PutNextEntry(inputFileName) - Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - Dim n As Integer - Dim buffer As Byte() = New Byte(2048) {} - Do While (n = input.Read(buffer, 0, buffer.Length) > 0) - output.Write(buffer, 0, n) - Loop - End Using - Next - End Using - End Using - End If - End Sub - - - - - - Create a ZipOutputStream that writes to a filesystem file. - - - - The class is generally easier to use when creating - zip files. The ZipOutputStream offers a different metaphor for creating a - zip file, based on the class. - - - - The name of the zip file to create. - - - - - This example shows how to create a zip file, using the - ZipOutputStream class. - - - private void Zipup() - { - if (filesToZip.Count == 0) - { - System.Console.WriteLine("Nothing to do."); - return; - } - - using (var output= new ZipOutputStream(outputFileName)) - { - output.Password = "VerySecret!"; - output.Encryption = EncryptionAlgorithm.WinZipAes256; - - foreach (string inputFileName in filesToZip) - { - System.Console.WriteLine("file: {0}", inputFileName); - - output.PutNextEntry(inputFileName); - using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, - FileShare.Read | FileShare.Write )) - { - byte[] buffer= new byte[2048]; - int n; - while ((n= input.Read(buffer,0,buffer.Length)) > 0) - { - output.Write(buffer,0,n); - } - } - } - } - } - - - - Private Sub Zipup() - Dim outputFileName As String = "XmlData.zip" - Dim filesToZip As String() = Directory.GetFiles(".", "*.xml") - If (filesToZip.Length = 0) Then - Console.WriteLine("Nothing to do.") - Else - Using output As ZipOutputStream = New ZipOutputStream(outputFileName) - output.Password = "VerySecret!" - output.Encryption = EncryptionAlgorithm.WinZipAes256 - Dim inputFileName As String - For Each inputFileName In filesToZip - Console.WriteLine("file: {0}", inputFileName) - output.PutNextEntry(inputFileName) - Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - Dim n As Integer - Dim buffer As Byte() = New Byte(2048) {} - Do While (n = input.Read(buffer, 0, buffer.Length) > 0) - output.Write(buffer, 0, n) - Loop - End Using - Next - End Using - End If - End Sub - - - - - - Create a ZipOutputStream. - - - - See the documentation for the ZipOutputStream(Stream) - constructor for an example. - - - - The stream to wrap. It must be writable. - - - - true if the application would like the stream - to remain open after the ZipOutputStream has been closed. - - - - Provides a string representation of the instance. - - - This can be useful for debugging purposes. - - - a string representation of the instance. - - - - Sets the password to be used on the ZipOutputStream instance. - - - - - - When writing a zip archive, this password is applied to the entries, not - to the zip archive itself. It applies to any ZipEntry subsequently - written to the ZipOutputStream. - - - - Using a password does not encrypt or protect the "directory" of the - archive - the list of entries contained in the archive. If you set the - Password property, the password actually applies to individual - entries that are added to the archive, subsequent to the setting of this - property. The list of filenames in the archive that is eventually created - will appear in clear text, but the contents of the individual files are - encrypted. This is how Zip encryption works. - - - - If you set this property, and then add a set of entries to the archive via - calls to PutNextEntry, then each entry is encrypted with that - password. You may also want to change the password between adding - different entries. If you set the password, add an entry, then set the - password to null (Nothing in VB), and add another entry, the - first entry is encrypted and the second is not. - - - - When setting the Password, you may also want to explicitly set the property, to specify how to encrypt the entries added - to the ZipFile. If you set the Password to a non-null value and do not - set , then PKZip 2.0 ("Weak") encryption is used. - This encryption is relatively weak but is very interoperable. If - you set the password to a null value (Nothing in VB), - Encryption is reset to None. - - - - Special case: if you wrap a ZipOutputStream around a non-seekable stream, - and use encryption, and emit an entry of zero bytes, the Close() or - PutNextEntry() following the entry will throw an exception. - - - - - - - The Encryption to use for entries added to the ZipOutputStream. - - - - - The specified Encryption is applied to the entries subsequently - written to the ZipOutputStream instance. - - - - If you set this to something other than - EncryptionAlgorithm.None, you will also need to set the - to a non-null, non-empty value in - order to actually get encryption on the entry. - - - - - ZipOutputStream.Password - ZipEntry.Encryption - - - - Size of the work buffer to use for the ZLIB codec during compression. - - - - Setting this may affect performance. For larger files, setting this to a - larger size may improve performance, but I'm not sure. Sorry, I don't - currently have good recommendations on how to set it. You can test it if - you like. - - - - - The compression strategy to use for all entries. - - - - Set the Strategy used by the ZLIB-compatible compressor, when compressing - data for the entries in the zip archive. Different compression strategies - work better on different sorts of data. The strategy parameter can affect - the compression ratio and the speed of compression but not the correctness - of the compresssion. For more information see . - - - - - The type of timestamp attached to the ZipEntry. - - - - Set this in order to specify the kind of timestamp that should be emitted - into the zip file for each entry. - - - - - Sets the compression level to be used for entries subsequently added to - the zip archive. - - - - - Varying the compression level used on entries can affect the - size-vs-speed tradeoff when compression and decompressing data streams - or files. - - - - As with some other properties on the ZipOutputStream class, like , and , - setting this property on a ZipOutputStream - instance will cause the specified CompressionLevel to be used on all - items that are subsequently added to the - ZipOutputStream instance. - - - - If you do not set this property, the default compression level is used, - which normally gives a good balance of compression efficiency and - compression speed. In some tests, using BestCompression can - double the time it takes to compress, while delivering just a small - increase in compression efficiency. This behavior will vary with the - type of data you compress. If you are in doubt, just leave this setting - alone, and accept the default. - - - - - - The compression method used on each entry added to the ZipOutputStream. - - - - - A comment attached to the zip archive. - - - - - - The application sets this property to specify a comment to be embedded - into the generated zip archive. - - - - According to PKWARE's - zip specification, the comment is not encrypted, even if there is a - password set on the zip file. - - - - The specification does not describe how to indicate the encoding used - on a comment string. Many "compliant" zip tools and libraries use - IBM437 as the code page for comments; DotNetZip, too, follows that - practice. On the other hand, there are situations where you want a - Comment to be encoded with something else, for example using code page - 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the - comment following the same procedure it follows for encoding - filenames: (a) if is - Never, it uses the default encoding (IBM437). (b) if is Always, it always uses the - alternate encoding (). (c) if is AsNecessary, it uses the - alternate encoding only if the default encoding is not sufficient for - encoding the comment - in other words if decoding the result does not - produce the original string. This decision is taken at the time of - the call to ZipFile.Save(). - - - - - - - Specify whether to use ZIP64 extensions when saving a zip archive. - - - - - The default value for the property is . is - safest, in the sense that you will not get an Exception if a - pre-ZIP64 limit is exceeded. - - - - You must set this property before calling Write(). - - - - - - - Indicates whether ZIP64 extensions were used when saving the zip archive. - - - - The value is defined only after the ZipOutputStream has been closed. - - - - - Whether the ZipOutputStream should use case-insensitive comparisons when - checking for uniqueness of zip entries. - - - - - Though the zip specification doesn't prohibit zipfiles with duplicate - entries, Sane zip files have no duplicates, and the DotNetZip library - cannot create zip files with duplicate entries. If an application attempts - to call with a name that duplicates one - already used within the archive, the library will throw an Exception. - - - This property allows the application to specify whether the - ZipOutputStream instance considers ordinal case when checking for - uniqueness of zip entries. - - - - - - Indicates whether to encode entry filenames and entry comments using - Unicode (UTF-8). - - - - - The - PKWare zip specification provides for encoding file names and file - comments in either the IBM437 code page, or in UTF-8. This flag selects - the encoding according to that specification. By default, this flag is - false, and filenames and comments are encoded into the zip file in the - IBM437 codepage. Setting this flag to true will specify that filenames - and comments that cannot be encoded with IBM437 will be encoded with - UTF-8. - - - - Zip files created with strict adherence to the PKWare specification with - respect to UTF-8 encoding can contain entries with filenames containing - any combination of Unicode characters, including the full range of - characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other - alphabets. However, because at this time, the UTF-8 portion of the PKWare - specification is not broadly supported by other zip libraries and - utilities, such zip files may not be readable by your favorite zip tool or - archiver. In other words, interoperability will decrease if you set this - flag to true. - - - - In particular, Zip files created with strict adherence to the PKWare - specification with respect to UTF-8 encoding will not work well with - Explorer in Windows XP or Windows Vista, because Windows compressed - folders, as far as I know, do not support UTF-8 in zip files. Vista can - read the zip files, but shows the filenames incorrectly. Unpacking from - Windows Vista Explorer will result in filenames that have rubbish - characters in place of the high-order UTF-8 bytes. - - - - Also, zip files that use UTF-8 encoding will not work well with Java - applications that use the java.util.zip classes, as of v5.0 of the Java - runtime. The Java runtime does not correctly implement the PKWare - specification in this regard. - - - - As a result, we have the unfortunate situation that "correct" behavior by - the DotNetZip library with regard to Unicode encoding of filenames during - zip creation will result in zip files that are readable by strictly - compliant and current tools (for example the most recent release of the - commercial WinZip tool); but these zip files will not be readable by - various other tools or libraries, including Windows Explorer. - - - - The DotNetZip library can read and write zip files with UTF8-encoded - entries, according to the PKware spec. If you use DotNetZip for both - creating and reading the zip file, and you use UTF-8, there will be no - loss of information in the filenames. For example, using a self-extractor - created by this library will allow you to unpack files correctly with no - loss of information in the filenames. - - - - If you do not set this flag, it will remain false. If this flag is false, - the ZipOutputStream will encode all filenames and comments using - the IBM437 codepage. This can cause "loss of information" on some - filenames, but the resulting zipfile will be more interoperable with other - utilities. As an example of the loss of information, diacritics can be - lost. The o-tilde character will be down-coded to plain o. The c with a - cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c. - Likewise, the O-stroke character (Unicode 248), used in Danish and - Norwegian, will be down-coded to plain o. Chinese characters cannot be - represented in codepage IBM437; when using the default encoding, Chinese - characters in filenames will be represented as ?. These are all examples - of "information loss". - - - - The loss of information associated to the use of the IBM437 encoding is - inconvenient, and can also lead to runtime errors. For example, using - IBM437, any sequence of 4 Chinese characters will be encoded as ????. If - your application creates a ZipOutputStream, does not set the - encoding, then adds two files, each with names of four Chinese characters - each, this will result in a duplicate filename exception. In the case - where you add a single file with a name containing four Chinese - characters, the zipfile will save properly, but extracting that file - later, with any zip tool, will result in an error, because the question - mark is not legal for use within filenames on Windows. These are just a - few examples of the problems associated to loss of information. - - - - This flag is independent of the encoding of the content within the entries - in the zip file. Think of the zip file as a container - it supports an - encoding. Within the container are other "containers" - the file entries - themselves. The encoding within those entries is independent of the - encoding of the zip archive container for those entries. - - - - Rather than specify the encoding in a binary fashion using this flag, an - application can specify an arbitrary encoding via the property. Setting the encoding - explicitly when creating zip archives will result in non-compliant zip - files that, curiously, are fairly interoperable. The challenge is, the - PKWare specification does not provide for a way to specify that an entry - in a zip archive uses a code page that is neither IBM437 nor UTF-8. - Therefore if you set the encoding explicitly when creating a zip archive, - you must take care upon reading the zip archive to use the same code page. - If you get it wrong, the behavior is undefined and may result in incorrect - filenames, exceptions, stomach upset, hair loss, and acne. - - - - - - - The text encoding to use when emitting entries into the zip archive, for - those entries whose filenames or comments cannot be encoded with the - default (IBM437) encoding. - - - - - In its - zip specification, PKWare describes two options for encoding - filenames and comments: using IBM437 or UTF-8. But, some archiving tools - or libraries do not follow the specification, and instead encode - characters using the system default code page. For example, WinRAR when - run on a machine in Shanghai may encode filenames with the Big-5 Chinese - (950) code page. This behavior is contrary to the Zip specification, but - it occurs anyway. - - - - When using DotNetZip to write zip archives that will be read by one of - these other archivers, set this property to specify the code page to use - when encoding the and for each ZipEntry in the zip file, for - values that cannot be encoded with the default codepage for zip files, - IBM437. This is why this property is "provisional". In all cases, IBM437 - is used where possible, in other words, where no loss of data would - result. It is possible, therefore, to have a given entry with a - Comment encoded in IBM437 and a FileName encoded with the - specified "provisional" codepage. - - - - Be aware that a zip file created after you've explicitly set the - ProvisionalAlternateEncoding property to a value other than - IBM437 may not be compliant to the PKWare specification, and may not be - readable by compliant archivers. On the other hand, many (most?) - archivers are non-compliant and can read zip files created in arbitrary - code pages. The trick is to use or specify the proper codepage when - reading the zip. - - - - When creating a zip archive using this library, it is possible to change - the value of ProvisionalAlternateEncoding between each entry you - add, and between adding entries and the call to Close(). Don't do - this. It will likely result in a zipfile that is not readable. For best - interoperability, either leave ProvisionalAlternateEncoding - alone, or specify it only once, before adding any entries to the - ZipOutputStream instance. There is one exception to this - recommendation, described later. - - - - When using an arbitrary, non-UTF8 code page for encoding, there is no - standard way for the creator application - whether DotNetZip, WinZip, - WinRar, or something else - to formally specify in the zip file which - codepage has been used for the entries. As a result, readers of zip files - are not able to inspect the zip file and determine the codepage that was - used for the entries contained within it. It is left to the application - or user to determine the necessary codepage when reading zip files encoded - this way. If you use an incorrect codepage when reading a zipfile, you - will get entries with filenames that are incorrect, and the incorrect - filenames may even contain characters that are not legal for use within - filenames in Windows. Extracting entries with illegal characters in the - filenames will lead to exceptions. It's too bad, but this is just the way - things are with code pages in zip files. Caveat Emptor. - - - - One possible approach for specifying the code page for a given zip file is - to describe the code page in a human-readable form in the Zip comment. For - example, the comment may read "Entries in this archive are encoded in the - Big5 code page". For maximum interoperability, the zip comment in this - case should be encoded in the default, IBM437 code page. In this case, - the zip comment is encoded using a different page than the filenames. To - do this, Specify ProvisionalAlternateEncoding to your desired - region-specific code page, once before adding any entries, and then set - the property and reset - ProvisionalAlternateEncoding to IBM437 before calling Close(). - - - - - - A Text Encoding to use when encoding the filenames and comments for - all the ZipEntry items, during a ZipFile.Save() operation. - - - - Whether the encoding specified here is used during the save depends - on . - - - - - - A flag that tells if and when this instance should apply - AlternateEncoding to encode the filenames and comments associated to - of ZipEntry objects contained within this instance. - - - - - The default text encoding used in zip archives. It is numeric 437, also - known as IBM437. - - - - - - The size threshold for an entry, above which a parallel deflate is used. - - - - - - DotNetZip will use multiple threads to compress any ZipEntry, when - the CompressionMethod is Deflate, and if the entry is - larger than the given size. Zero means "always use parallel - deflate", while -1 means "never use parallel deflate". - - - - If the entry size cannot be known before compression, as with any entry - added via a ZipOutputStream, then Parallel deflate will never be - performed, unless the value of this property is zero. - - - - A parallel deflate operations will speed up the compression of - large files, on computers with multiple CPUs or multiple CPU - cores. For files above 1mb, on a dual core or dual-cpu (2p) - machine, the time required to compress the file can be 70% of the - single-threaded deflate. For very large files on 4p machines the - compression can be done in 30% of the normal time. The downside - is that parallel deflate consumes extra memory during the deflate, - and the deflation is slightly less effective. - - - - Parallel deflate tends to not be as effective as single-threaded deflate - because the original data stream is split into multiple independent - buffers, each of which is compressed in parallel. But because they are - treated independently, there is no opportunity to share compression - dictionaries, and additional framing bytes must be added to the output - stream. For that reason, a deflated stream may be slightly larger when - compressed using parallel deflate, as compared to a traditional - single-threaded deflate. For files of about 512k, the increase over the - normal deflate is as much as 5% of the total compressed size. For larger - files, the difference can be as small as 0.1%. - - - - Multi-threaded compression does not give as much an advantage when using - Encryption. This is primarily because encryption tends to slow down - the entire pipeline. Also, multi-threaded compression gives less of an - advantage when using lower compression levels, for example . You may have to perform - some tests to determine the best approach for your situation. - - - - The default value for this property is -1, which means parallel - compression will not be performed unless you set it to zero. - - - - - - - The maximum number of buffer pairs to use when performing - parallel compression. - - - - - This property sets an upper limit on the number of memory - buffer pairs to create when performing parallel - compression. The implementation of the parallel - compression stream allocates multiple buffers to - facilitate parallel compression. As each buffer fills up, - the stream uses - ThreadPool.QueueUserWorkItem() to compress those - buffers in a background threadpool thread. After a buffer - is compressed, it is re-ordered and written to the output - stream. - - - - A higher number of buffer pairs enables a higher degree of - parallelism, which tends to increase the speed of compression on - multi-cpu computers. On the other hand, a higher number of buffer - pairs also implies a larger memory consumption, more active worker - threads, and a higher cpu utilization for any compression. This - property enables the application to limit its memory consumption and - CPU utilization behavior depending on requirements. - - - - For each compression "task" that occurs in parallel, there are 2 - buffers allocated: one for input and one for output. This property - sets a limit for the number of pairs. The total amount of storage - space allocated for buffering will then be (N*S*2), where N is the - number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer - pairs per CPU core, so if your machine has 4 cores, and you retain - the default buffer size of 128k, then the - ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer - memory in total, or 4mb, in blocks of 128kb. If you then set this - property to 8, then the number will be 8 * 2 * 128kb of buffer - memory, or 2mb. - - - - CPU utilization will also go up with additional buffers, because a - larger number of buffer pairs allows a larger number of background - threads to compress in parallel. If you find that parallel - compression is consuming too much memory or CPU, you can adjust this - value downward. - - - - The default value is 16. Different values may deliver better or - worse results, depending on your priorities and the dynamic - performance characteristics of your storage and compute resources. - - - - This property is not the number of buffer pairs to use; it is an - upper limit. An illustration: Suppose you have an application that - uses the default value of this property (which is 16), and it runs - on a machine with 2 CPU cores. In that case, DotNetZip will allocate - 4 buffer pairs per CPU core, for a total of 8 pairs. The upper - limit specified by this property has no effect. - - - - The application can set this value at any time, but it is - effective only if set before calling - ZipOutputStream.Write() for the first time. - - - - - - - - - Returns true if an entry by the given name has already been written - to the ZipOutputStream. - - - - The name of the entry to scan for. - - - - true if an entry by the given name has already been written. - - - - - Write the data from the buffer to the stream. - - - - As the application writes data into this stream, the data may be - compressed and encrypted before being written out to the underlying - stream, depending on the settings of the - and the properties. - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Specify the name of the next entry that will be written to the zip file. - - - - - Call this method just before calling , to - specify the name of the entry that the next set of bytes written to - the ZipOutputStream belongs to. All subsequent calls to Write, - until the next call to PutNextEntry, - will be inserted into the named entry in the zip file. - - - - If the used in PutNextEntry() ends in - a slash, then the entry added is marked as a directory. Because directory - entries do not contain data, a call to Write(), before an - intervening additional call to PutNextEntry(), will throw an - exception. - - - - If you don't call Write() between two calls to - PutNextEntry(), the first entry is inserted into the zip file as a - file of zero size. This may be what you want. - - - - Because PutNextEntry() closes out the prior entry, if any, this - method may throw if there is a problem with the prior entry. - - - - This method returns the ZipEntry. You can modify public properties - on the ZipEntry, such as , , and so on, until the first call to - ZipOutputStream.Write(), or until the next call to - PutNextEntry(). If you modify the ZipEntry after - having called Write(), you may get a runtime exception, or you may - silently get an invalid zip archive. - - - - - - - This example shows how to create a zip file, using the - ZipOutputStream class. - - - private void Zipup() - { - using (FileStream fs raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite )) - { - using (var output= new ZipOutputStream(fs)) - { - output.Password = "VerySecret!"; - output.Encryption = EncryptionAlgorithm.WinZipAes256; - output.PutNextEntry("entry1.txt"); - byte[] buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #1."); - output.Write(buffer,0,buffer.Length); - output.PutNextEntry("entry2.txt"); // this will be zero length - output.PutNextEntry("entry3.txt"); - buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #3."); - output.Write(buffer,0,buffer.Length); - } - } - } - - - - - The name of the entry to be added, including any path to be used - within the zip file. - - - - The ZipEntry created. - - - - - - Dispose the stream - - - - - This method writes the Zip Central directory, then closes the stream. The - application must call Dispose() (or Close) in order to produce a valid zip file. - - - - Typically the application will call Dispose() implicitly, via a using - statement in C#, or a Using statement in VB. - - - - - set this to true, always. - - - - Always returns false. - - - - - Always returns false. - - - - - Always returns true. - - - - - Always returns a NotSupportedException. - - - - - Setting this property always returns a NotSupportedException. Getting it - returns the value of the Position on the underlying stream. - - - - - This is a no-op. - - - - - This method always throws a NotSupportedException. - - ignored - ignored - ignored - nothing - - - - This method always throws a NotSupportedException. - - ignored - ignored - nothing - - - - This method always throws a NotSupportedException. - - ignored - - - - Sort-of like a factory method, ForUpdate is used only when - the application needs to update the zip entry metadata for - a segmented zip file, when the starting segment is earlier - than the ending segment, for a particular entry. - - - - The update is always contiguous, never rolls over. As a - result, this method doesn't need to return a ZSS; it can - simply return a FileStream. That's why it's "sort of" - like a Factory method. - - - Caller must Close/Dispose the stream object returned by - this method. - - - - - - Name of the filesystem file corresponding to the current segment. - - - - The name is not always the name currently being used in the - filesystem. When rwMode is RwMode.Write, the filesystem file has a - temporary name until the stream is closed or until the next segment is - started. - - - - - - Read from the stream - - the buffer to read - the offset at which to start - the number of bytes to read - the number of bytes actually read - - - - Write to the stream. - - the buffer from which to write - the offset at which to start writing - the number of bytes to write - - - - Enumerates the options for a logical conjunction. This enum is intended for use - internally by the FileSelector class. - - - - - FileSelector encapsulates logic that selects files from a source - a zip file - or the filesystem - based on a set of criteria. This class is used internally - by the DotNetZip library, in particular for the AddSelectedFiles() methods. - This class can also be used independently of the zip capability in DotNetZip. - - - - - - The FileSelector class is used internally by the ZipFile class for selecting - files for inclusion into the ZipFile, when the method, or one of - its overloads, is called. It's also used for the methods. Typically, an - application that creates or manipulates Zip archives will not directly - interact with the FileSelector class. - - - - Some applications may wish to use the FileSelector class directly, to - select files from disk volumes based on a set of criteria, without creating or - querying Zip archives. The file selection criteria include: a pattern to - match the filename; the last modified, created, or last accessed time of the - file; the size of the file; and the attributes of the file. - - - - Consult the documentation for - for more information on specifying the selection criteria. - - - - - - - Constructor that allows the caller to specify file selection criteria. - - - - - This constructor allows the caller to specify a set of criteria for - selection of files. - - - - See for a description of - the syntax of the selectionCriteria string. - - - - By default the FileSelector will traverse NTFS Reparse Points. To - change this, use FileSelector(String, bool). - - - - The criteria for file selection. - - - - Constructor that allows the caller to specify file selection criteria. - - - - - This constructor allows the caller to specify a set of criteria for - selection of files. - - - - See for a description of - the syntax of the selectionCriteria string. - - - - The criteria for file selection. - - whether to traverse NTFS reparse points (junctions). - - - - - The string specifying which files to include when retrieving. - - - - - Specify the criteria in statements of 3 elements: a noun, an operator, - and a value. Consider the string "name != *.doc" . The noun is - "name". The operator is "!=", implying "Not Equal". The value is - "*.doc". That criterion, in English, says "all files with a name that - does not end in the .doc extension." - - - - Supported nouns include "name" (or "filename") for the filename; - "atime", "mtime", and "ctime" for last access time, last modfied time, - and created time of the file, respectively; "attributes" (or "attrs") - for the file attributes; "size" (or "length") for the file length - (uncompressed); and "type" for the type of object, either a file or a - directory. The "attributes", "type", and "name" nouns all support = - and != as operators. The "size", "atime", "mtime", and "ctime" nouns - support = and !=, and >, >=, <, <= as well. The times are - taken to be expressed in local time. - - - - Specify values for the file attributes as a string with one or more of - the characters H,R,S,A,I,L in any order, implying file attributes of - Hidden, ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint - (symbolic link) respectively. - - - - To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as - the format. If you omit the HH:mm:ss portion, it is assumed to be - 00:00:00 (midnight). - - - - The value for a size criterion is expressed in integer quantities of - bytes, kilobytes (use k or kb after the number), megabytes (m or mb), - or gigabytes (g or gb). - - - - The value for a name is a pattern to match against the filename, - potentially including wildcards. The pattern follows CMD.exe glob - rules: * implies one or more of any character, while ? implies one - character. If the name pattern contains any slashes, it is matched to - the entire filename, including the path; otherwise, it is matched - against only the filename without the path. This means a pattern of - "*\*.*" matches all files one directory level deep, while a pattern of - "*.*" matches all files in all directories. - - - - To specify a name pattern that includes spaces, use single quotes - around the pattern. A pattern of "'* *.*'" will match all files that - have spaces in the filename. The full criteria string for that would - be "name = '* *.*'" . - - - - The value for a type criterion is either F (implying a file) or D - (implying a directory). - - - - Some examples: - - - - - criteria - Files retrieved - - - - name != *.xls - any file with an extension that is not .xls - - - - - name = *.mp3 - any file with a .mp3 extension. - - - - - *.mp3 - (same as above) any file with a .mp3 extension. - - - - - attributes = A - all files whose attributes include the Archive bit. - - - - - attributes != H - all files whose attributes do not include the Hidden bit. - - - - - mtime > 2009-01-01 - all files with a last modified time after January 1st, 2009. - - - - - ctime > 2009/01/01-03:00:00 - all files with a created time after 3am (local time), - on January 1st, 2009. - - - - - size > 2gb - all files whose uncompressed size is greater than 2gb. - - - - - type = D - all directories in the filesystem. - - - - - - You can combine criteria with the conjunctions AND, OR, and XOR. Using - a string like "name = *.txt AND size >= 100k" for the - selectionCriteria retrieves entries whose names end in .txt, and whose - uncompressed size is greater than or equal to 100 kilobytes. - - - - For more complex combinations of criteria, you can use parenthesis to - group clauses in the boolean logic. Absent parenthesis, the - precedence of the criterion atoms is determined by order of - appearance. Unlike the C# language, the AND conjunction does not take - precendence over the logical OR. This is important only in strings - that contain 3 or more criterion atoms. In other words, "name = *.txt - and size > 1000 or attributes = H" implies "((name = *.txt AND size - > 1000) OR attributes = H)" while "attributes = H OR name = *.txt - and size > 1000" evaluates to "((attributes = H OR name = *.txt) - AND size > 1000)". When in doubt, use parenthesis. - - - - Using time properties requires some extra care. If you want to - retrieve all entries that were last updated on 2009 February 14, - specify "mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this - to say: all files updated after 12:00am on February 14th, until - 12:00am on February 15th. You can use the same bracketing approach to - specify any time period - a year, a month, a week, and so on. - - - - The syntax allows one special case: if you provide a string with no - spaces, it is treated as a pattern to match for the filename. - Therefore a string like "*.xls" will be equivalent to specifying "name - = *.xls". This "shorthand" notation does not work with compound - criteria. - - - - There is no logic in this class that insures that the inclusion - criteria are internally consistent. For example, it's possible to - specify criteria that says the file must have a size of less than 100 - bytes, as well as a size that is greater than 1000 bytes. Obviously - no file will ever satisfy such criteria, but this class does not check - for or detect such inconsistencies. - - - - - - Thrown in the setter if the value has an invalid syntax. - - - - - Indicates whether searches will traverse NTFS reparse points, like Junctions. - - - - - Returns a string representation of the FileSelector object. - - The string representation of the boolean logic statement of the file - selection criteria for this instance. - - - - Returns the names of the files in the specified directory - that fit the selection criteria specified in the FileSelector. - - - - This is equivalent to calling - with recurseDirectories = false. - - - - The name of the directory over which to apply the FileSelector - criteria. - - - - A collection of strings containing fully-qualified pathnames of files - that match the criteria specified in the FileSelector instance. - - - - - Returns the names of the files in the specified directory that fit the - selection criteria specified in the FileSelector, optionally recursing - through subdirectories. - - - - This method applies the file selection criteria contained in the - FileSelector to the files contained in the given directory, and - returns the names of files that conform to the criteria. - - - - The name of the directory over which to apply the FileSelector - criteria. - - - - Whether to recurse through subdirectories when applying the file - selection criteria. - - - - A collection of strings containing fully-qualified pathnames of files - that match the criteria specified in the FileSelector instance. - - - - - Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria. - - - - - This method applies the criteria set in the FileSelector instance (as described in - the ) to the specified ZipFile. Using this - method, for example, you can retrieve all entries from the given ZipFile that - have filenames ending in .txt. - - - - Normally, applications would not call this method directly. This method is used - by the ZipFile class. - - - - Using the appropriate SelectionCriteria, you can retrieve entries based on size, - time, and attributes. See for a - description of the syntax of the SelectionCriteria string. - - - - - The ZipFile from which to retrieve entries. - - a collection of ZipEntry objects that conform to the criteria. - - - - Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria. - - - - - This method applies the criteria set in the FileSelector instance (as described in - the ) to the specified ZipFile. Using this - method, for example, you can retrieve all entries from the given ZipFile that - have filenames ending in .txt. - - - - Normally, applications would not call this method directly. This method is used - by the ZipFile class. - - - - This overload allows the selection of ZipEntry instances from the ZipFile to be restricted - to entries contained within a particular directory in the ZipFile. - - - - Using the appropriate SelectionCriteria, you can retrieve entries based on size, - time, and attributes. See for a - description of the syntax of the SelectionCriteria string. - - - - - The ZipFile from which to retrieve entries. - - - the directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - - a collection of ZipEntry objects that conform to the criteria. - - - - Summary description for EnumUtil. - - - - - Returns the value of the DescriptionAttribute if the specified Enum - value has one. If not, returns the ToString() representation of the - Enum value. - - The Enum to get the description for - - - - - Converts the string representation of the name or numeric value of one - or more enumerated constants to an equivalent enumerated object. - Note: use the DescriptionAttribute on enum values to enable this. - - The System.Type of the enumeration. - - A string containing the name or value to convert. - - - - - - Converts the string representation of the name or numeric value of one - or more enumerated constants to an equivalent enumerated object. A - parameter specified whether the operation is case-sensitive. Note: - use the DescriptionAttribute on enum values to enable this. - - The System.Type of the enumeration. - - A string containing the name or value to convert. - - - Whether the operation is case-sensitive or not. - - - - - Computes a CRC-32. The CRC-32 algorithm is parameterized - you - can set the polynomial and enable or disable bit - reversal. This can be used for GZIP, BZip2, or ZIP. - - - This type is used internally by DotNetZip; it is generally not used - directly by applications wishing to create, read, or manipulate zip - archive files. - - - - - Indicates the total number of bytes applied to the CRC. - - - - - Indicates the current CRC for all blocks slurped in. - - - - - Returns the CRC32 for the specified stream. - - The stream over which to calculate the CRC32 - the CRC32 calculation - - - - Returns the CRC32 for the specified stream, and writes the input into the - output stream. - - The stream over which to calculate the CRC32 - The stream into which to deflate the input - the CRC32 calculation - - - - Get the CRC32 for the given (word,byte) combo. This is a - computation defined by PKzip for PKZIP 2.0 (weak) encryption. - - The word to start with. - The byte to combine it with. - The CRC-ized result. - - - - Update the value for the running CRC32 using the given block of bytes. - This is useful when using the CRC32() class in a Stream. - - block of bytes to slurp - starting point in the block - how many bytes within the block to slurp - - - - Process one byte in the CRC. - - the byte to include into the CRC . - - - - Process a run of N identical bytes into the CRC. - - - - This method serves as an optimization for updating the CRC when a - run of identical bytes is found. Rather than passing in a buffer of - length n, containing all identical bytes b, this method accepts the - byte value and the length of the (virtual) buffer - the length of - the run. - - - the byte to include into the CRC. - the number of times that byte should be repeated. - - - - Combines the given CRC32 value with the current running total. - - - This is useful when using a divide-and-conquer approach to - calculating a CRC. Multiple threads can each calculate a - CRC32 on a segment of the data, and then combine the - individual CRC32 values at the end. - - the crc value to be combined with this one - the length of data the CRC value was calculated on - - - - Create an instance of the CRC32 class using the default settings: no - bit reversal, and a polynomial of 0xEDB88320. - - - - - Create an instance of the CRC32 class, specifying whether to reverse - data bits or not. - - - specify true if the instance should reverse data bits. - - - - In the CRC-32 used by BZip2, the bits are reversed. Therefore if you - want a CRC32 with compatibility with BZip2, you should pass true - here. In the CRC-32 used by GZIP and PKZIP, the bits are not - reversed; Therefore if you want a CRC32 with compatibility with - those, you should pass false. - - - - - - Create an instance of the CRC32 class, specifying the polynomial and - whether to reverse data bits or not. - - - The polynomial to use for the CRC, expressed in the reversed (LSB) - format: the highest ordered bit in the polynomial value is the - coefficient of the 0th power; the second-highest order bit is the - coefficient of the 1 power, and so on. Expressed this way, the - polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320. - - - specify true if the instance should reverse data bits. - - - - - In the CRC-32 used by BZip2, the bits are reversed. Therefore if you - want a CRC32 with compatibility with BZip2, you should pass true - here for the reverseBits parameter. In the CRC-32 used by - GZIP and PKZIP, the bits are not reversed; Therefore if you want a - CRC32 with compatibility with those, you should pass false for the - reverseBits parameter. - - - - - - Reset the CRC-32 class - clear the CRC "remainder register." - - - - Use this when employing a single instance of this class to compute - multiple, distinct CRCs on multiple, distinct data blocks. - - - - - - A Stream that calculates a CRC32 (a checksum) on all bytes read, - or on all bytes written. - - - - - This class can be used to verify the CRC of a ZipEntry when - reading from a stream, or to calculate a CRC when writing to a - stream. The stream should be used to either read, or write, but - not both. If you intermix reads and writes, the results are not - defined. - - - - This class is intended primarily for use internally by the - DotNetZip library. - - - - - - The default constructor. - - - - Instances returned from this constructor will leave the underlying - stream open upon Close(). The stream uses the default CRC32 - algorithm, which implies a polynomial of 0xEDB88320. - - - The underlying stream - - - - The constructor allows the caller to specify how to handle the - underlying stream at close. - - - - The stream uses the default CRC32 algorithm, which implies a - polynomial of 0xEDB88320. - - - The underlying stream - true to leave the underlying stream - open upon close of the CrcCalculatorStream; false otherwise. - - - - A constructor allowing the specification of the length of the stream - to read. - - - - The stream uses the default CRC32 algorithm, which implies a - polynomial of 0xEDB88320. - - - Instances returned from this constructor will leave the underlying - stream open upon Close(). - - - The underlying stream - The length of the stream to slurp - - - - A constructor allowing the specification of the length of the stream - to read, as well as whether to keep the underlying stream open upon - Close(). - - - - The stream uses the default CRC32 algorithm, which implies a - polynomial of 0xEDB88320. - - - The underlying stream - The length of the stream to slurp - true to leave the underlying stream - open upon close of the CrcCalculatorStream; false otherwise. - - - - A constructor allowing the specification of the length of the stream - to read, as well as whether to keep the underlying stream open upon - Close(), and the CRC32 instance to use. - - - - The stream uses the specified CRC32 instance, which allows the - application to specify how the CRC gets calculated. - - - The underlying stream - The length of the stream to slurp - true to leave the underlying stream - open upon close of the CrcCalculatorStream; false otherwise. - the CRC32 instance to use to calculate the CRC32 - - - - Gets the total number of bytes run through the CRC32 calculator. - - - - This is either the total number of bytes read, or the total number of - bytes written, depending on the direction of this stream. - - - - - Provides the current CRC for all blocks slurped in. - - - - The running total of the CRC is kept as data is written or read - through the stream. read this property after all reads or writes to - get an accurate CRC for the entire stream. - - - - - - Indicates whether the underlying stream will be left open when the - CrcCalculatorStream is Closed. - - - - Set this at any point before calling . - - - - - - Read from the stream - - the buffer to read - the offset at which to start - the number of bytes to read - the number of bytes actually read - - - - Write to the stream. - - the buffer from which to write - the offset at which to start writing - the number of bytes to write - - - - Indicates whether the stream supports reading. - - - - - Indicates whether the stream supports seeking. - - - - Always returns false. - - - - - - Indicates whether the stream supports writing. - - - - - Flush the stream. - - - - - Returns the length of the underlying stream. - - - - - The getter for this property returns the total bytes read. - If you use the setter, it will throw - . - - - - - Seeking is not supported on this stream. This method always throws - - - N/A - N/A - N/A - - - - This method always throws - - - N/A - - - - Closes the stream. - - - - - A class for compressing and decompressing streams using the Deflate algorithm. - - - - - - The DeflateStream is a Decorator on a . It adds DEFLATE compression or decompression to any - stream. - - - - Using this stream, applications can compress or decompress data via stream - Read and Write operations. Either compresssion or decompression - can occur through either reading or writing. The compression format used is - DEFLATE, which is documented in IETF RFC 1951, "DEFLATE - Compressed Data Format Specification version 1.3.". - - - - This class is similar to , except that - ZlibStream adds the RFC - 1950 - ZLIB framing bytes to a compressed stream when compressing, or - expects the RFC1950 framing bytes when decompressing. The DeflateStream - does not. - - - - - - - - - - Create a DeflateStream using the specified CompressionMode. - - - - When mode is CompressionMode.Compress, the DeflateStream will use - the default compression level. The "captive" stream will be closed when - the DeflateStream is closed. - - - - This example uses a DeflateStream to compress data from a file, and writes - the compressed data to another file. - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(fileToCompress + ".deflated")) - { - using (Stream compressor = new DeflateStream(raw, CompressionMode.Compress)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(fileToCompress & ".deflated") - Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - The stream which will be read or written. - Indicates whether the DeflateStream will compress or decompress. - - - - Create a DeflateStream using the specified CompressionMode and the specified CompressionLevel. - - - - - - When mode is CompressionMode.Decompress, the level parameter is - ignored. The "captive" stream will be closed when the DeflateStream is - closed. - - - - - - - This example uses a DeflateStream to compress data from a file, and writes - the compressed data to another file. - - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(fileToCompress + ".deflated")) - { - using (Stream compressor = new DeflateStream(raw, - CompressionMode.Compress, - CompressionLevel.BestCompression)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n= -1; - while (n != 0) - { - if (n > 0) - compressor.Write(buffer, 0, n); - n= input.Read(buffer, 0, buffer.Length); - } - } - } - } - - - - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(fileToCompress & ".deflated") - Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - The stream to be read or written while deflating or inflating. - Indicates whether the DeflateStream will compress or decompress. - A tuning knob to trade speed for effectiveness. - - - - Create a DeflateStream using the specified - CompressionMode, and explicitly specify whether the - stream should be left open after Deflation or Inflation. - - - - - - This constructor allows the application to request that the captive stream - remain open after the deflation or inflation occurs. By default, after - Close() is called on the stream, the captive stream is also - closed. In some cases this is not desired, for example if the stream is a - memory stream that will be re-read after compression. Specify true for - the parameter to leave the stream open. - - - - The DeflateStream will use the default compression level. - - - - See the other overloads of this constructor for example code. - - - - - The stream which will be read or written. This is called the - "captive" stream in other places in this documentation. - - - - Indicates whether the DeflateStream will compress or decompress. - - - true if the application would like the stream to - remain open after inflation/deflation. - - - - Create a DeflateStream using the specified CompressionMode - and the specified CompressionLevel, and explicitly specify whether - the stream should be left open after Deflation or Inflation. - - - - - - When mode is CompressionMode.Decompress, the level parameter is ignored. - - - - This constructor allows the application to request that the captive stream - remain open after the deflation or inflation occurs. By default, after - Close() is called on the stream, the captive stream is also - closed. In some cases this is not desired, for example if the stream is a - that will be re-read after - compression. Specify true for the parameter - to leave the stream open. - - - - - - - This example shows how to use a DeflateStream to compress data from - a file, and store the compressed data into another file. - - - using (var output = System.IO.File.Create(fileToCompress + ".deflated")) - { - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (Stream compressor = new DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n= -1; - while (n != 0) - { - if (n > 0) - compressor.Write(buffer, 0, n); - n= input.Read(buffer, 0, buffer.Length); - } - } - } - // can write additional data to the output stream here - } - - - - Using output As FileStream = File.Create(fileToCompress & ".deflated") - Using input As Stream = File.OpenRead(fileToCompress) - Using compressor As Stream = New DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - ' can write additional data to the output stream here. - End Using - - - The stream which will be read or written. - Indicates whether the DeflateStream will compress or decompress. - true if the application would like the stream to remain open after inflation/deflation. - A tuning knob to trade speed for effectiveness. - - - - This property sets the flush behavior on the stream. - - See the ZLIB documentation for the meaning of the flush behavior. - - - - - The size of the working buffer for the compression codec. - - - - - The working buffer is used for all stream operations. The default size is - 1024 bytes. The minimum size is 128 bytes. You may get better performance - with a larger buffer. Then again, you might not. You would have to test - it. - - - - Set this before the first call to Read() or Write() on the - stream. If you try to set it afterwards, it will throw. - - - - - - The ZLIB strategy to be used during compression. - - - - By tweaking this parameter, you may be able to optimize the compression for - data with particular characteristics. - - - - Returns the total number of bytes input so far. - - - Returns the total number of bytes output so far. - - - - Dispose the stream. - - - - This may or may not result in a Close() call on the captive - stream. See the constructors that have a leaveOpen parameter - for more information. - - - Application code won't call this code directly. This method may be - invoked in two distinct scenarios. If disposing == true, the method - has been called directly or indirectly by a user's code, for example - via the public Dispose() method. In this case, both managed and - unmanaged resources can be referenced and disposed. If disposing == - false, the method has been called by the runtime from inside the - object finalizer and this method should not reference other objects; - in that case only unmanaged resources must be referenced or - disposed. - - - - true if the Dispose method was invoked by user code. - - - - - Indicates whether the stream can be read. - - - The return value depends on whether the captive stream supports reading. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value depends on whether the captive stream supports writing. - - - - - Flush the stream. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the total bytes - written out, if used in writing, or the total bytes read in, if used in - reading. The count may refer to compressed bytes or uncompressed bytes, - depending on how you've used the stream. - - - - - Read data from the stream. - - - - - If you wish to use the DeflateStream to compress data while - reading, you can create a DeflateStream with - CompressionMode.Compress, providing an uncompressed data stream. - Then call Read() on that DeflateStream, and the data read will be - compressed as you read. If you wish to use the DeflateStream to - decompress data while reading, you can create a DeflateStream with - CompressionMode.Decompress, providing a readable compressed data - stream. Then call Read() on that DeflateStream, and the data read - will be decompressed as you read. - - - - A DeflateStream can be used for Read() or Write(), but not both. - - - - The buffer into which the read data should be placed. - the offset within that data array to put the first byte read. - the number of bytes to read. - the number of bytes actually read - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - this is irrelevant, since it will always throw! - irrelevant! - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - - - - Write data to the stream. - - - - - If you wish to use the DeflateStream to compress data while - writing, you can create a DeflateStream with - CompressionMode.Compress, and a writable output stream. Then call - Write() on that DeflateStream, providing uncompressed data - as input. The data sent to the output stream will be the compressed form - of the data written. If you wish to use the DeflateStream to - decompress data while writing, you can create a DeflateStream with - CompressionMode.Decompress, and a writable output stream. Then - call Write() on that stream, providing previously compressed - data. The data sent to the output stream will be the decompressed form of - the data written. - - - - A DeflateStream can be used for Read() or Write(), - but not both. - - - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Compress a string into a byte array using DEFLATE (RFC 1951). - - - - Uncompress it with . - - - DeflateStream.UncompressString(byte[]) - DeflateStream.CompressBuffer(byte[]) - GZipStream.CompressString(string) - ZlibStream.CompressString(string) - - - A string to compress. The string will first be encoded - using UTF8, then compressed. - - - The string in compressed form - - - - Compress a byte array into a new byte array using DEFLATE. - - - - Uncompress it with . - - - DeflateStream.CompressString(string) - DeflateStream.UncompressBuffer(byte[]) - GZipStream.CompressBuffer(byte[]) - ZlibStream.CompressBuffer(byte[]) - - - A buffer to compress. - - - The data in compressed form - - - - Uncompress a DEFLATE'd byte array into a single string. - - - DeflateStream.CompressString(String) - DeflateStream.UncompressBuffer(byte[]) - GZipStream.UncompressString(byte[]) - ZlibStream.UncompressString(byte[]) - - - A buffer containing DEFLATE-compressed data. - - - The uncompressed string - - - - Uncompress a DEFLATE'd byte array into a byte array. - - - DeflateStream.CompressBuffer(byte[]) - DeflateStream.UncompressString(byte[]) - GZipStream.UncompressBuffer(byte[]) - ZlibStream.UncompressBuffer(byte[]) - - - A buffer containing data that has been compressed with DEFLATE. - - - The data in uncompressed form - - - - A class for compressing and decompressing GZIP streams. - - - - - The GZipStream is a Decorator on a - . It adds GZIP compression or decompression to any - stream. - - - - Like the System.IO.Compression.GZipStream in the .NET Base Class Library, the - Ionic.Zlib.GZipStream can compress while writing, or decompress while - reading, but not vice versa. The compression method used is GZIP, which is - documented in IETF RFC - 1952, "GZIP file format specification version 4.3". - - - A GZipStream can be used to decompress data (through Read()) or - to compress data (through Write()), but not both. - - - - If you wish to use the GZipStream to compress data, you must wrap it - around a write-able stream. As you call Write() on the GZipStream, the - data will be compressed into the GZIP format. If you want to decompress data, - you must wrap the GZipStream around a readable stream that contains an - IETF RFC 1952-compliant stream. The data will be decompressed as you call - Read() on the GZipStream. - - - - Though the GZIP format allows data from multiple files to be concatenated - together, this stream handles only a single segment of GZIP format, typically - representing a single file. - - - - This class is similar to and . - ZlibStream handles RFC1950-compliant streams. - handles RFC1951-compliant streams. This class handles RFC1952-compliant streams. - - - - - - - - - - The comment on the GZIP stream. - - - - - The GZIP format allows for each file to optionally have an associated - comment stored with the file. The comment is encoded with the ISO-8859-1 - code page. To include a comment in a GZIP stream you create, set this - property before calling Write() for the first time on the - GZipStream. - - - - When using GZipStream to decompress, you can retrieve this property - after the first call to Read(). If no comment has been set in the - GZIP bytestream, the Comment property will return null - (Nothing in VB). - - - - - - The FileName for the GZIP stream. - - - - - - The GZIP format optionally allows each file to have an associated - filename. When compressing data (through Write()), set this - FileName before calling Write() the first time on the GZipStream. - The actual filename is encoded into the GZIP bytestream with the - ISO-8859-1 code page, according to RFC 1952. It is the application's - responsibility to insure that the FileName can be encoded and decoded - correctly with this code page. - - - - When decompressing (through Read()), you can retrieve this value - any time after the first Read(). In the case where there was no filename - encoded into the GZIP bytestream, the property will return null (Nothing - in VB). - - - - - - The last modified time for the GZIP stream. - - - - GZIP allows the storage of a last modified time with each GZIP entry. - When compressing data, you can set this before the first call to - Write(). When decompressing, you can retrieve this value any time - after the first call to Read(). - - - - - The CRC on the GZIP stream. - - - This is used for internal error checking. You probably don't need to look at this property. - - - - - Create a GZipStream using the specified CompressionMode. - - - - - When mode is CompressionMode.Compress, the GZipStream will use the - default compression level. - - - - As noted in the class documentation, the CompressionMode (Compress - or Decompress) also establishes the "direction" of the stream. A - GZipStream with CompressionMode.Compress works only through - Write(). A GZipStream with - CompressionMode.Decompress works only through Read(). - - - - - - This example shows how to use a GZipStream to compress data. - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(outputFile)) - { - using (Stream compressor = new GZipStream(raw, CompressionMode.Compress)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - Dim outputFile As String = (fileToCompress & ".compressed") - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(outputFile) - Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - - - This example shows how to use a GZipStream to uncompress a file. - - private void GunZipFile(string filename) - { - if (!filename.EndsWith(".gz)) - throw new ArgumentException("filename"); - var DecompressedFile = filename.Substring(0,filename.Length-3); - byte[] working = new byte[WORKING_BUFFER_SIZE]; - int n= 1; - using (System.IO.Stream input = System.IO.File.OpenRead(filename)) - { - using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) - { - using (var output = System.IO.File.Create(DecompressedFile)) - { - while (n !=0) - { - n= decompressor.Read(working, 0, working.Length); - if (n > 0) - { - output.Write(working, 0, n); - } - } - } - } - } - } - - - - Private Sub GunZipFile(ByVal filename as String) - If Not (filename.EndsWith(".gz)) Then - Throw New ArgumentException("filename") - End If - Dim DecompressedFile as String = filename.Substring(0,filename.Length-3) - Dim working(WORKING_BUFFER_SIZE) as Byte - Dim n As Integer = 1 - Using input As Stream = File.OpenRead(filename) - Using decompressor As Stream = new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, True) - Using output As Stream = File.Create(UncompressedFile) - Do - n= decompressor.Read(working, 0, working.Length) - If n > 0 Then - output.Write(working, 0, n) - End IF - Loop While (n > 0) - End Using - End Using - End Using - End Sub - - - - The stream which will be read or written. - Indicates whether the GZipStream will compress or decompress. - - - - Create a GZipStream using the specified CompressionMode and - the specified CompressionLevel. - - - - - The CompressionMode (Compress or Decompress) also establishes the - "direction" of the stream. A GZipStream with - CompressionMode.Compress works only through Write(). A - GZipStream with CompressionMode.Decompress works only - through Read(). - - - - - - - This example shows how to use a GZipStream to compress a file into a .gz file. - - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(fileToCompress + ".gz")) - { - using (Stream compressor = new GZipStream(raw, - CompressionMode.Compress, - CompressionLevel.BestCompression)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(fileToCompress & ".gz") - Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - The stream to be read or written while deflating or inflating. - Indicates whether the GZipStream will compress or decompress. - A tuning knob to trade speed for effectiveness. - - - - Create a GZipStream using the specified CompressionMode, and - explicitly specify whether the stream should be left open after Deflation - or Inflation. - - - - - This constructor allows the application to request that the captive stream - remain open after the deflation or inflation occurs. By default, after - Close() is called on the stream, the captive stream is also - closed. In some cases this is not desired, for example if the stream is a - memory stream that will be re-read after compressed data has been written - to it. Specify true for the parameter to leave - the stream open. - - - - The (Compress or Decompress) also - establishes the "direction" of the stream. A GZipStream with - CompressionMode.Compress works only through Write(). A GZipStream - with CompressionMode.Decompress works only through Read(). - - - - The GZipStream will use the default compression level. If you want - to specify the compression level, see . - - - - See the other overloads of this constructor for example code. - - - - - - The stream which will be read or written. This is called the "captive" - stream in other places in this documentation. - - - Indicates whether the GZipStream will compress or decompress. - - - - true if the application would like the base stream to remain open after - inflation/deflation. - - - - - Create a GZipStream using the specified CompressionMode and the - specified CompressionLevel, and explicitly specify whether the - stream should be left open after Deflation or Inflation. - - - - - - This constructor allows the application to request that the captive stream - remain open after the deflation or inflation occurs. By default, after - Close() is called on the stream, the captive stream is also - closed. In some cases this is not desired, for example if the stream is a - memory stream that will be re-read after compressed data has been written - to it. Specify true for the parameter to - leave the stream open. - - - - As noted in the class documentation, the CompressionMode (Compress - or Decompress) also establishes the "direction" of the stream. A - GZipStream with CompressionMode.Compress works only through - Write(). A GZipStream with CompressionMode.Decompress works only - through Read(). - - - - - - This example shows how to use a GZipStream to compress data. - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(outputFile)) - { - using (Stream compressor = new GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, true)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - Dim outputFile As String = (fileToCompress & ".compressed") - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(outputFile) - Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, True) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - The stream which will be read or written. - Indicates whether the GZipStream will compress or decompress. - true if the application would like the stream to remain open after inflation/deflation. - A tuning knob to trade speed for effectiveness. - - - - This property sets the flush behavior on the stream. - - - - - The size of the working buffer for the compression codec. - - - - - The working buffer is used for all stream operations. The default size is - 1024 bytes. The minimum size is 128 bytes. You may get better performance - with a larger buffer. Then again, you might not. You would have to test - it. - - - - Set this before the first call to Read() or Write() on the - stream. If you try to set it afterwards, it will throw. - - - - - Returns the total number of bytes input so far. - - - Returns the total number of bytes output so far. - - - - Dispose the stream. - - - - This may or may not result in a Close() call on the captive - stream. See the constructors that have a leaveOpen parameter - for more information. - - - This method may be invoked in two distinct scenarios. If disposing - == true, the method has been called directly or indirectly by a - user's code, for example via the public Dispose() method. In this - case, both managed and unmanaged resources can be referenced and - disposed. If disposing == false, the method has been called by the - runtime from inside the object finalizer and this method should not - reference other objects; in that case only unmanaged resources must - be referenced or disposed. - - - - indicates whether the Dispose method was invoked by user code. - - - - - Indicates whether the stream can be read. - - - The return value depends on whether the captive stream supports reading. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value depends on whether the captive stream supports writing. - - - - - Flush the stream. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the total bytes - written out, if used in writing, or the total bytes read in, if used in - reading. The count may refer to compressed bytes or uncompressed bytes, - depending on how you've used the stream. - - - - - Read and decompress data from the source stream. - - - - With a GZipStream, decompression is done through reading. - - - - - byte[] working = new byte[WORKING_BUFFER_SIZE]; - using (System.IO.Stream input = System.IO.File.OpenRead(_CompressedFile)) - { - using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) - { - using (var output = System.IO.File.Create(_DecompressedFile)) - { - int n; - while ((n= decompressor.Read(working, 0, working.Length)) !=0) - { - output.Write(working, 0, n); - } - } - } - } - - - The buffer into which the decompressed data should be placed. - the offset within that data array to put the first byte read. - the number of bytes to read. - the number of bytes actually read - - - - Calling this method always throws a . - - irrelevant; it will always throw! - irrelevant; it will always throw! - irrelevant! - - - - Calling this method always throws a . - - irrelevant; this method will always throw! - - - - Write data to the stream. - - - - - If you wish to use the GZipStream to compress data while writing, - you can create a GZipStream with CompressionMode.Compress, and a - writable output stream. Then call Write() on that GZipStream, - providing uncompressed data as input. The data sent to the output stream - will be the compressed form of the data written. - - - - A GZipStream can be used for Read() or Write(), but not - both. Writing implies compression. Reading implies decompression. - - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Compress a string into a byte array using GZip. - - - - Uncompress it with . - - - - - - - A string to compress. The string will first be encoded - using UTF8, then compressed. - - - The string in compressed form - - - - Compress a byte array into a new byte array using GZip. - - - - Uncompress it with . - - - - - - - A buffer to compress. - - - The data in compressed form - - - - Uncompress a GZip'ed byte array into a single string. - - - - - - - A buffer containing GZIP-compressed data. - - - The uncompressed string - - - - Uncompress a GZip'ed byte array into a byte array. - - - - - - - A buffer containing data that has been compressed with GZip. - - - The data in uncompressed form - - - - A class for compressing streams using the - Deflate algorithm with multiple threads. - - - - - This class performs DEFLATE compression through writing. For - more information on the Deflate algorithm, see IETF RFC 1951, - "DEFLATE Compressed Data Format Specification version 1.3." - - - - This class is similar to , except - that this class is for compression only, and this implementation uses an - approach that employs multiple worker threads to perform the DEFLATE. On - a multi-cpu or multi-core computer, the performance of this class can be - significantly higher than the single-threaded DeflateStream, particularly - for larger streams. How large? Anything over 10mb is a good candidate - for parallel compression. - - - - The tradeoff is that this class uses more memory and more CPU than the - vanilla DeflateStream, and also is less efficient as a compressor. For - large files the size of the compressed data stream can be less than 1% - larger than the size of a compressed data stream from the vanialla - DeflateStream. For smaller files the difference can be larger. The - difference will also be larger if you set the BufferSize to be lower than - the default value. Your mileage may vary. Finally, for small files, the - ParallelDeflateOutputStream can be much slower than the vanilla - DeflateStream, because of the overhead associated to using the thread - pool. - - - - - - - - Create a ParallelDeflateOutputStream. - - - - - This stream compresses data written into it via the DEFLATE - algorithm (see RFC 1951), and writes out the compressed byte stream. - - - - The instance will use the default compression level, the default - buffer sizes and the default number of threads and buffers per - thread. - - - - This class is similar to , - except that this implementation uses an approach that employs - multiple worker threads to perform the DEFLATE. On a multi-cpu or - multi-core computer, the performance of this class can be - significantly higher than the single-threaded DeflateStream, - particularly for larger streams. How large? Anything over 10mb is - a good candidate for parallel compression. - - - - - - - This example shows how to use a ParallelDeflateOutputStream to compress - data. It reads a file, compresses it, and writes the compressed data to - a second, output file. - - - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n= -1; - String outputFile = fileToCompress + ".compressed"; - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(outputFile)) - { - using (Stream compressor = new ParallelDeflateOutputStream(raw)) - { - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Dim outputFile As String = (fileToCompress & ".compressed") - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(outputFile) - Using compressor As Stream = New ParallelDeflateOutputStream(raw) - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - The stream to which compressed data will be written. - - - - Create a ParallelDeflateOutputStream using the specified CompressionLevel. - - - See the - constructor for example code. - - The stream to which compressed data will be written. - A tuning knob to trade speed for effectiveness. - - - - Create a ParallelDeflateOutputStream and specify whether to leave the captive stream open - when the ParallelDeflateOutputStream is closed. - - - See the - constructor for example code. - - The stream to which compressed data will be written. - - true if the application would like the stream to remain open after inflation/deflation. - - - - - Create a ParallelDeflateOutputStream and specify whether to leave the captive stream open - when the ParallelDeflateOutputStream is closed. - - - See the - constructor for example code. - - The stream to which compressed data will be written. - A tuning knob to trade speed for effectiveness. - - true if the application would like the stream to remain open after inflation/deflation. - - - - - Create a ParallelDeflateOutputStream using the specified - CompressionLevel and CompressionStrategy, and specifying whether to - leave the captive stream open when the ParallelDeflateOutputStream is - closed. - - - See the - constructor for example code. - - The stream to which compressed data will be written. - A tuning knob to trade speed for effectiveness. - - By tweaking this parameter, you may be able to optimize the compression for - data with particular characteristics. - - - true if the application would like the stream to remain open after inflation/deflation. - - - - - The ZLIB strategy to be used during compression. - - - - - - The maximum number of buffer pairs to use. - - - - - This property sets an upper limit on the number of memory buffer - pairs to create. The implementation of this stream allocates - multiple buffers to facilitate parallel compression. As each buffer - fills up, this stream uses - ThreadPool.QueueUserWorkItem() - to compress those buffers in a background threadpool thread. After a - buffer is compressed, it is re-ordered and written to the output - stream. - - - - A higher number of buffer pairs enables a higher degree of - parallelism, which tends to increase the speed of compression on - multi-cpu computers. On the other hand, a higher number of buffer - pairs also implies a larger memory consumption, more active worker - threads, and a higher cpu utilization for any compression. This - property enables the application to limit its memory consumption and - CPU utilization behavior depending on requirements. - - - - For each compression "task" that occurs in parallel, there are 2 - buffers allocated: one for input and one for output. This property - sets a limit for the number of pairs. The total amount of storage - space allocated for buffering will then be (N*S*2), where N is the - number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer - pairs per CPU core, so if your machine has 4 cores, and you retain - the default buffer size of 128k, then the - ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer - memory in total, or 4mb, in blocks of 128kb. If you then set this - property to 8, then the number will be 8 * 2 * 128kb of buffer - memory, or 2mb. - - - - CPU utilization will also go up with additional buffers, because a - larger number of buffer pairs allows a larger number of background - threads to compress in parallel. If you find that parallel - compression is consuming too much memory or CPU, you can adjust this - value downward. - - - - The default value is 16. Different values may deliver better or - worse results, depending on your priorities and the dynamic - performance characteristics of your storage and compute resources. - - - - This property is not the number of buffer pairs to use; it is an - upper limit. An illustration: Suppose you have an application that - uses the default value of this property (which is 16), and it runs - on a machine with 2 CPU cores. In that case, DotNetZip will allocate - 4 buffer pairs per CPU core, for a total of 8 pairs. The upper - limit specified by this property has no effect. - - - - The application can set this value at any time, but it is effective - only before the first call to Write(), which is when the buffers are - allocated. - - - - - - The size of the buffers used by the compressor threads. - - - - - The default buffer size is 128k. The application can set this value - at any time, but it is effective only before the first Write(). - - - - Larger buffer sizes implies larger memory consumption but allows - more efficient compression. Using smaller buffer sizes consumes less - memory but may result in less effective compression. For example, - using the default buffer size of 128k, the compression delivered is - within 1% of the compression delivered by the single-threaded . On the other hand, using a - BufferSize of 8k can result in a compressed data stream that is 5% - larger than that delivered by the single-threaded - DeflateStream. Excessively small buffer sizes can also cause - the speed of the ParallelDeflateOutputStream to drop, because of - larger thread scheduling overhead dealing with many many small - buffers. - - - - The total amount of storage space allocated for buffering will be - (N*S*2), where N is the number of buffer pairs, and S is the size of - each buffer (this property). There are 2 buffers used by the - compressor, one for input and one for output. By default, DotNetZip - allocates 4 buffer pairs per CPU core, so if your machine has 4 - cores, then the number of buffer pairs used will be 16. If you - accept the default value of this property, 128k, then the - ParallelDeflateOutputStream will use 16 * 2 * 128kb of buffer memory - in total, or 4mb, in blocks of 128kb. If you set this property to - 64kb, then the number will be 16 * 2 * 64kb of buffer memory, or - 2mb. - - - - - - - The CRC32 for the data that was written out, prior to compression. - - - This value is meaningful only after a call to Close(). - - - - - The total number of uncompressed bytes processed by the ParallelDeflateOutputStream. - - - This value is meaningful only after a call to Close(). - - - - - Write data to the stream. - - - - - - To use the ParallelDeflateOutputStream to compress data, create a - ParallelDeflateOutputStream with CompressionMode.Compress, passing a - writable output stream. Then call Write() on that - ParallelDeflateOutputStream, providing uncompressed data as input. The - data sent to the output stream will be the compressed form of the data - written. - - - - To decompress data, use the class. - - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Flush the stream. - - - - - Close the stream. - - - You must call Close on the stream to guarantee that all of the data written in has - been compressed, and the compressed data has been written out. - - - - Dispose the object - - - Because ParallelDeflateOutputStream is IDisposable, the - application must call this method when finished using the instance. - - - This method is generally called implicitly upon exit from - a using scope in C# (Using in VB). - - - - - The Dispose method - - indicates whether the Dispose method was invoked by user code. - - - - - Resets the stream for use with another stream. - - - Because the ParallelDeflateOutputStream is expensive to create, it - has been designed so that it can be recycled and re-used. You have - to call Close() on the stream first, then you can call Reset() on - it, to use it again on another stream. - - - - The new output stream for this era. - - - - - ParallelDeflateOutputStream deflater = null; - foreach (var inputFile in listOfFiles) - { - string outputFile = inputFile + ".compressed"; - using (System.IO.Stream input = System.IO.File.OpenRead(inputFile)) - { - using (var outStream = System.IO.File.Create(outputFile)) - { - if (deflater == null) - deflater = new ParallelDeflateOutputStream(outStream, - CompressionLevel.Best, - CompressionStrategy.Default, - true); - deflater.Reset(outStream); - - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - deflater.Write(buffer, 0, n); - } - } - } - } - - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream supports Read operations. - - - Always returns false. - - - - - Indicates whether the stream supports Write operations. - - - Returns true if the provided stream is writable. - - - - - Reading this property always throws a NotSupportedException. - - - - - Returns the current position of the output stream. - - - - Because the output gets written by a background thread, - the value may change asynchronously. Setting this - property always throws a NotSupportedException. - - - - - - This method always throws a NotSupportedException. - - - The buffer into which data would be read, IF THIS METHOD - ACTUALLY DID ANYTHING. - - - The offset within that data array at which to insert the - data that is read, IF THIS METHOD ACTUALLY DID - ANYTHING. - - - The number of bytes to write, IF THIS METHOD ACTUALLY DID - ANYTHING. - - nothing. - - - - This method always throws a NotSupportedException. - - - The offset to seek to.... - IF THIS METHOD ACTUALLY DID ANYTHING. - - - The reference specifying how to apply the offset.... IF - THIS METHOD ACTUALLY DID ANYTHING. - - nothing. It always throws. - - - - This method always throws a NotSupportedException. - - - The new value for the stream length.... IF - THIS METHOD ACTUALLY DID ANYTHING. - - - - - Map from a distance to a distance code. - - - No side effects. _dist_code[256] and _dist_code[257] are never used. - - - - - Describes how to flush the current deflate operation. - - - The different FlushType values are useful when using a Deflate in a streaming application. - - - - No flush at all. - - - Closes the current block, but doesn't flush it to - the output. Used internally only in hypothetical - scenarios. This was supposed to be removed by Zlib, but it is - still in use in some edge cases. - - - - - Use this during compression to specify that all pending output should be - flushed to the output buffer and the output should be aligned on a byte - boundary. You might use this in a streaming communication scenario, so that - the decompressor can get all input data available so far. When using this - with a ZlibCodec, AvailableBytesIn will be zero after the call if - enough output space has been provided before the call. Flushing will - degrade compression and so it should be used only when necessary. - - - - - Use this during compression to specify that all output should be flushed, as - with FlushType.Sync, but also, the compression state should be reset - so that decompression can restart from this point if previous compressed - data has been damaged or if random access is desired. Using - FlushType.Full too often can significantly degrade the compression. - - - - Signals the end of the compression/decompression stream. - - - - The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress. - - - - - None means that the data will be simply stored, with no change at all. - If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None - cannot be opened with the default zip reader. Use a different CompressionLevel. - - - - - Same as None. - - - - - The fastest but least effective compression. - - - - - A synonym for BestSpeed. - - - - - A little slower, but better, than level 1. - - - - - A little slower, but better, than level 2. - - - - - A little slower, but better, than level 3. - - - - - A little slower than level 4, but with better compression. - - - - - The default compression level, with a good balance of speed and compression efficiency. - - - - - A synonym for Default. - - - - - Pretty good compression! - - - - - Better compression than Level7! - - - - - The "best" compression, where best means greatest reduction in size of the input data stream. - This is also the slowest compression. - - - - - A synonym for BestCompression. - - - - - Describes options for how the compression algorithm is executed. Different strategies - work better on different sorts of data. The strategy parameter can affect the compression - ratio and the speed of compression but not the correctness of the compresssion. - - - - - The default strategy is probably the best for normal data. - - - - - The Filtered strategy is intended to be used most effectively with data produced by a - filter or predictor. By this definition, filtered data consists mostly of small - values with a somewhat random distribution. In this case, the compression algorithm - is tuned to compress them better. The effect of Filtered is to force more Huffman - coding and less string matching; it is a half-step between Default and HuffmanOnly. - - - - - Using HuffmanOnly will force the compressor to do Huffman encoding only, with no - string matching. - - - - - An enum to specify the direction of transcoding - whether to compress or decompress. - - - - - Used to specify that the stream should compress the data. - - - - - Used to specify that the stream should decompress the data. - - - - - A general purpose exception class for exceptions in the Zlib library. - - - - - The ZlibException class captures exception information generated - by the Zlib library. - - - - - This ctor collects a message attached to the exception. - - the message for the exception. - - - - Performs an unsigned bitwise right shift with the specified number - - Number to operate on - Ammount of bits to shift - The resulting number from the shift operation - - - - Reads a number of characters from the current source TextReader and writes - the data to the target array at the specified index. - - - The source TextReader to read from - Contains the array of characteres read from the source TextReader. - The starting index of the target array. - The maximum number of characters to read from the source TextReader. - - - The number of characters read. The number will be less than or equal to - count depending on the data available in the source TextReader. Returns -1 - if the end of the stream is reached. - - - - - Computes an Adler-32 checksum. - - - The Adler checksum is similar to a CRC checksum, but faster to compute, though less - reliable. It is used in producing RFC1950 compressed streams. The Adler checksum - is a required part of the "ZLIB" standard. Applications will almost never need to - use this class directly. - - - - - - - Calculates the Adler32 checksum. - - - - This is used within ZLIB. You probably don't need to use this directly. - - - - To compute an Adler32 checksum on a byte array: - - var adler = Adler.Adler32(0, null, 0, 0); - adler = Adler.Adler32(adler, buffer, index, length); - - - - - - Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951). - - - - This class compresses and decompresses data according to the Deflate algorithm - and optionally, the ZLIB format, as documented in RFC 1950 - ZLIB and RFC 1951 - DEFLATE. - - - - - The buffer from which data is taken. - - - - - An index into the InputBuffer array, indicating where to start reading. - - - - - The number of bytes available in the InputBuffer, starting at NextIn. - - - Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call. - The class will update this number as calls to Inflate/Deflate are made. - - - - - Total number of bytes read so far, through all calls to Inflate()/Deflate(). - - - - - Buffer to store output data. - - - - - An index into the OutputBuffer array, indicating where to start writing. - - - - - The number of bytes available in the OutputBuffer, starting at NextOut. - - - Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call. - The class will update this number as calls to Inflate/Deflate are made. - - - - - Total number of bytes written to the output so far, through all calls to Inflate()/Deflate(). - - - - - used for diagnostics, when something goes wrong! - - - - - The compression level to use in this codec. Useful only in compression mode. - - - - - The number of Window Bits to use. - - - This gauges the size of the sliding window, and hence the - compression effectiveness as well as memory consumption. It's best to just leave this - setting alone if you don't know what it is. The maximum value is 15 bits, which implies - a 32k window. - - - - - The compression strategy to use. - - - This is only effective in compression. The theory offered by ZLIB is that different - strategies could potentially produce significant differences in compression behavior - for different data sets. Unfortunately I don't have any good recommendations for how - to set it differently. When I tested changing the strategy I got minimally different - compression performance. It's best to leave this property alone if you don't have a - good feel for it. Or, you may want to produce a test harness that runs through the - different strategy options and evaluates them on different file types. If you do that, - let me know your results. - - - - - The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this. - - - - - Create a ZlibCodec. - - - If you use this default constructor, you will later have to explicitly call - InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress - or decompress. - - - - - Create a ZlibCodec that either compresses or decompresses. - - - Indicates whether the codec should compress (deflate) or decompress (inflate). - - - - - Initialize the inflation state. - - - It is not necessary to call this before using the ZlibCodec to inflate data; - It is implicitly called when you call the constructor. - - Z_OK if everything goes well. - - - - Initialize the inflation state with an explicit flag to - govern the handling of RFC1950 header bytes. - - - - By default, the ZLIB header defined in RFC 1950 is expected. If - you want to read a zlib stream you should specify true for - expectRfc1950Header. If you have a deflate stream, you will want to specify - false. It is only necessary to invoke this initializer explicitly if you - want to specify false. - - - whether to expect an RFC1950 header byte - pair when reading the stream of data to be inflated. - - Z_OK if everything goes well. - - - - Initialize the ZlibCodec for inflation, with the specified number of window bits. - - The number of window bits to use. If you need to ask what that is, - then you shouldn't be calling this initializer. - Z_OK if all goes well. - - - - Initialize the inflation state with an explicit flag to govern the handling of - RFC1950 header bytes. - - - - If you want to read a zlib stream you should specify true for - expectRfc1950Header. In this case, the library will expect to find a ZLIB - header, as defined in RFC - 1950, in the compressed stream. If you will be reading a DEFLATE or - GZIP stream, which does not have such a header, you will want to specify - false. - - - whether to expect an RFC1950 header byte pair when reading - the stream of data to be inflated. - The number of window bits to use. If you need to ask what that is, - then you shouldn't be calling this initializer. - Z_OK if everything goes well. - - - - Inflate the data in the InputBuffer, placing the result in the OutputBuffer. - - - You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and - AvailableBytesOut before calling this method. - - - - private void InflateBuffer() - { - int bufferSize = 1024; - byte[] buffer = new byte[bufferSize]; - ZlibCodec decompressor = new ZlibCodec(); - - Console.WriteLine("\n============================================"); - Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); - MemoryStream ms = new MemoryStream(DecompressedBytes); - - int rc = decompressor.InitializeInflate(); - - decompressor.InputBuffer = CompressedBytes; - decompressor.NextIn = 0; - decompressor.AvailableBytesIn = CompressedBytes.Length; - - decompressor.OutputBuffer = buffer; - - // pass 1: inflate - do - { - decompressor.NextOut = 0; - decompressor.AvailableBytesOut = buffer.Length; - rc = decompressor.Inflate(FlushType.None); - - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - throw new Exception("inflating: " + decompressor.Message); - - ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut); - } - while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); - - // pass 2: finish and flush - do - { - decompressor.NextOut = 0; - decompressor.AvailableBytesOut = buffer.Length; - rc = decompressor.Inflate(FlushType.Finish); - - if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) - throw new Exception("inflating: " + decompressor.Message); - - if (buffer.Length - decompressor.AvailableBytesOut > 0) - ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut); - } - while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); - - decompressor.EndInflate(); - } - - - - The flush to use when inflating. - Z_OK if everything goes well. - - - - Ends an inflation session. - - - Call this after successively calling Inflate(). This will cause all buffers to be flushed. - After calling this you cannot call Inflate() without a intervening call to one of the - InitializeInflate() overloads. - - Z_OK if everything goes well. - - - - I don't know what this does! - - Z_OK if everything goes well. - - - - Initialize the ZlibCodec for deflation operation. - - - The codec will use the MAX window bits and the default level of compression. - - - - int bufferSize = 40000; - byte[] CompressedBytes = new byte[bufferSize]; - byte[] DecompressedBytes = new byte[bufferSize]; - - ZlibCodec compressor = new ZlibCodec(); - - compressor.InitializeDeflate(CompressionLevel.Default); - - compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress); - compressor.NextIn = 0; - compressor.AvailableBytesIn = compressor.InputBuffer.Length; - - compressor.OutputBuffer = CompressedBytes; - compressor.NextOut = 0; - compressor.AvailableBytesOut = CompressedBytes.Length; - - while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize) - { - compressor.Deflate(FlushType.None); - } - - while (true) - { - int rc= compressor.Deflate(FlushType.Finish); - if (rc == ZlibConstants.Z_STREAM_END) break; - } - - compressor.EndDeflate(); - - - - Z_OK if all goes well. You generally don't need to check the return code. - - - - Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel. - - - The codec will use the maximum window bits (15) and the specified - CompressionLevel. It will emit a ZLIB stream as it compresses. - - The compression level for the codec. - Z_OK if all goes well. - - - - Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, - and the explicit flag governing whether to emit an RFC1950 header byte pair. - - - The codec will use the maximum window bits (15) and the specified CompressionLevel. - If you want to generate a zlib stream, you should specify true for - wantRfc1950Header. In this case, the library will emit a ZLIB - header, as defined in RFC - 1950, in the compressed stream. - - The compression level for the codec. - whether to emit an initial RFC1950 byte pair in the compressed stream. - Z_OK if all goes well. - - - - Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, - and the specified number of window bits. - - - The codec will use the specified number of window bits and the specified CompressionLevel. - - The compression level for the codec. - the number of window bits to use. If you don't know what this means, don't use this method. - Z_OK if all goes well. - - - - Initialize the ZlibCodec for deflation operation, using the specified - CompressionLevel, the specified number of window bits, and the explicit flag - governing whether to emit an RFC1950 header byte pair. - - - The compression level for the codec. - whether to emit an initial RFC1950 byte pair in the compressed stream. - the number of window bits to use. If you don't know what this means, don't use this method. - Z_OK if all goes well. - - - - Deflate one batch of data. - - - You must have set InputBuffer and OutputBuffer before calling this method. - - - - private void DeflateBuffer(CompressionLevel level) - { - int bufferSize = 1024; - byte[] buffer = new byte[bufferSize]; - ZlibCodec compressor = new ZlibCodec(); - - Console.WriteLine("\n============================================"); - Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); - MemoryStream ms = new MemoryStream(); - - int rc = compressor.InitializeDeflate(level); - - compressor.InputBuffer = UncompressedBytes; - compressor.NextIn = 0; - compressor.AvailableBytesIn = UncompressedBytes.Length; - - compressor.OutputBuffer = buffer; - - // pass 1: deflate - do - { - compressor.NextOut = 0; - compressor.AvailableBytesOut = buffer.Length; - rc = compressor.Deflate(FlushType.None); - - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - throw new Exception("deflating: " + compressor.Message); - - ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut); - } - while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); - - // pass 2: finish and flush - do - { - compressor.NextOut = 0; - compressor.AvailableBytesOut = buffer.Length; - rc = compressor.Deflate(FlushType.Finish); - - if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) - throw new Exception("deflating: " + compressor.Message); - - if (buffer.Length - compressor.AvailableBytesOut > 0) - ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut); - } - while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); - - compressor.EndDeflate(); - - ms.Seek(0, SeekOrigin.Begin); - CompressedBytes = new byte[compressor.TotalBytesOut]; - ms.Read(CompressedBytes, 0, CompressedBytes.Length); - } - - - whether to flush all data as you deflate. Generally you will want to - use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to - flush everything. - - Z_OK if all goes well. - - - - End a deflation session. - - - Call this after making a series of one or more calls to Deflate(). All buffers are flushed. - - Z_OK if all goes well. - - - - Reset a codec for another deflation session. - - - Call this to reset the deflation state. For example if a thread is deflating - non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first - block and before the next Deflate(None) of the second block. - - Z_OK if all goes well. - - - - Set the CompressionStrategy and CompressionLevel for a deflation session. - - the level of compression to use. - the strategy to use for compression. - Z_OK if all goes well. - - - - Set the dictionary to be used for either Inflation or Deflation. - - The dictionary bytes to use. - Z_OK if all goes well. - - - - Set the dictionary to be used for either Inflation or Deflation unconditionally. - - Decoding a MSZip file requires the dictionary state to be set unconditionally - at the end of each block to the previous decoded data - The dictionary bytes to use. - Z_OK if all goes well. - - - - A bunch of constants used in the Zlib interface. - - - - - The maximum number of window bits for the Deflate algorithm. - - - - - The default number of window bits for the Deflate algorithm. - - - - - indicates everything is A-OK - - - - - Indicates that the last operation reached the end of the stream. - - - - - The operation ended in need of a dictionary. - - - - - There was an error with the stream - not enough data, not open and readable, etc. - - - - - There was an error with the data - not enough data, bad data, etc. - - - - - There was an error with the working buffer. - - - - - The size of the working buffer used in the ZlibCodec class. - - - - - The minimum size of the working buffer used in the ZlibCodec class. - - - - - Represents a Zlib stream for compression or decompression. - - - - - The ZlibStream is a Decorator on a . It adds ZLIB compression or decompression to any - stream. - - - Using this stream, applications can compress or decompress data via - stream Read() and Write() operations. Either compresssion or - decompression can occur through either reading or writing. The compression - format used is ZLIB, which is documented in IETF RFC 1950, "ZLIB Compressed - Data Format Specification version 3.3". This implementation of ZLIB always uses - DEFLATE as the compression method. (see IETF RFC 1951, "DEFLATE - Compressed Data Format Specification version 1.3.") - - - The ZLIB format allows for varying compression methods, window sizes, and dictionaries. - This implementation always uses the DEFLATE compression method, a preset dictionary, - and 15 window bits by default. - - - - This class is similar to , except that it adds the - RFC1950 header and trailer bytes to a compressed stream when compressing, or expects - the RFC1950 header and trailer bytes when decompressing. It is also similar to the - . - - - - - - - - Create a ZlibStream using the specified CompressionMode. - - - - - When mode is CompressionMode.Compress, the ZlibStream - will use the default compression level. The "captive" stream will be - closed when the ZlibStream is closed. - - - - - - This example uses a ZlibStream to compress a file, and writes the - compressed data to another file. - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(fileToCompress + ".zlib")) - { - using (Stream compressor = new ZlibStream(raw, CompressionMode.Compress)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(fileToCompress & ".zlib") - Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - - The stream which will be read or written. - Indicates whether the ZlibStream will compress or decompress. - - - - Create a ZlibStream using the specified CompressionMode and - the specified CompressionLevel. - - - - - - When mode is CompressionMode.Decompress, the level parameter is ignored. - The "captive" stream will be closed when the ZlibStream is closed. - - - - - - This example uses a ZlibStream to compress data from a file, and writes the - compressed data to another file. - - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(fileToCompress + ".zlib")) - { - using (Stream compressor = new ZlibStream(raw, - CompressionMode.Compress, - CompressionLevel.BestCompression)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(fileToCompress & ".zlib") - Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - - The stream to be read or written while deflating or inflating. - Indicates whether the ZlibStream will compress or decompress. - A tuning knob to trade speed for effectiveness. - - - - Create a ZlibStream using the specified CompressionMode, and - explicitly specify whether the captive stream should be left open after - Deflation or Inflation. - - - - - - When mode is CompressionMode.Compress, the ZlibStream will use - the default compression level. - - - - This constructor allows the application to request that the captive stream - remain open after the deflation or inflation occurs. By default, after - Close() is called on the stream, the captive stream is also - closed. In some cases this is not desired, for example if the stream is a - that will be re-read after - compression. Specify true for the parameter to leave the stream - open. - - - - See the other overloads of this constructor for example code. - - - - - The stream which will be read or written. This is called the - "captive" stream in other places in this documentation. - Indicates whether the ZlibStream will compress or decompress. - true if the application would like the stream to remain - open after inflation/deflation. - - - - Create a ZlibStream using the specified CompressionMode - and the specified CompressionLevel, and explicitly specify - whether the stream should be left open after Deflation or Inflation. - - - - - - This constructor allows the application to request that the captive - stream remain open after the deflation or inflation occurs. By - default, after Close() is called on the stream, the captive - stream is also closed. In some cases this is not desired, for example - if the stream is a that will be - re-read after compression. Specify true for the parameter to leave the stream open. - - - - When mode is CompressionMode.Decompress, the level parameter is - ignored. - - - - - - - This example shows how to use a ZlibStream to compress the data from a file, - and store the result into another file. The filestream remains open to allow - additional data to be written to it. - - - using (var output = System.IO.File.Create(fileToCompress + ".zlib")) - { - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (Stream compressor = new ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - // can write additional data to the output stream here - } - - - Using output As FileStream = File.Create(fileToCompress & ".zlib") - Using input As Stream = File.OpenRead(fileToCompress) - Using compressor As Stream = New ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - ' can write additional data to the output stream here. - End Using - - - - The stream which will be read or written. - - Indicates whether the ZlibStream will compress or decompress. - - - true if the application would like the stream to remain open after - inflation/deflation. - - - - A tuning knob to trade speed for effectiveness. This parameter is - effective only when mode is CompressionMode.Compress. - - - - - This property sets the flush behavior on the stream. - Sorry, though, not sure exactly how to describe all the various settings. - - - - - The size of the working buffer for the compression codec. - - - - - The working buffer is used for all stream operations. The default size is - 1024 bytes. The minimum size is 128 bytes. You may get better performance - with a larger buffer. Then again, you might not. You would have to test - it. - - - - Set this before the first call to Read() or Write() on the - stream. If you try to set it afterwards, it will throw. - - - - - Returns the total number of bytes input so far. - - - Returns the total number of bytes output so far. - - - - Dispose the stream. - - - - This may or may not result in a Close() call on the captive - stream. See the constructors that have a leaveOpen parameter - for more information. - - - This method may be invoked in two distinct scenarios. If disposing - == true, the method has been called directly or indirectly by a - user's code, for example via the public Dispose() method. In this - case, both managed and unmanaged resources can be referenced and - disposed. If disposing == false, the method has been called by the - runtime from inside the object finalizer and this method should not - reference other objects; in that case only unmanaged resources must - be referenced or disposed. - - - - indicates whether the Dispose method was invoked by user code. - - - - - Indicates whether the stream can be read. - - - The return value depends on whether the captive stream supports reading. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value depends on whether the captive stream supports writing. - - - - - Flush the stream. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the total bytes - written out, if used in writing, or the total bytes read in, if used in - reading. The count may refer to compressed bytes or uncompressed bytes, - depending on how you've used the stream. - - - - - Read data from the stream. - - - - - - If you wish to use the ZlibStream to compress data while reading, - you can create a ZlibStream with CompressionMode.Compress, - providing an uncompressed data stream. Then call Read() on that - ZlibStream, and the data read will be compressed. If you wish to - use the ZlibStream to decompress data while reading, you can create - a ZlibStream with CompressionMode.Decompress, providing a - readable compressed data stream. Then call Read() on that - ZlibStream, and the data will be decompressed as it is read. - - - - A ZlibStream can be used for Read() or Write(), but - not both. - - - - - - The buffer into which the read data should be placed. - - - the offset within that data array to put the first byte read. - - the number of bytes to read. - - the number of bytes read - - - - Calling this method always throws a . - - - The offset to seek to.... - IF THIS METHOD ACTUALLY DID ANYTHING. - - - The reference specifying how to apply the offset.... IF - THIS METHOD ACTUALLY DID ANYTHING. - - - nothing. This method always throws. - - - - Calling this method always throws a . - - - The new value for the stream length.... IF - THIS METHOD ACTUALLY DID ANYTHING. - - - - - Write data to the stream. - - - - - - If you wish to use the ZlibStream to compress data while writing, - you can create a ZlibStream with CompressionMode.Compress, - and a writable output stream. Then call Write() on that - ZlibStream, providing uncompressed data as input. The data sent to - the output stream will be the compressed form of the data written. If you - wish to use the ZlibStream to decompress data while writing, you - can create a ZlibStream with CompressionMode.Decompress, and a - writable output stream. Then call Write() on that stream, - providing previously compressed data. The data sent to the output stream - will be the decompressed form of the data written. - - - - A ZlibStream can be used for Read() or Write(), but not both. - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Compress a string into a byte array using ZLIB. - - - - Uncompress it with . - - - - - - - - A string to compress. The string will first be encoded - using UTF8, then compressed. - - - The string in compressed form - - - - Compress a byte array into a new byte array using ZLIB. - - - - Uncompress it with . - - - - - - - A buffer to compress. - - - The data in compressed form - - - - Uncompress a ZLIB-compressed byte array into a single string. - - - - - - - A buffer containing ZLIB-compressed data. - - - The uncompressed string - - - - Uncompress a ZLIB-compressed byte array into a byte array. - - - - - - - A buffer containing ZLIB-compressed data. - - - The data in uncompressed form - -
-
diff --git a/packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.dll b/packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.dll deleted file mode 100644 index 2c6088a..0000000 Binary files a/packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.dll and /dev/null differ diff --git a/packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.pdb b/packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.pdb deleted file mode 100644 index a4f5522..0000000 Binary files a/packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.pdb and /dev/null differ diff --git a/packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.xml b/packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.xml deleted file mode 100644 index e1f7c2e..0000000 --- a/packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.xml +++ /dev/null @@ -1,18031 +0,0 @@ - - - - DotNetZip - - - - - Delivers the remaining bits, left-aligned, in a byte. - - - - This is valid only if NumRemainingBits is less than 8; - in other words it is valid only after a call to Flush(). - - - - - - Reset the BitWriter. - - - - This is useful when the BitWriter writes into a MemoryStream, and - is used by a BZip2Compressor, which itself is re-used for multiple - distinct data blocks. - - - - - - Write some number of bits from the given value, into the output. - - - - The nbits value should be a max of 25, for safety. For performance - reasons, this method does not check! - - - - - - Write a full 8-bit byte into the output. - - - - - Write four 8-bit bytes into the output. - - - - - Write all available byte-aligned bytes. - - - - This method writes no new output, but flushes any accumulated - bits. At completion, the accumulator may contain up to 7 - bits. - - - This is necessary when re-assembling output from N independent - compressors, one for each of N blocks. The output of any - particular compressor will in general have some fragment of a byte - remaining. This fragment needs to be accumulated into the - parent BZip2OutputStream. - - - - - - Writes all available bytes, and emits padding for the final byte as - necessary. This must be the last method invoked on an instance of - BitWriter. - - - - Knuth's increments seem to work better than Incerpi-Sedgewick here. - Possibly because the number of elems to sort is usually small, typically - <= 20. - - - - BZip2Compressor writes its compressed data out via a BitWriter. This - is necessary because BZip2 does byte shredding. - - - - - The number of uncompressed bytes being held in the buffer. - - - - I am thinking this may be useful in a Stream that uses this - compressor class. In the Close() method on the stream it could - check this value to see if anything has been written at all. You - may think the stream could easily track the number of bytes it - wrote, which would eliminate the need for this. But, there is the - case where the stream writes a complete block, and it is full, and - then writes no more. In that case the stream may want to check. - - - - - - Accept new bytes into the compressor data buffer - - - - This method does the first-level (cheap) run-length encoding, and - stores the encoded data into the rle block. - - - - - - Process one input byte into the block. - - - - - To "process" the byte means to do the run-length encoding. - There are 3 possible return values: - - 0 - the byte was not written, in other words, not - encoded into the block. This happens when the - byte b would require the start of a new run, and - the block has no more room for new runs. - - 1 - the byte was written, and the block is not full. - - 2 - the byte was written, and the block is full. - - - - 0 if the byte was not written, non-zero if written. - - - - Append one run to the output block. - - - - - This compressor does run-length-encoding before BWT and etc. This - method simply appends a run to the output block. The append always - succeeds. The return value indicates whether the block is full: - false (not full) implies that at least one additional run could be - processed. - - - true if the block is now full; otherwise false. - - - - Compress the data that has been placed (Run-length-encoded) into the - block. The compressed data goes into the CompressedBytes array. - - - - Side effects: 1. fills the CompressedBytes array. 2. sets the - AvailableBytesOut property. - - - - - This is the most hammered method of this class. - -

- This is the version using unrolled loops. -

-
- - Method "mainQSort3", file "blocksort.c", BZip2 1.0.2 - - - Array instance identical to sfmap, both are used only - temporarily and independently, so we do not need to allocate - additional memory. - - - - A read-only decorator stream that performs BZip2 decompression on Read. - - - - - Compressor State - - - - - Create a BZip2InputStream, wrapping it around the given input Stream. - - - - The input stream will be closed when the BZip2InputStream is closed. - - - The stream from which to read compressed data - - - - Create a BZip2InputStream with the given stream, and - specifying whether to leave the wrapped stream open when - the BZip2InputStream is closed. - - The stream from which to read compressed data - - Whether to leave the input stream open, when the BZip2InputStream closes. - - - - - This example reads a bzip2-compressed file, decompresses it, - and writes the decompressed data into a newly created file. - - - var fname = "logfile.log.bz2"; - using (var fs = File.OpenRead(fname)) - { - using (var decompressor = new Ionic.BZip2.BZip2InputStream(fs)) - { - var outFname = fname + ".decompressed"; - using (var output = File.Create(outFname)) - { - byte[] buffer = new byte[2048]; - int n; - while ((n = decompressor.Read(buffer, 0, buffer.Length)) > 0) - { - output.Write(buffer, 0, n); - } - } - } - } - - - - - - Read data from the stream. - - - - - To decompress a BZip2 data stream, create a BZip2InputStream, - providing a stream that reads compressed data. Then call Read() on - that BZip2InputStream, and the data read will be decompressed - as you read. - - - - A BZip2InputStream can be used only for Read(), not for Write(). - - - - The buffer into which the read data should be placed. - the offset within that data array to put the first byte read. - the number of bytes to read. - the number of bytes actually read - - - - Read a single byte from the stream. - - the byte read from the stream, or -1 if EOF - - - - Indicates whether the stream can be read. - - - The return value depends on whether the captive stream supports reading. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value depends on whether the captive stream supports writing. - - - - - Flush the stream. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the - total number of uncompressed bytes read in. - - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - this is irrelevant, since it will always throw! - irrelevant! - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - - - - Calling this method always throws a . - - this parameter is never used - this parameter is never used - this parameter is never used - - - - Dispose the stream. - - - indicates whether the Dispose method was invoked by user code. - - - - - Close the stream. - - - - - Read n bits from input, right justifying the result. - - - - For example, if you read 1 bit, the result is either 0 - or 1. - - - - The number of bits to read, always between 1 and 32. - - - - Called by createHuffmanDecodingTables() exclusively. - - - Called by recvDecodingTables() exclusively. - - - Freq table collected to save a pass over the data during - decompression. - - - Initializes the tt array. - - This method is called when the required length of the array is known. - I don't initialize it at construction time to avoid unneccessary - memory allocation when compressing small files. - - - - A write-only decorator stream that compresses data as it is - written using the BZip2 algorithm. - - - - - Constructs a new BZip2OutputStream, that sends its - compressed output to the given output stream. - - - - The destination stream, to which compressed output will be sent. - - - - - This example reads a file, then compresses it with bzip2 file, - and writes the compressed data into a newly created file. - - - var fname = "logfile.log"; - using (var fs = File.OpenRead(fname)) - { - var outFname = fname + ".bz2"; - using (var output = File.Create(outFname)) - { - using (var compressor = new Ionic.BZip2.BZip2OutputStream(output)) - { - byte[] buffer = new byte[2048]; - int n; - while ((n = fs.Read(buffer, 0, buffer.Length)) > 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - - - - Constructs a new BZip2OutputStream with specified blocksize. - - the destination stream. - - The blockSize in units of 100000 bytes. - The valid range is 1..9. - - - - - Constructs a new BZip2OutputStream. - - the destination stream. - - whether to leave the captive stream open upon closing this stream. - - - - - Constructs a new BZip2OutputStream with specified blocksize, - and explicitly specifies whether to leave the wrapped stream open. - - - the destination stream. - - The blockSize in units of 100000 bytes. - The valid range is 1..9. - - - whether to leave the captive stream open upon closing this stream. - - - - - Close the stream. - - - - This may or may not close the underlying stream. Check the - constructors that accept a bool value. - - - - - - Flush the stream. - - - - - The blocksize parameter specified at construction time. - - - - - Write data to the stream. - - - - - Use the BZip2OutputStream to compress data while writing: - create a BZip2OutputStream with a writable output stream. - Then call Write() on that BZip2OutputStream, providing - uncompressed data as input. The data sent to the output stream will - be the compressed form of the input data. - - - - A BZip2OutputStream can be used only for Write() not for Read(). - - - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Indicates whether the stream can be read. - - - The return value is always false. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value should always be true, unless and until the - object is disposed and closed. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the - total number of uncompressed bytes written through. - - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - this is irrelevant, since it will always throw! - irrelevant! - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - - - - Calling this method always throws a . - - this parameter is never used - this parameter is never used - this parameter is never used - never returns anything; always throws - - - - A write-only decorator stream that compresses data as it is - written using the BZip2 algorithm. This stream compresses by - block using multiple threads. - - - This class performs BZIP2 compression through writing. For - more information on the BZIP2 algorithm, see - . - - - - This class is similar to , - except that this implementation uses an approach that employs multiple - worker threads to perform the compression. On a multi-cpu or multi-core - computer, the performance of this class can be significantly higher than - the single-threaded BZip2OutputStream, particularly for larger streams. - How large? Anything over 10mb is a good candidate for parallel - compression. - - - - The tradeoff is that this class uses more memory and more CPU than the - vanilla BZip2OutputStream. Also, for small files, the - ParallelBZip2OutputStream can be much slower than the vanilla - BZip2OutputStream, because of the overhead associated to using the - thread pool. - - - - - - - Constructs a new ParallelBZip2OutputStream, that sends its - compressed output to the given output stream. - - - - The destination stream, to which compressed output will be sent. - - - - - This example reads a file, then compresses it with bzip2 file, - and writes the compressed data into a newly created file. - - - var fname = "logfile.log"; - using (var fs = File.OpenRead(fname)) - { - var outFname = fname + ".bz2"; - using (var output = File.Create(outFname)) - { - using (var compressor = new Ionic.BZip2.ParallelBZip2OutputStream(output)) - { - byte[] buffer = new byte[2048]; - int n; - while ((n = fs.Read(buffer, 0, buffer.Length)) > 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - - - - Constructs a new ParallelBZip2OutputStream with specified blocksize. - - the destination stream. - - The blockSize in units of 100000 bytes. - The valid range is 1..9. - - - - - Constructs a new ParallelBZip2OutputStream. - - the destination stream. - - whether to leave the captive stream open upon closing this stream. - - - - - Constructs a new ParallelBZip2OutputStream with specified blocksize, - and explicitly specifies whether to leave the wrapped stream open. - - - the destination stream. - - The blockSize in units of 100000 bytes. - The valid range is 1..9. - - - whether to leave the captive stream open upon closing this stream. - - - - - The maximum number of concurrent compression worker threads to use. - - - - - This property sets an upper limit on the number of concurrent worker - threads to employ for compression. The implementation of this stream - employs multiple threads from the .NET thread pool, via - ThreadPool.QueueUserWorkItem(), to compress the incoming data by - block. As each block of data is compressed, this stream re-orders the - compressed blocks and writes them to the output stream. - - - - A higher number of workers enables a higher degree of - parallelism, which tends to increase the speed of compression on - multi-cpu computers. On the other hand, a higher number of buffer - pairs also implies a larger memory consumption, more active worker - threads, and a higher cpu utilization for any compression. This - property enables the application to limit its memory consumption and - CPU utilization behavior depending on requirements. - - - - By default, DotNetZip allocates 4 workers per CPU core, subject to the - upper limit specified in this property. For example, suppose the - application sets this property to 16. Then, on a machine with 2 - cores, DotNetZip will use 8 workers; that number does not exceed the - upper limit specified by this property, so the actual number of - workers used will be 4 * 2 = 8. On a machine with 4 cores, DotNetZip - will use 16 workers; again, the limit does not apply. On a machine - with 8 cores, DotNetZip will use 16 workers, because of the limit. - - - - For each compression "worker thread" that occurs in parallel, there is - up to 2mb of memory allocated, for buffering and processing. The - actual number depends on the property. - - - - CPU utilization will also go up with additional workers, because a - larger number of buffer pairs allows a larger number of background - threads to compress in parallel. If you find that parallel - compression is consuming too much memory or CPU, you can adjust this - value downward. - - - - The default value is 16. Different values may deliver better or - worse results, depending on your priorities and the dynamic - performance characteristics of your storage and compute resources. - - - - The application can set this value at any time, but it is effective - only before the first call to Write(), which is when the buffers are - allocated. - - - - - - Close the stream. - - - - This may or may not close the underlying stream. Check the - constructors that accept a bool value. - - - - - - Flush the stream. - - - - - The blocksize parameter specified at construction time. - - - - - Write data to the stream. - - - - - Use the ParallelBZip2OutputStream to compress data while - writing: create a ParallelBZip2OutputStream with a writable - output stream. Then call Write() on that - ParallelBZip2OutputStream, providing uncompressed data as - input. The data sent to the output stream will be the compressed - form of the input data. - - - - A ParallelBZip2OutputStream can be used only for - Write() not for Read(). - - - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Indicates whether the stream can be read. - - - The return value is always false. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value depends on whether the captive stream supports writing. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the - total number of uncompressed bytes written through. - - - - - The total number of bytes written out by the stream. - - - This value is meaningful only after a call to Close(). - - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - this is irrelevant, since it will always throw! - irrelevant! - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - - - - Calling this method always throws a . - - this parameter is never used - this parameter is never used - this parameter is never used - never returns anything; always throws - - - - Returns the "random" number at a specific index. - - the index - the random number - - - - Computes a CRC-32. The CRC-32 algorithm is parameterized - you - can set the polynomial and enable or disable bit - reversal. This can be used for GZIP, BZip2, or ZIP. - - - This type is used internally by DotNetZip; it is generally not used - directly by applications wishing to create, read, or manipulate zip - archive files. - - - - - Indicates the total number of bytes applied to the CRC. - - - - - Indicates the current CRC for all blocks slurped in. - - - - - Returns the CRC32 for the specified stream. - - The stream over which to calculate the CRC32 - the CRC32 calculation - - - - Returns the CRC32 for the specified stream, and writes the input into the - output stream. - - The stream over which to calculate the CRC32 - The stream into which to deflate the input - the CRC32 calculation - - - - Get the CRC32 for the given (word,byte) combo. This is a - computation defined by PKzip for PKZIP 2.0 (weak) encryption. - - The word to start with. - The byte to combine it with. - The CRC-ized result. - - - - Update the value for the running CRC32 using the given block of bytes. - This is useful when using the CRC32() class in a Stream. - - block of bytes to slurp - starting point in the block - how many bytes within the block to slurp - - - - Process one byte in the CRC. - - the byte to include into the CRC . - - - - Process a run of N identical bytes into the CRC. - - - - This method serves as an optimization for updating the CRC when a - run of identical bytes is found. Rather than passing in a buffer of - length n, containing all identical bytes b, this method accepts the - byte value and the length of the (virtual) buffer - the length of - the run. - - - the byte to include into the CRC. - the number of times that byte should be repeated. - - - - Combines the given CRC32 value with the current running total. - - - This is useful when using a divide-and-conquer approach to - calculating a CRC. Multiple threads can each calculate a - CRC32 on a segment of the data, and then combine the - individual CRC32 values at the end. - - the crc value to be combined with this one - the length of data the CRC value was calculated on - - - - Create an instance of the CRC32 class using the default settings: no - bit reversal, and a polynomial of 0xEDB88320. - - - - - Create an instance of the CRC32 class, specifying whether to reverse - data bits or not. - - - specify true if the instance should reverse data bits. - - - - In the CRC-32 used by BZip2, the bits are reversed. Therefore if you - want a CRC32 with compatibility with BZip2, you should pass true - here. In the CRC-32 used by GZIP and PKZIP, the bits are not - reversed; Therefore if you want a CRC32 with compatibility with - those, you should pass false. - - - - - - Create an instance of the CRC32 class, specifying the polynomial and - whether to reverse data bits or not. - - - The polynomial to use for the CRC, expressed in the reversed (LSB) - format: the highest ordered bit in the polynomial value is the - coefficient of the 0th power; the second-highest order bit is the - coefficient of the 1 power, and so on. Expressed this way, the - polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320. - - - specify true if the instance should reverse data bits. - - - - - In the CRC-32 used by BZip2, the bits are reversed. Therefore if you - want a CRC32 with compatibility with BZip2, you should pass true - here for the reverseBits parameter. In the CRC-32 used by - GZIP and PKZIP, the bits are not reversed; Therefore if you want a - CRC32 with compatibility with those, you should pass false for the - reverseBits parameter. - - - - - - Reset the CRC-32 class - clear the CRC "remainder register." - - - - Use this when employing a single instance of this class to compute - multiple, distinct CRCs on multiple, distinct data blocks. - - - - - - A Stream that calculates a CRC32 (a checksum) on all bytes read, - or on all bytes written. - - - - - This class can be used to verify the CRC of a ZipEntry when - reading from a stream, or to calculate a CRC when writing to a - stream. The stream should be used to either read, or write, but - not both. If you intermix reads and writes, the results are not - defined. - - - - This class is intended primarily for use internally by the - DotNetZip library. - - - - - - The default constructor. - - - - Instances returned from this constructor will leave the underlying - stream open upon Close(). The stream uses the default CRC32 - algorithm, which implies a polynomial of 0xEDB88320. - - - The underlying stream - - - - The constructor allows the caller to specify how to handle the - underlying stream at close. - - - - The stream uses the default CRC32 algorithm, which implies a - polynomial of 0xEDB88320. - - - The underlying stream - true to leave the underlying stream - open upon close of the CrcCalculatorStream; false otherwise. - - - - A constructor allowing the specification of the length of the stream - to read. - - - - The stream uses the default CRC32 algorithm, which implies a - polynomial of 0xEDB88320. - - - Instances returned from this constructor will leave the underlying - stream open upon Close(). - - - The underlying stream - The length of the stream to slurp - - - - A constructor allowing the specification of the length of the stream - to read, as well as whether to keep the underlying stream open upon - Close(). - - - - The stream uses the default CRC32 algorithm, which implies a - polynomial of 0xEDB88320. - - - The underlying stream - The length of the stream to slurp - true to leave the underlying stream - open upon close of the CrcCalculatorStream; false otherwise. - - - - A constructor allowing the specification of the length of the stream - to read, as well as whether to keep the underlying stream open upon - Close(), and the CRC32 instance to use. - - - - The stream uses the specified CRC32 instance, which allows the - application to specify how the CRC gets calculated. - - - The underlying stream - The length of the stream to slurp - true to leave the underlying stream - open upon close of the CrcCalculatorStream; false otherwise. - the CRC32 instance to use to calculate the CRC32 - - - - Gets the total number of bytes run through the CRC32 calculator. - - - - This is either the total number of bytes read, or the total number of - bytes written, depending on the direction of this stream. - - - - - Provides the current CRC for all blocks slurped in. - - - - The running total of the CRC is kept as data is written or read - through the stream. read this property after all reads or writes to - get an accurate CRC for the entire stream. - - - - - - Indicates whether the underlying stream will be left open when the - CrcCalculatorStream is Closed. - - - - Set this at any point before calling . - - - - - - Read from the stream - - the buffer to read - the offset at which to start - the number of bytes to read - the number of bytes actually read - - - - Write to the stream. - - the buffer from which to write - the offset at which to start writing - the number of bytes to write - - - - Indicates whether the stream supports reading. - - - - - Indicates whether the stream supports seeking. - - - - Always returns false. - - - - - - Indicates whether the stream supports writing. - - - - - Flush the stream. - - - - - Returns the length of the underlying stream. - - - - - The getter for this property returns the total bytes read. - If you use the setter, it will throw - . - - - - - Seeking is not supported on this stream. This method always throws - - - N/A - N/A - N/A - - - - This method always throws - - - N/A - - - - Closes the stream. - - - - - A class for compressing and decompressing streams using the Deflate algorithm. - - - - - - The DeflateStream is a Decorator on a . It adds DEFLATE compression or decompression to any - stream. - - - - Using this stream, applications can compress or decompress data via stream - Read and Write operations. Either compresssion or decompression - can occur through either reading or writing. The compression format used is - DEFLATE, which is documented in IETF RFC 1951, "DEFLATE - Compressed Data Format Specification version 1.3.". - - - - This class is similar to , except that - ZlibStream adds the RFC - 1950 - ZLIB framing bytes to a compressed stream when compressing, or - expects the RFC1950 framing bytes when decompressing. The DeflateStream - does not. - - - - - - - - - - Create a DeflateStream using the specified CompressionMode. - - - - When mode is CompressionMode.Compress, the DeflateStream will use - the default compression level. The "captive" stream will be closed when - the DeflateStream is closed. - - - - This example uses a DeflateStream to compress data from a file, and writes - the compressed data to another file. - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(fileToCompress + ".deflated")) - { - using (Stream compressor = new DeflateStream(raw, CompressionMode.Compress)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(fileToCompress & ".deflated") - Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - The stream which will be read or written. - Indicates whether the DeflateStream will compress or decompress. - - - - Create a DeflateStream using the specified CompressionMode and the specified CompressionLevel. - - - - - - When mode is CompressionMode.Decompress, the level parameter is - ignored. The "captive" stream will be closed when the DeflateStream is - closed. - - - - - - - This example uses a DeflateStream to compress data from a file, and writes - the compressed data to another file. - - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(fileToCompress + ".deflated")) - { - using (Stream compressor = new DeflateStream(raw, - CompressionMode.Compress, - CompressionLevel.BestCompression)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n= -1; - while (n != 0) - { - if (n > 0) - compressor.Write(buffer, 0, n); - n= input.Read(buffer, 0, buffer.Length); - } - } - } - } - - - - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(fileToCompress & ".deflated") - Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - The stream to be read or written while deflating or inflating. - Indicates whether the DeflateStream will compress or decompress. - A tuning knob to trade speed for effectiveness. - - - - Create a DeflateStream using the specified - CompressionMode, and explicitly specify whether the - stream should be left open after Deflation or Inflation. - - - - - - This constructor allows the application to request that the captive stream - remain open after the deflation or inflation occurs. By default, after - Close() is called on the stream, the captive stream is also - closed. In some cases this is not desired, for example if the stream is a - memory stream that will be re-read after compression. Specify true for - the parameter to leave the stream open. - - - - The DeflateStream will use the default compression level. - - - - See the other overloads of this constructor for example code. - - - - - The stream which will be read or written. This is called the - "captive" stream in other places in this documentation. - - - - Indicates whether the DeflateStream will compress or decompress. - - - true if the application would like the stream to - remain open after inflation/deflation. - - - - Create a DeflateStream using the specified CompressionMode - and the specified CompressionLevel, and explicitly specify whether - the stream should be left open after Deflation or Inflation. - - - - - - When mode is CompressionMode.Decompress, the level parameter is ignored. - - - - This constructor allows the application to request that the captive stream - remain open after the deflation or inflation occurs. By default, after - Close() is called on the stream, the captive stream is also - closed. In some cases this is not desired, for example if the stream is a - that will be re-read after - compression. Specify true for the parameter - to leave the stream open. - - - - - - - This example shows how to use a DeflateStream to compress data from - a file, and store the compressed data into another file. - - - using (var output = System.IO.File.Create(fileToCompress + ".deflated")) - { - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (Stream compressor = new DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n= -1; - while (n != 0) - { - if (n > 0) - compressor.Write(buffer, 0, n); - n= input.Read(buffer, 0, buffer.Length); - } - } - } - // can write additional data to the output stream here - } - - - - Using output As FileStream = File.Create(fileToCompress & ".deflated") - Using input As Stream = File.OpenRead(fileToCompress) - Using compressor As Stream = New DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - ' can write additional data to the output stream here. - End Using - - - The stream which will be read or written. - Indicates whether the DeflateStream will compress or decompress. - true if the application would like the stream to remain open after inflation/deflation. - A tuning knob to trade speed for effectiveness. - - - - This property sets the flush behavior on the stream. - - See the ZLIB documentation for the meaning of the flush behavior. - - - - - The size of the working buffer for the compression codec. - - - - - The working buffer is used for all stream operations. The default size is - 1024 bytes. The minimum size is 128 bytes. You may get better performance - with a larger buffer. Then again, you might not. You would have to test - it. - - - - Set this before the first call to Read() or Write() on the - stream. If you try to set it afterwards, it will throw. - - - - - - The ZLIB strategy to be used during compression. - - - - By tweaking this parameter, you may be able to optimize the compression for - data with particular characteristics. - - - - Returns the total number of bytes input so far. - - - Returns the total number of bytes output so far. - - - - Dispose the stream. - - - - This may or may not result in a Close() call on the captive - stream. See the constructors that have a leaveOpen parameter - for more information. - - - Application code won't call this code directly. This method may be - invoked in two distinct scenarios. If disposing == true, the method - has been called directly or indirectly by a user's code, for example - via the public Dispose() method. In this case, both managed and - unmanaged resources can be referenced and disposed. If disposing == - false, the method has been called by the runtime from inside the - object finalizer and this method should not reference other objects; - in that case only unmanaged resources must be referenced or - disposed. - - - - true if the Dispose method was invoked by user code. - - - - - Indicates whether the stream can be read. - - - The return value depends on whether the captive stream supports reading. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value depends on whether the captive stream supports writing. - - - - - Flush the stream. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the total bytes - written out, if used in writing, or the total bytes read in, if used in - reading. The count may refer to compressed bytes or uncompressed bytes, - depending on how you've used the stream. - - - - - Read data from the stream. - - - - - If you wish to use the DeflateStream to compress data while - reading, you can create a DeflateStream with - CompressionMode.Compress, providing an uncompressed data stream. - Then call Read() on that DeflateStream, and the data read will be - compressed as you read. If you wish to use the DeflateStream to - decompress data while reading, you can create a DeflateStream with - CompressionMode.Decompress, providing a readable compressed data - stream. Then call Read() on that DeflateStream, and the data read - will be decompressed as you read. - - - - A DeflateStream can be used for Read() or Write(), but not both. - - - - The buffer into which the read data should be placed. - the offset within that data array to put the first byte read. - the number of bytes to read. - the number of bytes actually read - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - this is irrelevant, since it will always throw! - irrelevant! - - - - Calling this method always throws a . - - this is irrelevant, since it will always throw! - - - - Write data to the stream. - - - - - If you wish to use the DeflateStream to compress data while - writing, you can create a DeflateStream with - CompressionMode.Compress, and a writable output stream. Then call - Write() on that DeflateStream, providing uncompressed data - as input. The data sent to the output stream will be the compressed form - of the data written. If you wish to use the DeflateStream to - decompress data while writing, you can create a DeflateStream with - CompressionMode.Decompress, and a writable output stream. Then - call Write() on that stream, providing previously compressed - data. The data sent to the output stream will be the decompressed form of - the data written. - - - - A DeflateStream can be used for Read() or Write(), - but not both. - - - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Compress a string into a byte array using DEFLATE (RFC 1951). - - - - Uncompress it with . - - - DeflateStream.UncompressString(byte[]) - DeflateStream.CompressBuffer(byte[]) - GZipStream.CompressString(string) - ZlibStream.CompressString(string) - - - A string to compress. The string will first be encoded - using UTF8, then compressed. - - - The string in compressed form - - - - Compress a byte array into a new byte array using DEFLATE. - - - - Uncompress it with . - - - DeflateStream.CompressString(string) - DeflateStream.UncompressBuffer(byte[]) - GZipStream.CompressBuffer(byte[]) - ZlibStream.CompressBuffer(byte[]) - - - A buffer to compress. - - - The data in compressed form - - - - Uncompress a DEFLATE'd byte array into a single string. - - - DeflateStream.CompressString(String) - DeflateStream.UncompressBuffer(byte[]) - GZipStream.UncompressString(byte[]) - ZlibStream.UncompressString(byte[]) - - - A buffer containing DEFLATE-compressed data. - - - The uncompressed string - - - - Uncompress a DEFLATE'd byte array into a byte array. - - - DeflateStream.CompressBuffer(byte[]) - DeflateStream.UncompressString(byte[]) - GZipStream.UncompressBuffer(byte[]) - ZlibStream.UncompressBuffer(byte[]) - - - A buffer containing data that has been compressed with DEFLATE. - - - The data in uncompressed form - - - - A class for compressing and decompressing GZIP streams. - - - - - The GZipStream is a Decorator on a - . It adds GZIP compression or decompression to any - stream. - - - - Like the System.IO.Compression.GZipStream in the .NET Base Class Library, the - Ionic.Zlib.GZipStream can compress while writing, or decompress while - reading, but not vice versa. The compression method used is GZIP, which is - documented in IETF RFC - 1952, "GZIP file format specification version 4.3". - - - A GZipStream can be used to decompress data (through Read()) or - to compress data (through Write()), but not both. - - - - If you wish to use the GZipStream to compress data, you must wrap it - around a write-able stream. As you call Write() on the GZipStream, the - data will be compressed into the GZIP format. If you want to decompress data, - you must wrap the GZipStream around a readable stream that contains an - IETF RFC 1952-compliant stream. The data will be decompressed as you call - Read() on the GZipStream. - - - - Though the GZIP format allows data from multiple files to be concatenated - together, this stream handles only a single segment of GZIP format, typically - representing a single file. - - - - This class is similar to and . - ZlibStream handles RFC1950-compliant streams. - handles RFC1951-compliant streams. This class handles RFC1952-compliant streams. - - - - - - - - - - The comment on the GZIP stream. - - - - - The GZIP format allows for each file to optionally have an associated - comment stored with the file. The comment is encoded with the ISO-8859-1 - code page. To include a comment in a GZIP stream you create, set this - property before calling Write() for the first time on the - GZipStream. - - - - When using GZipStream to decompress, you can retrieve this property - after the first call to Read(). If no comment has been set in the - GZIP bytestream, the Comment property will return null - (Nothing in VB). - - - - - - The FileName for the GZIP stream. - - - - - - The GZIP format optionally allows each file to have an associated - filename. When compressing data (through Write()), set this - FileName before calling Write() the first time on the GZipStream. - The actual filename is encoded into the GZIP bytestream with the - ISO-8859-1 code page, according to RFC 1952. It is the application's - responsibility to insure that the FileName can be encoded and decoded - correctly with this code page. - - - - When decompressing (through Read()), you can retrieve this value - any time after the first Read(). In the case where there was no filename - encoded into the GZIP bytestream, the property will return null (Nothing - in VB). - - - - - - The last modified time for the GZIP stream. - - - - GZIP allows the storage of a last modified time with each GZIP entry. - When compressing data, you can set this before the first call to - Write(). When decompressing, you can retrieve this value any time - after the first call to Read(). - - - - - The CRC on the GZIP stream. - - - This is used for internal error checking. You probably don't need to look at this property. - - - - - Create a GZipStream using the specified CompressionMode. - - - - - When mode is CompressionMode.Compress, the GZipStream will use the - default compression level. - - - - As noted in the class documentation, the CompressionMode (Compress - or Decompress) also establishes the "direction" of the stream. A - GZipStream with CompressionMode.Compress works only through - Write(). A GZipStream with - CompressionMode.Decompress works only through Read(). - - - - - - This example shows how to use a GZipStream to compress data. - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(outputFile)) - { - using (Stream compressor = new GZipStream(raw, CompressionMode.Compress)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - Dim outputFile As String = (fileToCompress & ".compressed") - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(outputFile) - Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - - - This example shows how to use a GZipStream to uncompress a file. - - private void GunZipFile(string filename) - { - if (!filename.EndsWith(".gz)) - throw new ArgumentException("filename"); - var DecompressedFile = filename.Substring(0,filename.Length-3); - byte[] working = new byte[WORKING_BUFFER_SIZE]; - int n= 1; - using (System.IO.Stream input = System.IO.File.OpenRead(filename)) - { - using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) - { - using (var output = System.IO.File.Create(DecompressedFile)) - { - while (n !=0) - { - n= decompressor.Read(working, 0, working.Length); - if (n > 0) - { - output.Write(working, 0, n); - } - } - } - } - } - } - - - - Private Sub GunZipFile(ByVal filename as String) - If Not (filename.EndsWith(".gz)) Then - Throw New ArgumentException("filename") - End If - Dim DecompressedFile as String = filename.Substring(0,filename.Length-3) - Dim working(WORKING_BUFFER_SIZE) as Byte - Dim n As Integer = 1 - Using input As Stream = File.OpenRead(filename) - Using decompressor As Stream = new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, True) - Using output As Stream = File.Create(UncompressedFile) - Do - n= decompressor.Read(working, 0, working.Length) - If n > 0 Then - output.Write(working, 0, n) - End IF - Loop While (n > 0) - End Using - End Using - End Using - End Sub - - - - The stream which will be read or written. - Indicates whether the GZipStream will compress or decompress. - - - - Create a GZipStream using the specified CompressionMode and - the specified CompressionLevel. - - - - - The CompressionMode (Compress or Decompress) also establishes the - "direction" of the stream. A GZipStream with - CompressionMode.Compress works only through Write(). A - GZipStream with CompressionMode.Decompress works only - through Read(). - - - - - - - This example shows how to use a GZipStream to compress a file into a .gz file. - - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(fileToCompress + ".gz")) - { - using (Stream compressor = new GZipStream(raw, - CompressionMode.Compress, - CompressionLevel.BestCompression)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(fileToCompress & ".gz") - Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - The stream to be read or written while deflating or inflating. - Indicates whether the GZipStream will compress or decompress. - A tuning knob to trade speed for effectiveness. - - - - Create a GZipStream using the specified CompressionMode, and - explicitly specify whether the stream should be left open after Deflation - or Inflation. - - - - - This constructor allows the application to request that the captive stream - remain open after the deflation or inflation occurs. By default, after - Close() is called on the stream, the captive stream is also - closed. In some cases this is not desired, for example if the stream is a - memory stream that will be re-read after compressed data has been written - to it. Specify true for the parameter to leave - the stream open. - - - - The (Compress or Decompress) also - establishes the "direction" of the stream. A GZipStream with - CompressionMode.Compress works only through Write(). A GZipStream - with CompressionMode.Decompress works only through Read(). - - - - The GZipStream will use the default compression level. If you want - to specify the compression level, see . - - - - See the other overloads of this constructor for example code. - - - - - - The stream which will be read or written. This is called the "captive" - stream in other places in this documentation. - - - Indicates whether the GZipStream will compress or decompress. - - - - true if the application would like the base stream to remain open after - inflation/deflation. - - - - - Create a GZipStream using the specified CompressionMode and the - specified CompressionLevel, and explicitly specify whether the - stream should be left open after Deflation or Inflation. - - - - - - This constructor allows the application to request that the captive stream - remain open after the deflation or inflation occurs. By default, after - Close() is called on the stream, the captive stream is also - closed. In some cases this is not desired, for example if the stream is a - memory stream that will be re-read after compressed data has been written - to it. Specify true for the parameter to - leave the stream open. - - - - As noted in the class documentation, the CompressionMode (Compress - or Decompress) also establishes the "direction" of the stream. A - GZipStream with CompressionMode.Compress works only through - Write(). A GZipStream with CompressionMode.Decompress works only - through Read(). - - - - - - This example shows how to use a GZipStream to compress data. - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(outputFile)) - { - using (Stream compressor = new GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, true)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - Dim outputFile As String = (fileToCompress & ".compressed") - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(outputFile) - Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, True) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - The stream which will be read or written. - Indicates whether the GZipStream will compress or decompress. - true if the application would like the stream to remain open after inflation/deflation. - A tuning knob to trade speed for effectiveness. - - - - This property sets the flush behavior on the stream. - - - - - The size of the working buffer for the compression codec. - - - - - The working buffer is used for all stream operations. The default size is - 1024 bytes. The minimum size is 128 bytes. You may get better performance - with a larger buffer. Then again, you might not. You would have to test - it. - - - - Set this before the first call to Read() or Write() on the - stream. If you try to set it afterwards, it will throw. - - - - - Returns the total number of bytes input so far. - - - Returns the total number of bytes output so far. - - - - Dispose the stream. - - - - This may or may not result in a Close() call on the captive - stream. See the constructors that have a leaveOpen parameter - for more information. - - - This method may be invoked in two distinct scenarios. If disposing - == true, the method has been called directly or indirectly by a - user's code, for example via the public Dispose() method. In this - case, both managed and unmanaged resources can be referenced and - disposed. If disposing == false, the method has been called by the - runtime from inside the object finalizer and this method should not - reference other objects; in that case only unmanaged resources must - be referenced or disposed. - - - - indicates whether the Dispose method was invoked by user code. - - - - - Indicates whether the stream can be read. - - - The return value depends on whether the captive stream supports reading. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value depends on whether the captive stream supports writing. - - - - - Flush the stream. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the total bytes - written out, if used in writing, or the total bytes read in, if used in - reading. The count may refer to compressed bytes or uncompressed bytes, - depending on how you've used the stream. - - - - - Read and decompress data from the source stream. - - - - With a GZipStream, decompression is done through reading. - - - - - byte[] working = new byte[WORKING_BUFFER_SIZE]; - using (System.IO.Stream input = System.IO.File.OpenRead(_CompressedFile)) - { - using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) - { - using (var output = System.IO.File.Create(_DecompressedFile)) - { - int n; - while ((n= decompressor.Read(working, 0, working.Length)) !=0) - { - output.Write(working, 0, n); - } - } - } - } - - - The buffer into which the decompressed data should be placed. - the offset within that data array to put the first byte read. - the number of bytes to read. - the number of bytes actually read - - - - Calling this method always throws a . - - irrelevant; it will always throw! - irrelevant; it will always throw! - irrelevant! - - - - Calling this method always throws a . - - irrelevant; this method will always throw! - - - - Write data to the stream. - - - - - If you wish to use the GZipStream to compress data while writing, - you can create a GZipStream with CompressionMode.Compress, and a - writable output stream. Then call Write() on that GZipStream, - providing uncompressed data as input. The data sent to the output stream - will be the compressed form of the data written. - - - - A GZipStream can be used for Read() or Write(), but not - both. Writing implies compression. Reading implies decompression. - - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Compress a string into a byte array using GZip. - - - - Uncompress it with . - - - - - - - A string to compress. The string will first be encoded - using UTF8, then compressed. - - - The string in compressed form - - - - Compress a byte array into a new byte array using GZip. - - - - Uncompress it with . - - - - - - - A buffer to compress. - - - The data in compressed form - - - - Uncompress a GZip'ed byte array into a single string. - - - - - - - A buffer containing GZIP-compressed data. - - - The uncompressed string - - - - Uncompress a GZip'ed byte array into a byte array. - - - - - - - A buffer containing data that has been compressed with GZip. - - - The data in uncompressed form - - - - A class for compressing streams using the - Deflate algorithm with multiple threads. - - - - - This class performs DEFLATE compression through writing. For - more information on the Deflate algorithm, see IETF RFC 1951, - "DEFLATE Compressed Data Format Specification version 1.3." - - - - This class is similar to , except - that this class is for compression only, and this implementation uses an - approach that employs multiple worker threads to perform the DEFLATE. On - a multi-cpu or multi-core computer, the performance of this class can be - significantly higher than the single-threaded DeflateStream, particularly - for larger streams. How large? Anything over 10mb is a good candidate - for parallel compression. - - - - The tradeoff is that this class uses more memory and more CPU than the - vanilla DeflateStream, and also is less efficient as a compressor. For - large files the size of the compressed data stream can be less than 1% - larger than the size of a compressed data stream from the vanialla - DeflateStream. For smaller files the difference can be larger. The - difference will also be larger if you set the BufferSize to be lower than - the default value. Your mileage may vary. Finally, for small files, the - ParallelDeflateOutputStream can be much slower than the vanilla - DeflateStream, because of the overhead associated to using the thread - pool. - - - - - - - - Create a ParallelDeflateOutputStream. - - - - - This stream compresses data written into it via the DEFLATE - algorithm (see RFC 1951), and writes out the compressed byte stream. - - - - The instance will use the default compression level, the default - buffer sizes and the default number of threads and buffers per - thread. - - - - This class is similar to , - except that this implementation uses an approach that employs - multiple worker threads to perform the DEFLATE. On a multi-cpu or - multi-core computer, the performance of this class can be - significantly higher than the single-threaded DeflateStream, - particularly for larger streams. How large? Anything over 10mb is - a good candidate for parallel compression. - - - - - - - This example shows how to use a ParallelDeflateOutputStream to compress - data. It reads a file, compresses it, and writes the compressed data to - a second, output file. - - - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n= -1; - String outputFile = fileToCompress + ".compressed"; - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(outputFile)) - { - using (Stream compressor = new ParallelDeflateOutputStream(raw)) - { - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Dim outputFile As String = (fileToCompress & ".compressed") - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(outputFile) - Using compressor As Stream = New ParallelDeflateOutputStream(raw) - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - The stream to which compressed data will be written. - - - - Create a ParallelDeflateOutputStream using the specified CompressionLevel. - - - See the - constructor for example code. - - The stream to which compressed data will be written. - A tuning knob to trade speed for effectiveness. - - - - Create a ParallelDeflateOutputStream and specify whether to leave the captive stream open - when the ParallelDeflateOutputStream is closed. - - - See the - constructor for example code. - - The stream to which compressed data will be written. - - true if the application would like the stream to remain open after inflation/deflation. - - - - - Create a ParallelDeflateOutputStream and specify whether to leave the captive stream open - when the ParallelDeflateOutputStream is closed. - - - See the - constructor for example code. - - The stream to which compressed data will be written. - A tuning knob to trade speed for effectiveness. - - true if the application would like the stream to remain open after inflation/deflation. - - - - - Create a ParallelDeflateOutputStream using the specified - CompressionLevel and CompressionStrategy, and specifying whether to - leave the captive stream open when the ParallelDeflateOutputStream is - closed. - - - See the - constructor for example code. - - The stream to which compressed data will be written. - A tuning knob to trade speed for effectiveness. - - By tweaking this parameter, you may be able to optimize the compression for - data with particular characteristics. - - - true if the application would like the stream to remain open after inflation/deflation. - - - - - The ZLIB strategy to be used during compression. - - - - - - The maximum number of buffer pairs to use. - - - - - This property sets an upper limit on the number of memory buffer - pairs to create. The implementation of this stream allocates - multiple buffers to facilitate parallel compression. As each buffer - fills up, this stream uses - ThreadPool.QueueUserWorkItem() - to compress those buffers in a background threadpool thread. After a - buffer is compressed, it is re-ordered and written to the output - stream. - - - - A higher number of buffer pairs enables a higher degree of - parallelism, which tends to increase the speed of compression on - multi-cpu computers. On the other hand, a higher number of buffer - pairs also implies a larger memory consumption, more active worker - threads, and a higher cpu utilization for any compression. This - property enables the application to limit its memory consumption and - CPU utilization behavior depending on requirements. - - - - For each compression "task" that occurs in parallel, there are 2 - buffers allocated: one for input and one for output. This property - sets a limit for the number of pairs. The total amount of storage - space allocated for buffering will then be (N*S*2), where N is the - number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer - pairs per CPU core, so if your machine has 4 cores, and you retain - the default buffer size of 128k, then the - ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer - memory in total, or 4mb, in blocks of 128kb. If you then set this - property to 8, then the number will be 8 * 2 * 128kb of buffer - memory, or 2mb. - - - - CPU utilization will also go up with additional buffers, because a - larger number of buffer pairs allows a larger number of background - threads to compress in parallel. If you find that parallel - compression is consuming too much memory or CPU, you can adjust this - value downward. - - - - The default value is 16. Different values may deliver better or - worse results, depending on your priorities and the dynamic - performance characteristics of your storage and compute resources. - - - - This property is not the number of buffer pairs to use; it is an - upper limit. An illustration: Suppose you have an application that - uses the default value of this property (which is 16), and it runs - on a machine with 2 CPU cores. In that case, DotNetZip will allocate - 4 buffer pairs per CPU core, for a total of 8 pairs. The upper - limit specified by this property has no effect. - - - - The application can set this value at any time, but it is effective - only before the first call to Write(), which is when the buffers are - allocated. - - - - - - The size of the buffers used by the compressor threads. - - - - - The default buffer size is 128k. The application can set this value - at any time, but it is effective only before the first Write(). - - - - Larger buffer sizes implies larger memory consumption but allows - more efficient compression. Using smaller buffer sizes consumes less - memory but may result in less effective compression. For example, - using the default buffer size of 128k, the compression delivered is - within 1% of the compression delivered by the single-threaded . On the other hand, using a - BufferSize of 8k can result in a compressed data stream that is 5% - larger than that delivered by the single-threaded - DeflateStream. Excessively small buffer sizes can also cause - the speed of the ParallelDeflateOutputStream to drop, because of - larger thread scheduling overhead dealing with many many small - buffers. - - - - The total amount of storage space allocated for buffering will be - (N*S*2), where N is the number of buffer pairs, and S is the size of - each buffer (this property). There are 2 buffers used by the - compressor, one for input and one for output. By default, DotNetZip - allocates 4 buffer pairs per CPU core, so if your machine has 4 - cores, then the number of buffer pairs used will be 16. If you - accept the default value of this property, 128k, then the - ParallelDeflateOutputStream will use 16 * 2 * 128kb of buffer memory - in total, or 4mb, in blocks of 128kb. If you set this property to - 64kb, then the number will be 16 * 2 * 64kb of buffer memory, or - 2mb. - - - - - - - The CRC32 for the data that was written out, prior to compression. - - - This value is meaningful only after a call to Close(). - - - - - The total number of uncompressed bytes processed by the ParallelDeflateOutputStream. - - - This value is meaningful only after a call to Close(). - - - - - Write data to the stream. - - - - - - To use the ParallelDeflateOutputStream to compress data, create a - ParallelDeflateOutputStream with CompressionMode.Compress, passing a - writable output stream. Then call Write() on that - ParallelDeflateOutputStream, providing uncompressed data as input. The - data sent to the output stream will be the compressed form of the data - written. - - - - To decompress data, use the class. - - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Flush the stream. - - - - - Close the stream. - - - You must call Close on the stream to guarantee that all of the data written in has - been compressed, and the compressed data has been written out. - - - - Dispose the object - - - Because ParallelDeflateOutputStream is IDisposable, the - application must call this method when finished using the instance. - - - This method is generally called implicitly upon exit from - a using scope in C# (Using in VB). - - - - - The Dispose method - - indicates whether the Dispose method was invoked by user code. - - - - - Resets the stream for use with another stream. - - - Because the ParallelDeflateOutputStream is expensive to create, it - has been designed so that it can be recycled and re-used. You have - to call Close() on the stream first, then you can call Reset() on - it, to use it again on another stream. - - - - The new output stream for this era. - - - - - ParallelDeflateOutputStream deflater = null; - foreach (var inputFile in listOfFiles) - { - string outputFile = inputFile + ".compressed"; - using (System.IO.Stream input = System.IO.File.OpenRead(inputFile)) - { - using (var outStream = System.IO.File.Create(outputFile)) - { - if (deflater == null) - deflater = new ParallelDeflateOutputStream(outStream, - CompressionLevel.Best, - CompressionStrategy.Default, - true); - deflater.Reset(outStream); - - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - deflater.Write(buffer, 0, n); - } - } - } - } - - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream supports Read operations. - - - Always returns false. - - - - - Indicates whether the stream supports Write operations. - - - Returns true if the provided stream is writable. - - - - - Reading this property always throws a NotSupportedException. - - - - - Returns the current position of the output stream. - - - - Because the output gets written by a background thread, - the value may change asynchronously. Setting this - property always throws a NotSupportedException. - - - - - - This method always throws a NotSupportedException. - - - The buffer into which data would be read, IF THIS METHOD - ACTUALLY DID ANYTHING. - - - The offset within that data array at which to insert the - data that is read, IF THIS METHOD ACTUALLY DID - ANYTHING. - - - The number of bytes to write, IF THIS METHOD ACTUALLY DID - ANYTHING. - - nothing. - - - - This method always throws a NotSupportedException. - - - The offset to seek to.... - IF THIS METHOD ACTUALLY DID ANYTHING. - - - The reference specifying how to apply the offset.... IF - THIS METHOD ACTUALLY DID ANYTHING. - - nothing. It always throws. - - - - This method always throws a NotSupportedException. - - - The new value for the stream length.... IF - THIS METHOD ACTUALLY DID ANYTHING. - - - - - Map from a distance to a distance code. - - - No side effects. _dist_code[256] and _dist_code[257] are never used. - - - - - Describes how to flush the current deflate operation. - - - The different FlushType values are useful when using a Deflate in a streaming application. - - - - No flush at all. - - - Closes the current block, but doesn't flush it to - the output. Used internally only in hypothetical - scenarios. This was supposed to be removed by Zlib, but it is - still in use in some edge cases. - - - - - Use this during compression to specify that all pending output should be - flushed to the output buffer and the output should be aligned on a byte - boundary. You might use this in a streaming communication scenario, so that - the decompressor can get all input data available so far. When using this - with a ZlibCodec, AvailableBytesIn will be zero after the call if - enough output space has been provided before the call. Flushing will - degrade compression and so it should be used only when necessary. - - - - - Use this during compression to specify that all output should be flushed, as - with FlushType.Sync, but also, the compression state should be reset - so that decompression can restart from this point if previous compressed - data has been damaged or if random access is desired. Using - FlushType.Full too often can significantly degrade the compression. - - - - Signals the end of the compression/decompression stream. - - - - The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress. - - - - - None means that the data will be simply stored, with no change at all. - If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None - cannot be opened with the default zip reader. Use a different CompressionLevel. - - - - - Same as None. - - - - - The fastest but least effective compression. - - - - - A synonym for BestSpeed. - - - - - A little slower, but better, than level 1. - - - - - A little slower, but better, than level 2. - - - - - A little slower, but better, than level 3. - - - - - A little slower than level 4, but with better compression. - - - - - The default compression level, with a good balance of speed and compression efficiency. - - - - - A synonym for Default. - - - - - Pretty good compression! - - - - - Better compression than Level7! - - - - - The "best" compression, where best means greatest reduction in size of the input data stream. - This is also the slowest compression. - - - - - A synonym for BestCompression. - - - - - Describes options for how the compression algorithm is executed. Different strategies - work better on different sorts of data. The strategy parameter can affect the compression - ratio and the speed of compression but not the correctness of the compresssion. - - - - - The default strategy is probably the best for normal data. - - - - - The Filtered strategy is intended to be used most effectively with data produced by a - filter or predictor. By this definition, filtered data consists mostly of small - values with a somewhat random distribution. In this case, the compression algorithm - is tuned to compress them better. The effect of Filtered is to force more Huffman - coding and less string matching; it is a half-step between Default and HuffmanOnly. - - - - - Using HuffmanOnly will force the compressor to do Huffman encoding only, with no - string matching. - - - - - An enum to specify the direction of transcoding - whether to compress or decompress. - - - - - Used to specify that the stream should compress the data. - - - - - Used to specify that the stream should decompress the data. - - - - - A general purpose exception class for exceptions in the Zlib library. - - - - - The ZlibException class captures exception information generated - by the Zlib library. - - - - - This ctor collects a message attached to the exception. - - the message for the exception. - - - - Performs an unsigned bitwise right shift with the specified number - - Number to operate on - Ammount of bits to shift - The resulting number from the shift operation - - - - Reads a number of characters from the current source TextReader and writes - the data to the target array at the specified index. - - - The source TextReader to read from - Contains the array of characteres read from the source TextReader. - The starting index of the target array. - The maximum number of characters to read from the source TextReader. - - - The number of characters read. The number will be less than or equal to - count depending on the data available in the source TextReader. Returns -1 - if the end of the stream is reached. - - - - - Computes an Adler-32 checksum. - - - The Adler checksum is similar to a CRC checksum, but faster to compute, though less - reliable. It is used in producing RFC1950 compressed streams. The Adler checksum - is a required part of the "ZLIB" standard. Applications will almost never need to - use this class directly. - - - - - - - Calculates the Adler32 checksum. - - - - This is used within ZLIB. You probably don't need to use this directly. - - - - To compute an Adler32 checksum on a byte array: - - var adler = Adler.Adler32(0, null, 0, 0); - adler = Adler.Adler32(adler, buffer, index, length); - - - - - - Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951). - - - - This class compresses and decompresses data according to the Deflate algorithm - and optionally, the ZLIB format, as documented in RFC 1950 - ZLIB and RFC 1951 - DEFLATE. - - - - - The buffer from which data is taken. - - - - - An index into the InputBuffer array, indicating where to start reading. - - - - - The number of bytes available in the InputBuffer, starting at NextIn. - - - Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call. - The class will update this number as calls to Inflate/Deflate are made. - - - - - Total number of bytes read so far, through all calls to Inflate()/Deflate(). - - - - - Buffer to store output data. - - - - - An index into the OutputBuffer array, indicating where to start writing. - - - - - The number of bytes available in the OutputBuffer, starting at NextOut. - - - Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call. - The class will update this number as calls to Inflate/Deflate are made. - - - - - Total number of bytes written to the output so far, through all calls to Inflate()/Deflate(). - - - - - used for diagnostics, when something goes wrong! - - - - - The compression level to use in this codec. Useful only in compression mode. - - - - - The number of Window Bits to use. - - - This gauges the size of the sliding window, and hence the - compression effectiveness as well as memory consumption. It's best to just leave this - setting alone if you don't know what it is. The maximum value is 15 bits, which implies - a 32k window. - - - - - The compression strategy to use. - - - This is only effective in compression. The theory offered by ZLIB is that different - strategies could potentially produce significant differences in compression behavior - for different data sets. Unfortunately I don't have any good recommendations for how - to set it differently. When I tested changing the strategy I got minimally different - compression performance. It's best to leave this property alone if you don't have a - good feel for it. Or, you may want to produce a test harness that runs through the - different strategy options and evaluates them on different file types. If you do that, - let me know your results. - - - - - The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this. - - - - - Create a ZlibCodec. - - - If you use this default constructor, you will later have to explicitly call - InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress - or decompress. - - - - - Create a ZlibCodec that either compresses or decompresses. - - - Indicates whether the codec should compress (deflate) or decompress (inflate). - - - - - Initialize the inflation state. - - - It is not necessary to call this before using the ZlibCodec to inflate data; - It is implicitly called when you call the constructor. - - Z_OK if everything goes well. - - - - Initialize the inflation state with an explicit flag to - govern the handling of RFC1950 header bytes. - - - - By default, the ZLIB header defined in RFC 1950 is expected. If - you want to read a zlib stream you should specify true for - expectRfc1950Header. If you have a deflate stream, you will want to specify - false. It is only necessary to invoke this initializer explicitly if you - want to specify false. - - - whether to expect an RFC1950 header byte - pair when reading the stream of data to be inflated. - - Z_OK if everything goes well. - - - - Initialize the ZlibCodec for inflation, with the specified number of window bits. - - The number of window bits to use. If you need to ask what that is, - then you shouldn't be calling this initializer. - Z_OK if all goes well. - - - - Initialize the inflation state with an explicit flag to govern the handling of - RFC1950 header bytes. - - - - If you want to read a zlib stream you should specify true for - expectRfc1950Header. In this case, the library will expect to find a ZLIB - header, as defined in RFC - 1950, in the compressed stream. If you will be reading a DEFLATE or - GZIP stream, which does not have such a header, you will want to specify - false. - - - whether to expect an RFC1950 header byte pair when reading - the stream of data to be inflated. - The number of window bits to use. If you need to ask what that is, - then you shouldn't be calling this initializer. - Z_OK if everything goes well. - - - - Inflate the data in the InputBuffer, placing the result in the OutputBuffer. - - - You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and - AvailableBytesOut before calling this method. - - - - private void InflateBuffer() - { - int bufferSize = 1024; - byte[] buffer = new byte[bufferSize]; - ZlibCodec decompressor = new ZlibCodec(); - - Console.WriteLine("\n============================================"); - Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); - MemoryStream ms = new MemoryStream(DecompressedBytes); - - int rc = decompressor.InitializeInflate(); - - decompressor.InputBuffer = CompressedBytes; - decompressor.NextIn = 0; - decompressor.AvailableBytesIn = CompressedBytes.Length; - - decompressor.OutputBuffer = buffer; - - // pass 1: inflate - do - { - decompressor.NextOut = 0; - decompressor.AvailableBytesOut = buffer.Length; - rc = decompressor.Inflate(FlushType.None); - - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - throw new Exception("inflating: " + decompressor.Message); - - ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut); - } - while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); - - // pass 2: finish and flush - do - { - decompressor.NextOut = 0; - decompressor.AvailableBytesOut = buffer.Length; - rc = decompressor.Inflate(FlushType.Finish); - - if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) - throw new Exception("inflating: " + decompressor.Message); - - if (buffer.Length - decompressor.AvailableBytesOut > 0) - ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut); - } - while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); - - decompressor.EndInflate(); - } - - - - The flush to use when inflating. - Z_OK if everything goes well. - - - - Ends an inflation session. - - - Call this after successively calling Inflate(). This will cause all buffers to be flushed. - After calling this you cannot call Inflate() without a intervening call to one of the - InitializeInflate() overloads. - - Z_OK if everything goes well. - - - - I don't know what this does! - - Z_OK if everything goes well. - - - - Initialize the ZlibCodec for deflation operation. - - - The codec will use the MAX window bits and the default level of compression. - - - - int bufferSize = 40000; - byte[] CompressedBytes = new byte[bufferSize]; - byte[] DecompressedBytes = new byte[bufferSize]; - - ZlibCodec compressor = new ZlibCodec(); - - compressor.InitializeDeflate(CompressionLevel.Default); - - compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress); - compressor.NextIn = 0; - compressor.AvailableBytesIn = compressor.InputBuffer.Length; - - compressor.OutputBuffer = CompressedBytes; - compressor.NextOut = 0; - compressor.AvailableBytesOut = CompressedBytes.Length; - - while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize) - { - compressor.Deflate(FlushType.None); - } - - while (true) - { - int rc= compressor.Deflate(FlushType.Finish); - if (rc == ZlibConstants.Z_STREAM_END) break; - } - - compressor.EndDeflate(); - - - - Z_OK if all goes well. You generally don't need to check the return code. - - - - Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel. - - - The codec will use the maximum window bits (15) and the specified - CompressionLevel. It will emit a ZLIB stream as it compresses. - - The compression level for the codec. - Z_OK if all goes well. - - - - Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, - and the explicit flag governing whether to emit an RFC1950 header byte pair. - - - The codec will use the maximum window bits (15) and the specified CompressionLevel. - If you want to generate a zlib stream, you should specify true for - wantRfc1950Header. In this case, the library will emit a ZLIB - header, as defined in RFC - 1950, in the compressed stream. - - The compression level for the codec. - whether to emit an initial RFC1950 byte pair in the compressed stream. - Z_OK if all goes well. - - - - Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, - and the specified number of window bits. - - - The codec will use the specified number of window bits and the specified CompressionLevel. - - The compression level for the codec. - the number of window bits to use. If you don't know what this means, don't use this method. - Z_OK if all goes well. - - - - Initialize the ZlibCodec for deflation operation, using the specified - CompressionLevel, the specified number of window bits, and the explicit flag - governing whether to emit an RFC1950 header byte pair. - - - The compression level for the codec. - whether to emit an initial RFC1950 byte pair in the compressed stream. - the number of window bits to use. If you don't know what this means, don't use this method. - Z_OK if all goes well. - - - - Deflate one batch of data. - - - You must have set InputBuffer and OutputBuffer before calling this method. - - - - private void DeflateBuffer(CompressionLevel level) - { - int bufferSize = 1024; - byte[] buffer = new byte[bufferSize]; - ZlibCodec compressor = new ZlibCodec(); - - Console.WriteLine("\n============================================"); - Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); - MemoryStream ms = new MemoryStream(); - - int rc = compressor.InitializeDeflate(level); - - compressor.InputBuffer = UncompressedBytes; - compressor.NextIn = 0; - compressor.AvailableBytesIn = UncompressedBytes.Length; - - compressor.OutputBuffer = buffer; - - // pass 1: deflate - do - { - compressor.NextOut = 0; - compressor.AvailableBytesOut = buffer.Length; - rc = compressor.Deflate(FlushType.None); - - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - throw new Exception("deflating: " + compressor.Message); - - ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut); - } - while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); - - // pass 2: finish and flush - do - { - compressor.NextOut = 0; - compressor.AvailableBytesOut = buffer.Length; - rc = compressor.Deflate(FlushType.Finish); - - if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) - throw new Exception("deflating: " + compressor.Message); - - if (buffer.Length - compressor.AvailableBytesOut > 0) - ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut); - } - while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); - - compressor.EndDeflate(); - - ms.Seek(0, SeekOrigin.Begin); - CompressedBytes = new byte[compressor.TotalBytesOut]; - ms.Read(CompressedBytes, 0, CompressedBytes.Length); - } - - - whether to flush all data as you deflate. Generally you will want to - use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to - flush everything. - - Z_OK if all goes well. - - - - End a deflation session. - - - Call this after making a series of one or more calls to Deflate(). All buffers are flushed. - - Z_OK if all goes well. - - - - Reset a codec for another deflation session. - - - Call this to reset the deflation state. For example if a thread is deflating - non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first - block and before the next Deflate(None) of the second block. - - Z_OK if all goes well. - - - - Set the CompressionStrategy and CompressionLevel for a deflation session. - - the level of compression to use. - the strategy to use for compression. - Z_OK if all goes well. - - - - Set the dictionary to be used for either Inflation or Deflation. - - The dictionary bytes to use. - Z_OK if all goes well. - - - - Set the dictionary to be used for either Inflation or Deflation unconditionally. - - Decoding a MSZip file requires the dictionary state to be set unconditionally - at the end of each block to the previous decoded data - The dictionary bytes to use. - Z_OK if all goes well. - - - - A bunch of constants used in the Zlib interface. - - - - - The maximum number of window bits for the Deflate algorithm. - - - - - The default number of window bits for the Deflate algorithm. - - - - - indicates everything is A-OK - - - - - Indicates that the last operation reached the end of the stream. - - - - - The operation ended in need of a dictionary. - - - - - There was an error with the stream - not enough data, not open and readable, etc. - - - - - There was an error with the data - not enough data, bad data, etc. - - - - - There was an error with the working buffer. - - - - - The size of the working buffer used in the ZlibCodec class. - - - - - The minimum size of the working buffer used in the ZlibCodec class. - - - - - Represents a Zlib stream for compression or decompression. - - - - - The ZlibStream is a Decorator on a . It adds ZLIB compression or decompression to any - stream. - - - Using this stream, applications can compress or decompress data via - stream Read() and Write() operations. Either compresssion or - decompression can occur through either reading or writing. The compression - format used is ZLIB, which is documented in IETF RFC 1950, "ZLIB Compressed - Data Format Specification version 3.3". This implementation of ZLIB always uses - DEFLATE as the compression method. (see IETF RFC 1951, "DEFLATE - Compressed Data Format Specification version 1.3.") - - - The ZLIB format allows for varying compression methods, window sizes, and dictionaries. - This implementation always uses the DEFLATE compression method, a preset dictionary, - and 15 window bits by default. - - - - This class is similar to , except that it adds the - RFC1950 header and trailer bytes to a compressed stream when compressing, or expects - the RFC1950 header and trailer bytes when decompressing. It is also similar to the - . - - - - - - - - Create a ZlibStream using the specified CompressionMode. - - - - - When mode is CompressionMode.Compress, the ZlibStream - will use the default compression level. The "captive" stream will be - closed when the ZlibStream is closed. - - - - - - This example uses a ZlibStream to compress a file, and writes the - compressed data to another file. - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(fileToCompress + ".zlib")) - { - using (Stream compressor = new ZlibStream(raw, CompressionMode.Compress)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(fileToCompress & ".zlib") - Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - - The stream which will be read or written. - Indicates whether the ZlibStream will compress or decompress. - - - - Create a ZlibStream using the specified CompressionMode and - the specified CompressionLevel. - - - - - - When mode is CompressionMode.Decompress, the level parameter is ignored. - The "captive" stream will be closed when the ZlibStream is closed. - - - - - - This example uses a ZlibStream to compress data from a file, and writes the - compressed data to another file. - - - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (var raw = System.IO.File.Create(fileToCompress + ".zlib")) - { - using (Stream compressor = new ZlibStream(raw, - CompressionMode.Compress, - CompressionLevel.BestCompression)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - } - - - - Using input As Stream = File.OpenRead(fileToCompress) - Using raw As FileStream = File.Create(fileToCompress & ".zlib") - Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - End Using - - - - The stream to be read or written while deflating or inflating. - Indicates whether the ZlibStream will compress or decompress. - A tuning knob to trade speed for effectiveness. - - - - Create a ZlibStream using the specified CompressionMode, and - explicitly specify whether the captive stream should be left open after - Deflation or Inflation. - - - - - - When mode is CompressionMode.Compress, the ZlibStream will use - the default compression level. - - - - This constructor allows the application to request that the captive stream - remain open after the deflation or inflation occurs. By default, after - Close() is called on the stream, the captive stream is also - closed. In some cases this is not desired, for example if the stream is a - that will be re-read after - compression. Specify true for the parameter to leave the stream - open. - - - - See the other overloads of this constructor for example code. - - - - - The stream which will be read or written. This is called the - "captive" stream in other places in this documentation. - Indicates whether the ZlibStream will compress or decompress. - true if the application would like the stream to remain - open after inflation/deflation. - - - - Create a ZlibStream using the specified CompressionMode - and the specified CompressionLevel, and explicitly specify - whether the stream should be left open after Deflation or Inflation. - - - - - - This constructor allows the application to request that the captive - stream remain open after the deflation or inflation occurs. By - default, after Close() is called on the stream, the captive - stream is also closed. In some cases this is not desired, for example - if the stream is a that will be - re-read after compression. Specify true for the parameter to leave the stream open. - - - - When mode is CompressionMode.Decompress, the level parameter is - ignored. - - - - - - - This example shows how to use a ZlibStream to compress the data from a file, - and store the result into another file. The filestream remains open to allow - additional data to be written to it. - - - using (var output = System.IO.File.Create(fileToCompress + ".zlib")) - { - using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) - { - using (Stream compressor = new ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true)) - { - byte[] buffer = new byte[WORKING_BUFFER_SIZE]; - int n; - while ((n= input.Read(buffer, 0, buffer.Length)) != 0) - { - compressor.Write(buffer, 0, n); - } - } - } - // can write additional data to the output stream here - } - - - Using output As FileStream = File.Create(fileToCompress & ".zlib") - Using input As Stream = File.OpenRead(fileToCompress) - Using compressor As Stream = New ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True) - Dim buffer As Byte() = New Byte(4096) {} - Dim n As Integer = -1 - Do While (n <> 0) - If (n > 0) Then - compressor.Write(buffer, 0, n) - End If - n = input.Read(buffer, 0, buffer.Length) - Loop - End Using - End Using - ' can write additional data to the output stream here. - End Using - - - - The stream which will be read or written. - - Indicates whether the ZlibStream will compress or decompress. - - - true if the application would like the stream to remain open after - inflation/deflation. - - - - A tuning knob to trade speed for effectiveness. This parameter is - effective only when mode is CompressionMode.Compress. - - - - - This property sets the flush behavior on the stream. - Sorry, though, not sure exactly how to describe all the various settings. - - - - - The size of the working buffer for the compression codec. - - - - - The working buffer is used for all stream operations. The default size is - 1024 bytes. The minimum size is 128 bytes. You may get better performance - with a larger buffer. Then again, you might not. You would have to test - it. - - - - Set this before the first call to Read() or Write() on the - stream. If you try to set it afterwards, it will throw. - - - - - Returns the total number of bytes input so far. - - - Returns the total number of bytes output so far. - - - - Dispose the stream. - - - - This may or may not result in a Close() call on the captive - stream. See the constructors that have a leaveOpen parameter - for more information. - - - This method may be invoked in two distinct scenarios. If disposing - == true, the method has been called directly or indirectly by a - user's code, for example via the public Dispose() method. In this - case, both managed and unmanaged resources can be referenced and - disposed. If disposing == false, the method has been called by the - runtime from inside the object finalizer and this method should not - reference other objects; in that case only unmanaged resources must - be referenced or disposed. - - - - indicates whether the Dispose method was invoked by user code. - - - - - Indicates whether the stream can be read. - - - The return value depends on whether the captive stream supports reading. - - - - - Indicates whether the stream supports Seek operations. - - - Always returns false. - - - - - Indicates whether the stream can be written. - - - The return value depends on whether the captive stream supports writing. - - - - - Flush the stream. - - - - - Reading this property always throws a . - - - - - The position of the stream pointer. - - - - Setting this property always throws a . Reading will return the total bytes - written out, if used in writing, or the total bytes read in, if used in - reading. The count may refer to compressed bytes or uncompressed bytes, - depending on how you've used the stream. - - - - - Read data from the stream. - - - - - - If you wish to use the ZlibStream to compress data while reading, - you can create a ZlibStream with CompressionMode.Compress, - providing an uncompressed data stream. Then call Read() on that - ZlibStream, and the data read will be compressed. If you wish to - use the ZlibStream to decompress data while reading, you can create - a ZlibStream with CompressionMode.Decompress, providing a - readable compressed data stream. Then call Read() on that - ZlibStream, and the data will be decompressed as it is read. - - - - A ZlibStream can be used for Read() or Write(), but - not both. - - - - - - The buffer into which the read data should be placed. - - - the offset within that data array to put the first byte read. - - the number of bytes to read. - - the number of bytes read - - - - Calling this method always throws a . - - - The offset to seek to.... - IF THIS METHOD ACTUALLY DID ANYTHING. - - - The reference specifying how to apply the offset.... IF - THIS METHOD ACTUALLY DID ANYTHING. - - - nothing. This method always throws. - - - - Calling this method always throws a . - - - The new value for the stream length.... IF - THIS METHOD ACTUALLY DID ANYTHING. - - - - - Write data to the stream. - - - - - - If you wish to use the ZlibStream to compress data while writing, - you can create a ZlibStream with CompressionMode.Compress, - and a writable output stream. Then call Write() on that - ZlibStream, providing uncompressed data as input. The data sent to - the output stream will be the compressed form of the data written. If you - wish to use the ZlibStream to decompress data while writing, you - can create a ZlibStream with CompressionMode.Decompress, and a - writable output stream. Then call Write() on that stream, - providing previously compressed data. The data sent to the output stream - will be the decompressed form of the data written. - - - - A ZlibStream can be used for Read() or Write(), but not both. - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Compress a string into a byte array using ZLIB. - - - - Uncompress it with . - - - - - - - - A string to compress. The string will first be encoded - using UTF8, then compressed. - - - The string in compressed form - - - - Compress a byte array into a new byte array using ZLIB. - - - - Uncompress it with . - - - - - - - A buffer to compress. - - - The data in compressed form - - - - Uncompress a ZLIB-compressed byte array into a single string. - - - - - - - A buffer containing ZLIB-compressed data. - - - The uncompressed string - - - - Uncompress a ZLIB-compressed byte array into a byte array. - - - - - - - A buffer containing ZLIB-compressed data. - - - The data in uncompressed form - - - - This class exposes a set of COM-accessible wrappers for static - methods available on the ZipFile class. You don't need this - class unless you are using DotNetZip from a COM environment. - - - - - A wrapper for ZipFile.IsZipFile(string) - - The filename to of the zip file to check. - true if the file contains a valid zip file. - - - - A wrapper for ZipFile.IsZipFile(string, bool) - - - We cannot use "overloaded" Method names in COM interop. - So, here, we use a unique name. - - The filename to of the zip file to check. - true if the file contains a valid zip file. - - - - A wrapper for ZipFile.CheckZip(string) - - The filename to of the zip file to check. - - true if the named zip file checks OK. Otherwise, false. - - - - A COM-friendly wrapper for the static method . - - - The filename to of the zip file to check. - - The password to check. - - true if the named zip file checks OK. Otherwise, false. - - - - A wrapper for ZipFile.FixZipDirectory(string) - - The filename to of the zip file to fix. - - - - A wrapper for ZipFile.LibraryVersion - - - the version number on the DotNetZip assembly, formatted as a string. - - - - - An enum that provides the various encryption algorithms supported by this - library. - - - - - - PkzipWeak implies the use of Zip 2.0 encryption, which is known to be - weak and subvertible. - - - - A note on interoperability: Values of PkzipWeak and None are - specified in PKWARE's zip - specification, and are considered to be "standard". Zip archives - produced using these options will be interoperable with many other zip tools - and libraries, including Windows Explorer. - - - - Values of WinZipAes128 and WinZipAes256 are not part of the Zip - specification, but rather imply the use of a vendor-specific extension from - WinZip. If you want to produce interoperable Zip archives, do not use these - values. For example, if you produce a zip archive using WinZipAes256, you - will be able to open it in Windows Explorer on Windows XP and Vista, but you - will not be able to extract entries; trying this will lead to an "unspecified - error". For this reason, some people have said that a zip archive that uses - WinZip's AES encryption is not actually a zip archive at all. A zip archive - produced this way will be readable with the WinZip tool (Version 11 and - beyond). - - - - There are other third-party tools and libraries, both commercial and - otherwise, that support WinZip's AES encryption. These will be able to read - AES-encrypted zip archives produced by DotNetZip, and conversely applications - that use DotNetZip to read zip archives will be able to read AES-encrypted - archives produced by those tools or libraries. Consult the documentation for - those other tools and libraries to find out if WinZip's AES encryption is - supported. - - - - In case you care: According to the WinZip specification, the - actual AES key used is derived from the via an - algorithm that complies with RFC 2898, using an iteration - count of 1000. The algorithm is sometimes referred to as PBKDF2, which stands - for "Password Based Key Derivation Function #2". - - - - A word about password strength and length: The AES encryption technology is - very good, but any system is only as secure as the weakest link. If you want - to secure your data, be sure to use a password that is hard to guess. To make - it harder to guess (increase its "entropy"), you should make it longer. If - you use normal characters from an ASCII keyboard, a password of length 20 will - be strong enough that it will be impossible to guess. For more information on - that, I'd encourage you to read this - article. - - - - - - - No encryption at all. - - - - - Traditional or Classic pkzip encryption. - - - - - WinZip AES encryption (128 key bits). - - - - - WinZip AES encryption (256 key bits). - - - - - An encryption algorithm that is not supported by DotNetZip. - - - - - Delegate in which the application writes the ZipEntry content for the named entry. - - - The name of the entry that must be written. - The stream to which the entry data should be written. - - - When you add an entry and specify a WriteDelegate, via , the application - code provides the logic that writes the entry data directly into the zip file. - - - - - This example shows how to define a WriteDelegate that obtains a DataSet, and then - writes the XML for the DataSet into the zip archive. There's no need to - save the XML to a disk file first. - - - private void WriteEntry (String filename, Stream output) - { - DataSet ds1 = ObtainDataSet(); - ds1.WriteXml(output); - } - - private void Run() - { - using (var zip = new ZipFile()) - { - zip.AddEntry(zipEntryName, WriteEntry); - zip.Save(zipFileName); - } - } - - - - Private Sub WriteEntry (ByVal filename As String, ByVal output As Stream) - DataSet ds1 = ObtainDataSet() - ds1.WriteXml(stream) - End Sub - - Public Sub Run() - Using zip = New ZipFile - zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry)) - zip.Save(zipFileName) - End Using - End Sub - - - - - - - Delegate in which the application opens the stream, just-in-time, for the named entry. - - - - The name of the ZipEntry that the application should open the stream for. - - - - When you add an entry via , the application code provides the logic that - opens and closes the stream for the given ZipEntry. - - - - - - - Delegate in which the application closes the stream, just-in-time, for the named entry. - - - - The name of the ZipEntry that the application should close the stream for. - - - The stream to be closed. - - - When you add an entry via , the application code provides the logic that - opens and closes the stream for the given ZipEntry. - - - - - - - Delegate for the callback by which the application tells the - library the CompressionLevel to use for a file. - - - - - Using this callback, the application can, for example, specify that - previously-compressed files (.mp3, .png, .docx, etc) should use a - CompressionLevel of None, or can set the compression level based - on any other factor. - - - - - - - In an EventArgs type, indicates which sort of progress event is being - reported. - - - There are events for reading, events for saving, and events for - extracting. This enumeration allows a single EventArgs type to be sued to - describe one of multiple subevents. For example, a SaveProgress event is - invoked before, after, and during the saving of a single entry. The value - of an enum with this type, specifies which event is being triggered. The - same applies to Extraction, Reading and Adding events. - - - - - Indicates that a Add() operation has started. - - - - - Indicates that an individual entry in the archive has been added. - - - - - Indicates that a Add() operation has completed. - - - - - Indicates that a Read() operation has started. - - - - - Indicates that an individual entry in the archive is about to be read. - - - - - Indicates that an individual entry in the archive has just been read. - - - - - Indicates that a Read() operation has completed. - - - - - The given event reports the number of bytes read so far - during a Read() operation. - - - - - Indicates that a Save() operation has started. - - - - - Indicates that an individual entry in the archive is about to be written. - - - - - Indicates that an individual entry in the archive has just been saved. - - - - - Indicates that a Save() operation has completed. - - - - - Indicates that the zip archive has been created in a - temporary location during a Save() operation. - - - - - Indicates that the temporary file is about to be renamed to the final archive - name during a Save() operation. - - - - - Indicates that the temporary file is has just been renamed to the final archive - name during a Save() operation. - - - - - Indicates that the self-extracting archive has been compiled - during a Save() operation. - - - - - The given event is reporting the number of source bytes that have run through the compressor so far - during a Save() operation. - - - - - Indicates that an entry is about to be extracted. - - - - - Indicates that an entry has just been extracted. - - - - - Indicates that extraction of an entry would overwrite an existing - filesystem file. You must use - - ExtractExistingFileAction.InvokeExtractProgressEvent in the call - to ZipEntry.Extract() in order to receive this event. - - - - - The given event is reporting the number of bytes written so far for - the current entry during an Extract() operation. - - - - - Indicates that an ExtractAll operation is about to begin. - - - - - Indicates that an ExtractAll operation has completed. - - - - - Indicates that an error has occurred while saving a zip file. - This generally means the file cannot be opened, because it has been - removed, or because it is locked by another process. It can also - mean that the file cannot be Read, because of a range lock conflict. - - - - - Provides information about the progress of a save, read, or extract operation. - This is a base class; you will probably use one of the classes derived from this one. - - - - - The total number of entries to be saved or extracted. - - - - - The name of the last entry saved or extracted. - - - - - In an event handler, set this to cancel the save or extract - operation that is in progress. - - - - - The type of event being reported. - - - - - Returns the archive name associated to this event. - - - - - The number of bytes read or written so far for this entry. - - - - - Total number of bytes that will be read or written for this entry. - This number will be -1 if the value cannot be determined. - - - - - Provides information about the progress of a Read operation. - - - - - Provides information about the progress of a Add operation. - - - - - Provides information about the progress of a save operation. - - - - - Constructor for the SaveProgressEventArgs. - - the name of the zip archive. - whether this is before saving the entry, or after - The total number of entries in the zip archive. - Number of entries that have been saved. - The entry involved in the event. - - - - Number of entries saved so far. - - - - - Provides information about the progress of the extract operation. - - - - - Constructor for the ExtractProgressEventArgs. - - the name of the zip archive. - whether this is before saving the entry, or after - The total number of entries in the zip archive. - Number of entries that have been extracted. - The entry involved in the event. - The location to which entries are extracted. - - - - Number of entries extracted so far. This is set only if the - EventType is Extracting_BeforeExtractEntry or Extracting_AfterExtractEntry, and - the Extract() is occurring witin the scope of a call to ExtractAll(). - - - - - Returns the extraction target location, a filesystem path. - - - - - Provides information about the an error that occurred while zipping. - - - - - Returns the exception that occurred, if any. - - - - - Returns the name of the file that caused the exception, if any. - - - - - Issued when an ZipEntry.ExtractWithPassword() method is invoked - with an incorrect password. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - The innerException for this exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - Indicates that a read was attempted on a stream, and bad or incomplete data was - received. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - The innerException for this exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - Issued when an CRC check fails upon extracting an entry from a zip archive. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - Issued when errors occur saving a self-extracting archive. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - Indicates that an operation was attempted on a ZipFile which was not possible - given the state of the instance. For example, if you call Save() on a ZipFile - which has no filename set, you can get this exception. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - The innerException for this exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - Base class for all exceptions defined by and throw by the Zip library. - - - - - Default ctor. - - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The message in the exception. - The innerException for this exception. - - - - Come on, you know how exceptions work. Why are you looking at this documentation? - - The serialization info for the exception. - The streaming context from which to deserialize. - - - - An enum for the options when extracting an entry would overwrite an existing file. - - - - - This enum describes the actions that the library can take when an - Extract() or ExtractWithPassword() method is called to extract an - entry to a filesystem, and the extraction would overwrite an existing filesystem - file. - - - - - - - Throw an exception when extraction would overwrite an existing file. (For - COM clients, this is a 0 (zero).) - - - - - When extraction would overwrite an existing file, overwrite the file silently. - The overwrite will happen even if the target file is marked as read-only. - (For COM clients, this is a 1.) - - - - - When extraction would overwrite an existing file, don't overwrite the file, silently. - (For COM clients, this is a 2.) - - - - - When extraction would overwrite an existing file, invoke the ExtractProgress - event, using an event type of . In - this way, the application can decide, just-in-time, whether to overwrite the - file. For example, a GUI application may wish to pop up a dialog to allow - the user to choose. You may want to examine the property before making - the decision. If, after your processing in the Extract progress event, you - want to NOT extract the file, set - on the ZipProgressEventArgs.CurrentEntry to DoNotOverwrite. - If you do want to extract the file, set ZipEntry.ExtractExistingFile - to OverwriteSilently. If you want to cancel the Extraction, set - ZipProgressEventArgs.Cancel to true. Cancelling differs from using - DoNotOverwrite in that a cancel will not extract any further entries, if - there are any. (For COM clients, the value of this enum is a 3.) - - - - - Collects general purpose utility methods. - - - - private null constructor - - - - Utility routine for transforming path names from filesystem format (on Windows that means backslashes) to - a format suitable for use within zipfiles. This means trimming the volume letter and colon (if any) And - swapping backslashes for forward slashes. - - source path. - transformed path - - - - Sanitize paths in zip files. This means making sure that relative paths in a zip file don't go outside - the top directory. Entries like something/../../../../Temp/evil.txt get sanitized to Temp/evil.txt - when extracting - - A path with forward slashes as directory separator - sanitized path - - - - Finds a signature in the zip stream. This is useful for finding - the end of a zip entry, for example, or the beginning of the next ZipEntry. - - - - - Scans through 64k at a time. - - - - If the method fails to find the requested signature, the stream Position - after completion of this method is unchanged. If the method succeeds in - finding the requested signature, the stream position after completion is - direct AFTER the signature found in the stream. - - - - The stream to search - The 4-byte signature to find - The number of bytes read - - - - Create a pseudo-random filename, suitable for use as a temporary - file, and open it. - - - - This method produces a filename of the form - DotNetZip-xxxxxxxx.tmp, where xxxxxxxx is replaced by randomly - chosen characters, and creates that file. - - - - - - Workitem 7889: handle ERROR_LOCK_VIOLATION during read - - - This could be gracefully handled with an extension attribute, but - This assembly used to be built for .NET 2.0, so could not use - extension methods. - - - - - A decorator stream. It wraps another stream, and performs bookkeeping - to keep track of the stream Position. - - - - In some cases, it is not possible to get the Position of a stream, let's - say, on a write-only output stream like ASP.NET's - Response.OutputStream, or on a different write-only stream - provided as the destination for the zip by the application. In this - case, programmers can use this counting stream to count the bytes read - or written. - - - Consider the scenario of an application that saves a self-extracting - archive (SFX), that uses a custom SFX stub. - - - Saving to a filesystem file, the application would open the - filesystem file (getting a FileStream), save the custom sfx stub - into it, and then call ZipFile.Save(), specifying the same - FileStream. ZipFile.Save() does the right thing for the zipentry - offsets, by inquiring the Position of the FileStream before writing - any data, and then adding that initial offset into any ZipEntry - offsets in the zip directory. Everything works fine. - - - Now suppose the application is an ASPNET application and it saves - directly to Response.OutputStream. It's not possible for DotNetZip to - inquire the Position, so the offsets for the SFX will be wrong. - - - The workaround is for the application to use this class to wrap - HttpResponse.OutputStream, then write the SFX stub and the ZipFile - into that wrapper stream. Because ZipFile.Save() can inquire the - Position, it will then do the right thing with the offsets. - - - - - - The constructor. - - The underlying stream - - - - Gets the wrapped stream. - - - - - The count of bytes written out to the stream. - - - - - the count of bytes that have been read from the stream. - - - - - Adjust the byte count on the stream. - - - - the number of bytes to subtract from the count. - - - - - Subtract delta from the count of bytes written to the stream. - This is necessary when seeking back, and writing additional data, - as happens in some cases when saving Zip files. - - - - - - The read method. - - The buffer to hold the data read from the stream. - the offset within the buffer to copy the first byte read. - the number of bytes to read. - the number of bytes read, after decryption and decompression. - - - - Write data into the stream. - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Whether the stream can be read. - - - - - Whether it is possible to call Seek() on the stream. - - - - - Whether it is possible to call Write() on the stream. - - - - - Flushes the underlying stream. - - - - - The length of the underlying stream. - - - - - Returns the sum of number of bytes written, plus the initial - offset before writing. - - - - - The Position of the stream. - - - - - Seek in the stream. - - the offset point to seek to - the reference point from which to seek - The new position - - - - Set the length of the underlying stream. Be careful with this! - - - the length to set on the underlying stream. - - - - This is a helper class supporting WinZip AES encryption. - This class is intended for use only by the DotNetZip library. - - - - Most uses of the DotNetZip library will not involve direct calls into - the WinZipAesCrypto class. Instead, the WinZipAesCrypto class is - instantiated and used by the ZipEntry() class when WinZip AES - encryption or decryption on an entry is employed. - - - - - A stream that encrypts as it writes, or decrypts as it reads. The - Crypto is AES in CTR (counter) mode, which is compatible with the AES - encryption employed by WinZip 12.0. - - - - The AES/CTR encryption protocol used by WinZip works like this: - - - start with a counter, initialized to zero. - - - to encrypt, take the data by 16-byte blocks. For each block: - - apply the transform to the counter - - increement the counter - - XOR the result of the transform with the plaintext to - get the ciphertext. - - compute the mac on the encrypted bytes - - when finished with all blocks, store the computed MAC. - - - to decrypt, take the data by 16-byte blocks. For each block: - - compute the mac on the encrypted bytes, - - apply the transform to the counter - - increement the counter - - XOR the result of the transform with the ciphertext to - get the plaintext. - - when finished with all blocks, compare the computed MAC against - the stored MAC - - - - - - - The constructor. - - The underlying stream - To either encrypt or decrypt. - The pre-initialized WinZipAesCrypto object. - The maximum number of bytes to read from the stream. - - - - Returns the final HMAC-SHA1-80 for the data that was encrypted. - - - - - Close the stream. - - - - - Returns true if the stream can be read. - - - - - Always returns false. - - - - - Returns true if the CryptoMode is Encrypt. - - - - - Flush the content in the stream. - - - - - Getting this property throws a NotImplementedException. - - - - - Getting or Setting this property throws a NotImplementedException. - - - - - This method throws a NotImplementedException. - - - - - This method throws a NotImplementedException. - - - - - This class implements the "traditional" or "classic" PKZip encryption, - which today is considered to be weak. On the other hand it is - ubiquitous. This class is intended for use only by the DotNetZip - library. - - - - Most uses of the DotNetZip library will not involve direct calls into - the ZipCrypto class. Instead, the ZipCrypto class is instantiated and - used by the ZipEntry() class when encryption or decryption on an entry - is employed. If for some reason you really wanted to use a weak - encryption algorithm in some other application, you might use this - library. But you would be much better off using one of the built-in - strong encryption libraries in the .NET Framework, like the AES - algorithm or SHA. - - - - - The default constructor for ZipCrypto. - - - - This class is intended for internal use by the library only. It's - probably not useful to you. Seriously. Stop reading this - documentation. It's a waste of your time. Go do something else. - Check the football scores. Go get an ice cream with a friend. - Seriously. - - - - - - From AppNote.txt: - unsigned char decrypt_byte() - local unsigned short temp - temp :=- Key(2) | 2 - decrypt_byte := (temp * (temp ^ 1)) bitshift-right 8 - end decrypt_byte - - - - - Call this method on a cipher text to render the plaintext. You must - first initialize the cipher with a call to InitCipher. - - - - - var cipher = new ZipCrypto(); - cipher.InitCipher(Password); - // Decrypt the header. This has a side effect of "further initializing the - // encryption keys" in the traditional zip encryption. - byte[] DecryptedMessage = cipher.DecryptMessage(EncryptedMessage); - - - - The encrypted buffer. - - The number of bytes to encrypt. - Should be less than or equal to CipherText.Length. - - - The plaintext. - - - - This is the converse of DecryptMessage. It encrypts the plaintext - and produces a ciphertext. - - - The plain text buffer. - - - The number of bytes to encrypt. - Should be less than or equal to plainText.Length. - - - The ciphertext. - - - - This initializes the cipher with the given password. - See AppNote.txt for details. - - - - The passphrase for encrypting or decrypting with this cipher. - - - - - Step 1 - Initializing the encryption keys - ----------------------------------------- - Start with these keys: - Key(0) := 305419896 (0x12345678) - Key(1) := 591751049 (0x23456789) - Key(2) := 878082192 (0x34567890) - - Then, initialize the keys with a password: - - loop for i from 0 to length(password)-1 - update_keys(password(i)) - end loop - - Where update_keys() is defined as: - - update_keys(char): - Key(0) := crc32(key(0),char) - Key(1) := Key(1) + (Key(0) bitwiseAND 000000ffH) - Key(1) := Key(1) * 134775813 + 1 - Key(2) := crc32(key(2),key(1) rightshift 24) - end update_keys - - Where crc32(old_crc,char) is a routine that given a CRC value and a - character, returns an updated CRC value after applying the CRC-32 - algorithm described elsewhere in this document. - - - - - After the keys are initialized, then you can use the cipher to - encrypt the plaintext. - - - - Essentially we encrypt the password with the keys, then discard the - ciphertext for the password. This initializes the keys for later use. - - - - - - - A Stream for reading and concurrently decrypting data from a zip file, - or for writing and concurrently encrypting data to a zip file. - - - - The constructor. - The underlying stream - To either encrypt or decrypt. - The pre-initialized ZipCrypto object. - - - - Represents a single entry in a ZipFile. Typically, applications get a ZipEntry - by enumerating the entries within a ZipFile, or by adding an entry to a ZipFile. - - - - - True if the referenced entry is a directory. - - - - - Provides a human-readable string with information about the ZipEntry. - - - - - Reads one entry from the zip directory structure in the zip file. - - - - The zipfile for which a directory entry will be read. From this param, the - method gets the ReadStream and the expected text encoding - (ProvisionalAlternateEncoding) which is used if the entry is not marked - UTF-8. - - - - a list of previously seen entry names; used to prevent duplicates. - - - the entry read from the archive. - - - - Returns true if the passed-in value is a valid signature for a ZipDirEntry. - - the candidate 4-byte signature value. - true, if the signature is valid according to the PKWare spec. - - - - Default constructor. - - - Applications should never need to call this directly. It is exposed to - support COM Automation environments. - - - - - The time and date at which the file indicated by the ZipEntry was - last modified. - - - - - The DotNetZip library sets the LastModified value for an entry, equal to - the Last Modified time of the file in the filesystem. If an entry is - added from a stream, the library uses System.DateTime.Now for this - value, for the given entry. - - - - This property allows the application to retrieve and possibly set the - LastModified value on an entry, to an arbitrary value. values with a - setting of DateTimeKind.Unspecified are taken to be expressed as - DateTimeKind.Local. - - - - Be aware that because of the way PKWare's - Zip specification describes how times are stored in the zip file, - the full precision of the System.DateTime datatype is not stored - for the last modified time when saving zip files. For more information on - how times are formatted, see the PKZip specification. - - - - The actual last modified time of a file can be stored in multiple ways in - the zip file, and they are not mutually exclusive: - - - - - In the so-called "DOS" format, which has a 2-second precision. Values - are rounded to the nearest even second. For example, if the time on the - file is 12:34:43, then it will be stored as 12:34:44. This first value - is accessible via the LastModified property. This value is always - present in the metadata for each zip entry. In some cases the value is - invalid, or zero. - - - - In the so-called "Windows" or "NTFS" format, as an 8-byte integer - quantity expressed as the number of 1/10 milliseconds (in other words - the number of 100 nanosecond units) since January 1, 1601 (UTC). This - format is how Windows represents file times. This time is accessible - via the ModifiedTime property. - - - - In the "Unix" format, a 4-byte quantity specifying the number of seconds since - January 1, 1970 UTC. - - - - In an older format, now deprecated but still used by some current - tools. This format is also a 4-byte quantity specifying the number of - seconds since January 1, 1970 UTC. - - - - - - Zip tools and libraries will always at least handle (read or write) the - DOS time, and may also handle the other time formats. Keep in mind that - while the names refer to particular operating systems, there is nothing in - the time formats themselves that prevents their use on other operating - systems. - - - - When reading ZIP files, the DotNetZip library reads the Windows-formatted - time, if it is stored in the entry, and sets both LastModified and - ModifiedTime to that value. When writing ZIP files, the DotNetZip - library by default will write both time quantities. It can also emit the - Unix-formatted time if desired (See .) - - - - The last modified time of the file created upon a call to - ZipEntry.Extract() may be adjusted during extraction to compensate - for differences in how the .NET Base Class Library deals with daylight - saving time (DST) versus how the Windows filesystem deals with daylight - saving time. Raymond Chen provides - some good context. - - - - In a nutshell: Daylight savings time rules change regularly. In 2007, for - example, the inception week of DST changed. In 1977, DST was in place all - year round. In 1945, likewise. And so on. Win32 does not attempt to - guess which time zone rules were in effect at the time in question. It - will render a time as "standard time" and allow the app to change to DST - as necessary. .NET makes a different choice. - - - - Compare the output of FileInfo.LastWriteTime.ToString("f") with what you - see in the Windows Explorer property sheet for a file that was last - written to on the other side of the DST transition. For example, suppose - the file was last modified on October 17, 2003, during DST but DST is not - currently in effect. Explorer's file properties reports Thursday, October - 17, 2003, 8:45:38 AM, but .NETs FileInfo reports Thursday, October 17, - 2003, 9:45 AM. - - - - Win32 says, "Thursday, October 17, 2002 8:45:38 AM PST". Note: Pacific - STANDARD Time. Even though October 17 of that year occurred during Pacific - Daylight Time, Win32 displays the time as standard time because that's - what time it is NOW. - - - - .NET BCL assumes that the current DST rules were in place at the time in - question. So, .NET says, "Well, if the rules in effect now were also in - effect on October 17, 2003, then that would be daylight time" so it - displays "Thursday, October 17, 2003, 9:45 AM PDT" - daylight time. - - - - So .NET gives a value which is more intuitively correct, but is also - potentially incorrect, and which is not invertible. Win32 gives a value - which is intuitively incorrect, but is strictly correct. - - - - Because of this funkiness, this library adds one hour to the LastModified - time on the extracted file, if necessary. That is to say, if the time in - question had occurred in what the .NET Base Class Library assumed to be - DST. This assumption may be wrong given the constantly changing DST rules, - but it is the best we can do. - - - - - - - - Ability to set Last Modified DOS time to zero - (for using with EmitTimesInWindowsFormatWhenSaving+EmitTimesInUnixFormatWhenSaving setted to false) - some flasher hardware use as marker of first binary - - - - - Last Modified time for the file represented by the entry. - - - - - - This value corresponds to the "last modified" time in the NTFS file times - as described in the Zip - specification. When getting this property, the value may be - different from . When setting the property, - the property also gets set, but with a lower - precision. - - - - Let me explain. It's going to take a while, so get - comfortable. Originally, waaaaay back in 1989 when the ZIP specification - was originally described by the esteemed Mr. Phil Katz, the dominant - operating system of the time was MS-DOS. MSDOS stored file times with a - 2-second precision, because, c'mon, who is ever going to need better - resolution than THAT? And so ZIP files, regardless of the platform on - which the zip file was created, store file times in exactly the same format that DOS used - in 1989. - - - - Since then, the ZIP spec has evolved, but the internal format for file - timestamps remains the same. Despite the fact that the way times are - stored in a zip file is rooted in DOS heritage, any program on any - operating system can format a time in this way, and most zip tools and - libraries DO - they round file times to the nearest even second and store - it just like DOS did 25+ years ago. - - - - PKWare extended the ZIP specification to allow a zip file to store what - are called "NTFS Times" and "Unix(tm) times" for a file. These are the - last write, last access, and file creation - times of a particular file. These metadata are not actually specific - to NTFS or Unix. They are tracked for each file by NTFS and by various - Unix filesystems, but they are also tracked by other filesystems, too. - The key point is that the times are formatted in the zip file - in the same way that NTFS formats the time (ticks since win32 epoch), - or in the same way that Unix formats the time (seconds since Unix - epoch). As with the DOS time, any tool or library running on any - operating system is capable of formatting a time in one of these ways - and embedding it into the zip file. - - - - These extended times are higher precision quantities than the DOS time. - As described above, the (DOS) LastModified has a precision of 2 seconds. - The Unix time is stored with a precision of 1 second. The NTFS time is - stored with a precision of 0.0000001 seconds. The quantities are easily - convertible, except for the loss of precision you may incur. - - - - A zip archive can store the {C,A,M} times in NTFS format, in Unix format, - or not at all. Often a tool running on Unix or Mac will embed the times - in Unix format (1 second precision), while WinZip running on Windows might - embed the times in NTFS format (precision of of 0.0000001 seconds). When - reading a zip file with these "extended" times, in either format, - DotNetZip represents the values with the - ModifiedTime, AccessedTime and CreationTime - properties on the ZipEntry. - - - - While any zip application or library, regardless of the platform it - runs on, could use any of the time formats allowed by the ZIP - specification, not all zip tools or libraries do support all these - formats. Storing the higher-precision times for each entry is - optional for zip files, and many tools and libraries don't use the - higher precision quantities at all. The old DOS time, represented by - , is guaranteed to be present, though it - sometimes unset. - - - - Ok, getting back to the question about how the LastModified - property relates to this ModifiedTime - property... LastModified is always set, while - ModifiedTime is not. (The other times stored in the NTFS - times extension, CreationTime and AccessedTime also - may not be set on an entry that is read from an existing zip file.) - When reading a zip file, then LastModified takes the DOS time - that is stored with the file. If the DOS time has been stored as zero - in the zipfile, then this library will use DateTime.Now for the - LastModified value. If the ZIP file was created by an evolved - tool, then there will also be higher precision NTFS or Unix times in - the zip file. In that case, this library will read those times, and - set LastModified and ModifiedTime to the same value, the - one corresponding to the last write time of the file. If there are no - higher precision times stored for the entry, then ModifiedTime - remains unset (likewise AccessedTime and CreationTime), - and LastModified keeps its DOS time. - - - - When creating zip files with this library, by default the extended time - properties (ModifiedTime, AccessedTime, and - CreationTime) are set on the ZipEntry instance, and these data are - stored in the zip archive for each entry, in NTFS format. If you add an - entry from an actual filesystem file, then the entry gets the actual file - times for that file, to NTFS-level precision. If you add an entry from a - stream, or a string, then the times get the value DateTime.Now. In - this case LastModified and ModifiedTime will be identical, - to 2 seconds of precision. You can explicitly set the - CreationTime, AccessedTime, and ModifiedTime of an - entry using the property setters. If you want to set all of those - quantities, it's more efficient to use the method. Those - changes are not made permanent in the zip file until you call or one of its cousins. - - - - When creating a zip file, you can override the default behavior of - this library for formatting times in the zip file, disabling the - embedding of file times in NTFS format or enabling the storage of file - times in Unix format, or both. You may want to do this, for example, - when creating a zip file on Windows, that will be consumed on a Mac, - by an application that is not hip to the "NTFS times" format. To do - this, use the and - properties. A valid zip - file may store the file times in both formats. But, there are no - guarantees that a program running on Mac or Linux will gracefully - handle the NTFS-formatted times when Unix times are present, or that a - non-DotNetZip-powered application running on Windows will be able to - handle file times in Unix format. DotNetZip will always do something - reasonable; other libraries or tools may not. When in doubt, test. - - - - I'll bet you didn't think one person could type so much about time, eh? - And reading it was so enjoyable, too! Well, in appreciation, maybe you - should donate? - - - - - - - - - - - Last Access time for the file represented by the entry. - - - This value may or may not be meaningful. If the ZipEntry was read from an existing - Zip archive, this information may not be available. For an explanation of why, see - . - - - - - - - - The file creation time for the file represented by the entry. - - - - This value may or may not be meaningful. If the ZipEntry was read - from an existing zip archive, and the creation time was not set on the entry - when the zip file was created, then this property may be meaningless. For an - explanation of why, see . - - - - - - - - Sets the NTFS Creation, Access, and Modified times for the given entry. - - - - - When adding an entry from a file or directory, the Creation, Access, and - Modified times for the given entry are automatically set from the - filesystem values. When adding an entry from a stream or string, the - values are implicitly set to DateTime.Now. The application may wish to - set these values to some arbitrary value, before saving the archive, and - can do so using the various setters. If you want to set all of the times, - this method is more efficient. - - - - The values you set here will be retrievable with the , and properties. - - - - When this method is called, if both and are false, then the - EmitTimesInWindowsFormatWhenSaving flag is automatically set. - - - - DateTime values provided here without a DateTimeKind are assumed to be Local Time. - - - - the creation time of the entry. - the last access time of the entry. - the last modified time of the entry. - - - - - - - - - - Specifies whether the Creation, Access, and Modified times for the given - entry will be emitted in "Windows format" when the zip archive is saved. - - - - - An application creating a zip archive can use this flag to explicitly - specify that the file times for the entry should or should not be stored - in the zip archive in the format used by Windows. The default value of - this property is true. - - - - When adding an entry from a file or directory, the Creation (), Access (), and Modified - () times for the given entry are automatically - set from the filesystem values. When adding an entry from a stream or - string, all three values are implicitly set to DateTime.Now. Applications - can also explicitly set those times by calling . - - - - PKWARE's - zip specification describes multiple ways to format these times in a - zip file. One is the format Windows applications normally use: 100ns ticks - since Jan 1, 1601 UTC. The other is a format Unix applications typically - use: seconds since January 1, 1970 UTC. Each format can be stored in an - "extra field" in the zip entry when saving the zip archive. The former - uses an extra field with a Header Id of 0x000A, while the latter uses a - header ID of 0x5455. - - - - Not all zip tools and libraries can interpret these fields. Windows - compressed folders is one that can read the Windows Format timestamps, - while I believe the Infozip - tools can read the Unix format timestamps. Although the time values are - easily convertible, subject to a loss of precision, some tools and - libraries may be able to read only one or the other. DotNetZip can read or - write times in either or both formats. - - - - The times stored are taken from , , and . - - - - This property is not mutually exclusive from the property. It is - possible that a zip entry can embed the timestamps in both forms, one - form, or neither. But, there are no guarantees that a program running on - Mac or Linux will gracefully handle NTFS Formatted times, or that a - non-DotNetZip-powered application running on Windows will be able to - handle file times in Unix format. When in doubt, test. - - - - Normally you will use the ZipFile.EmitTimesInWindowsFormatWhenSaving - property, to specify the behavior for all entries in a zip, rather than - the property on each individual entry. - - - - - - - - - - - - - Specifies whether the Creation, Access, and Modified times for the given - entry will be emitted in "Unix(tm) format" when the zip archive is saved. - - - - - An application creating a zip archive can use this flag to explicitly - specify that the file times for the entry should or should not be stored - in the zip archive in the format used by Unix. By default this flag is - false, meaning the Unix-format times are not stored in the zip - archive. - - - - When adding an entry from a file or directory, the Creation (), Access (), and Modified - () times for the given entry are automatically - set from the filesystem values. When adding an entry from a stream or - string, all three values are implicitly set to DateTime.Now. Applications - can also explicitly set those times by calling . - - - - PKWARE's - zip specification describes multiple ways to format these times in a - zip file. One is the format Windows applications normally use: 100ns ticks - since Jan 1, 1601 UTC. The other is a format Unix applications typically - use: seconds since Jan 1, 1970 UTC. Each format can be stored in an - "extra field" in the zip entry when saving the zip archive. The former - uses an extra field with a Header Id of 0x000A, while the latter uses a - header ID of 0x5455. - - - - Not all tools and libraries can interpret these fields. Windows - compressed folders is one that can read the Windows Format timestamps, - while I believe the Infozip - tools can read the Unix format timestamps. Although the time values are - easily convertible, subject to a loss of precision, some tools and - libraries may be able to read only one or the other. DotNetZip can read or - write times in either or both formats. - - - - The times stored are taken from , , and . - - - - This property is not mutually exclusive from the property. It is - possible that a zip entry can embed the timestamps in both forms, one - form, or neither. But, there are no guarantees that a program running on - Mac or Linux will gracefully handle NTFS Formatted times, or that a - non-DotNetZip-powered application running on Windows will be able to - handle file times in Unix format. When in doubt, test. - - - - Normally you will use the ZipFile.EmitTimesInUnixFormatWhenSaving - property, to specify the behavior for all entries, rather than the - property on each individual entry. - - - - - - - - - - - - - The type of timestamp attached to the ZipEntry. - - - - This property is valid only for a ZipEntry that was read from a zip archive. - It indicates the type of timestamp attached to the entry. - - - - - - - - The file attributes for the entry. - - - - - - The attributes in NTFS include - ReadOnly, Archive, Hidden, System, and Indexed. When adding a - ZipEntry to a ZipFile, these attributes are set implicitly when - adding an entry from the filesystem. When adding an entry from a stream - or string, the Attributes are not set implicitly. Regardless of the way - an entry was added to a ZipFile, you can set the attributes - explicitly if you like. - - - - When reading a ZipEntry from a ZipFile, the attributes are - set according to the data stored in the ZipFile. If you extract the - entry from the archive to a filesystem file, DotNetZip will set the - attributes on the resulting file accordingly. - - - - The attributes can be set explicitly by the application. For example the - application may wish to set the FileAttributes.ReadOnly bit for all - entries added to an archive, so that on unpack, this attribute will be set - on the extracted file. Any changes you make to this property are made - permanent only when you call a Save() method on the ZipFile - instance that contains the ZipEntry. - - - - For example, an application may wish to zip up a directory and set the - ReadOnly bit on every file in the archive, so that upon later extraction, - the resulting files will be marked as ReadOnly. Not every extraction tool - respects these attributes, but if you unpack with DotNetZip, as for - example in a self-extracting archive, then the attributes will be set as - they are stored in the ZipFile. - - - - These attributes may not be interesting or useful if the resulting archive - is extracted on a non-Windows platform. How these attributes get used - upon extraction depends on the platform and tool used. - - - - - - - The name of the filesystem file, referred to by the ZipEntry. - - - - - This property specifies the thing-to-be-zipped on disk, and is set only - when the ZipEntry is being created from a filesystem file. If the - ZipFile is instantiated by reading an existing .zip archive, then - the LocalFileName will be null (Nothing in VB). - - - - When it is set, the value of this property may be different than , which is the path used in the archive itself. If you - call Zip.AddFile("foop.txt", AlternativeDirectory), then the path - used for the ZipEntry within the zip archive will be different - than this path. - - - - If the entry is being added from a stream, then this is null (Nothing in VB). - - - - - - - - The name of the file contained in the ZipEntry. - - - - - - This is the name of the entry in the ZipFile itself. When creating - a zip archive, if the ZipEntry has been created from a filesystem - file, via a call to or , or a related overload, the value - of this property is derived from the name of that file. The - FileName property does not include drive letters, and may include a - different directory path, depending on the value of the - directoryPathInArchive parameter used when adding the entry into - the ZipFile. - - - - In some cases there is no related filesystem file - for example when a - ZipEntry is created using or one of the similar overloads. In this case, the value of - this property is derived from the fileName and the directory path passed - to that method. - - - - When reading a zip file, this property takes the value of the entry name - as stored in the zip file. If you extract such an entry, the extracted - file will take the name given by this property. - - - - Applications can set this property when creating new zip archives or when - reading existing archives. When setting this property, the actual value - that is set will replace backslashes with forward slashes, in accordance - with the Zip - specification, for compatibility with Unix(tm) and ... get - this.... Amiga! - - - - If an application reads a ZipFile via or a related overload, and then explicitly - sets the FileName on an entry contained within the ZipFile, and - then calls , the application will effectively - rename the entry within the zip archive. - - - - If an application sets the value of FileName, then calls - Extract() on the entry, the entry is extracted to a file using the - newly set value as the filename. The FileName value is made - permanent in the zip archive only after a call to one of the - ZipFile.Save() methods on the ZipFile that contains the - ZipEntry. - - - - If an application attempts to set the FileName to a value that - would result in a duplicate entry in the ZipFile, an exception is - thrown. - - - - When a ZipEntry is contained within a ZipFile, applications - cannot rename the entry within the context of a foreach (For - Each in VB) loop, because of the way the ZipFile stores - entries. If you need to enumerate through all the entries and rename one - or more of them, use ZipFile.EntriesSorted as the - collection. See also, ZipFile.GetEnumerator(). - - - - - - - The stream that provides content for the ZipEntry. - - - - - - The application can use this property to set the input stream for an - entry on a just-in-time basis. Imagine a scenario where the application - creates a ZipFile comprised of content obtained from hundreds of - files, via calls to AddFile(). The DotNetZip library opens streams - on these files on a just-in-time basis, only when writing the entry out to - an external store within the scope of a ZipFile.Save() call. Only - one input stream is opened at a time, as each entry is being written out. - - - - Now imagine a different application that creates a ZipFile - with content obtained from hundreds of streams, added through . Normally the - application would supply an open stream to that call. But when large - numbers of streams are being added, this can mean many open streams at one - time, unnecessarily. - - - - To avoid this, call and specify delegates that open and close the stream at - the time of Save. - - - - - Setting the value of this property when the entry was not added from a - stream (for example, when the ZipEntry was added with or , or when the entry was added by - reading an existing zip archive) will throw an exception. - - - - - - - - A flag indicating whether the InputStream was provided Just-in-time. - - - - - - When creating a zip archive, an application can obtain content for one or - more of the ZipEntry instances from streams, using the method. At the time - of calling that method, the application can supply null as the value of - the stream parameter. By doing so, the application indicates to the - library that it will provide a stream for the entry on a just-in-time - basis, at the time one of the ZipFile.Save() methods is called and - the data for the various entries are being compressed and written out. - - - - In this case, the application can set the - property, typically within the SaveProgress event (event type: ) for that entry. - - - - The application will later want to call Close() and Dispose() on that - stream. In the SaveProgress event, when the event type is , the application can - do so. This flag indicates that the stream has been provided by the - application on a just-in-time basis and that it is the application's - responsibility to call Close/Dispose on that stream. - - - - - - - - An enum indicating the source of the ZipEntry. - - - - - The version of the zip engine needed to read the ZipEntry. - - - - - This is a readonly property, indicating the version of the Zip - specification that the extracting tool or library must support to - extract the given entry. Generally higher versions indicate newer - features. Older zip engines obviously won't know about new features, and - won't be able to extract entries that depend on those newer features. - - - - - value - Features - - - - 20 - a basic Zip Entry, potentially using PKZIP encryption. - - - - - 45 - The ZIP64 extension is used on the entry. - - - - - 46 - File is compressed using BZIP2 compression* - - - - 50 - File is encrypted using PkWare's DES, 3DES, (broken) RC2 or RC4 - - - - 51 - File is encrypted using PKWare's AES encryption or corrected RC2 encryption. - - - - 52 - File is encrypted using corrected RC2-64 encryption** - - - - 61 - File is encrypted using non-OAEP key wrapping*** - - - - 63 - File is compressed using LZMA, PPMd+, Blowfish, or Twofish - - - - - - There are other values possible, not listed here. DotNetZip supports - regular PKZip encryption, and ZIP64 extensions. DotNetZip cannot extract - entries that require a zip engine higher than 45. - - - - This value is set upon reading an existing zip file, or after saving a zip - archive. - - - - - - The comment attached to the ZipEntry. - - - - - Each entry in a zip file can optionally have a comment associated to - it. The comment might be displayed by a zip tool during extraction, for - example. - - - - By default, the Comment is encoded in IBM437 code page. You can - specify an alternative with and - . - - - - - - - - Indicates whether the entry requires ZIP64 extensions. - - - - - - This property is null (Nothing in VB) until a Save() method on the - containing instance has been called. The property is - non-null (HasValue is true) only after a Save() method has - been called. - - - - After the containing ZipFile has been saved, the Value of this - property is true if any of the following three conditions holds: the - uncompressed size of the entry is larger than 0xFFFFFFFF; the compressed - size of the entry is larger than 0xFFFFFFFF; the relative offset of the - entry within the zip archive is larger than 0xFFFFFFFF. These quantities - are not known until a Save() is attempted on the zip archive and - the compression is applied. - - - - If none of the three conditions holds, then the Value is false. - - - - A Value of false does not indicate that the entry, as saved in the - zip archive, does not use ZIP64. It merely indicates that ZIP64 is - not required. An entry may use ZIP64 even when not required if - the property on the containing - ZipFile instance is set to , or if - the property on the containing - ZipFile instance is set to - and the output stream was not seekable. - - - - - - - - Indicates whether the entry actually used ZIP64 extensions, as it was most - recently written to the output file or stream. - - - - - - This Nullable property is null (Nothing in VB) until a Save() - method on the containing instance has been - called. HasValue is true only after a Save() method has been - called. - - - - The value of this property for a particular ZipEntry may change - over successive calls to Save() methods on the containing ZipFile, - even if the file that corresponds to the ZipEntry does not. This - may happen if other entries contained in the ZipFile expand, - causing the offset for this particular entry to exceed 0xFFFFFFFF. - - - - - - - The bitfield for the entry as defined in the zip spec. You probably - never need to look at this. - - - - - You probably do not need to concern yourself with the contents of this - property, but in case you do: - - - - - bit - meaning - - - - 0 - set if encryption is used. - - - - 1-2 - - set to determine whether normal, max, fast deflation. DotNetZip library - always leaves these bits unset when writing (indicating "normal" - deflation"), but can read an entry with any value here. - - - - - 3 - - Indicates that the Crc32, Compressed and Uncompressed sizes are zero in the - local header. This bit gets set on an entry during writing a zip file, when - it is saved to a non-seekable output stream. - - - - - - 4 - reserved for "enhanced deflating". This library doesn't do enhanced deflating. - - - - 5 - set to indicate the zip is compressed patched data. This library doesn't do that. - - - - 6 - - set if PKWare's strong encryption is used (must also set bit 1 if bit 6 is - set). This bit is not set if WinZip's AES encryption is set. - - - - 7 - not used - - - - 8 - not used - - - - 9 - not used - - - - 10 - not used - - - - 11 - - Language encoding flag (EFS). If this bit is set, the filename and comment - fields for this file must be encoded using UTF-8. This library currently - does not support UTF-8. - - - - - 12 - Reserved by PKWARE for enhanced compression. - - - - 13 - - Used when encrypting the Central Directory to indicate selected data - values in the Local Header are masked to hide their actual values. See - the section in the Zip - specification describing the Strong Encryption Specification for - details. - - - - - 14 - Reserved by PKWARE. - - - - 15 - Reserved by PKWARE. - - - - - - - - - The compression method employed for this ZipEntry. - - - - - - The - Zip specification allows a variety of compression methods. This - library supports just two: 0x08 = Deflate. 0x00 = Store (no compression), - for reading or writing. - - - - When reading an entry from an existing zipfile, the value you retrieve - here indicates the compression method used on the entry by the original - creator of the zip. When writing a zipfile, you can specify either 0x08 - (Deflate) or 0x00 (None). If you try setting something else, you will get - an exception. - - - - You may wish to set CompressionMethod to CompressionMethod.None (0) - when zipping already-compressed data like a jpg, png, or mp3 file. - This can save time and cpu cycles. - - - - When setting this property on a ZipEntry that is read from an - existing zip file, calling ZipFile.Save() will cause the new - CompressionMethod to be used on the entry in the newly saved zip file. - - - - Setting this property may have the side effect of modifying the - CompressionLevel property. If you set the CompressionMethod to a - value other than None, and CompressionLevel is previously - set to None, then CompressionLevel will be set to - Default. - - - - - - - In this example, the first entry added to the zip archive uses the default - behavior - compression is used where it makes sense. The second entry, - the MP3 file, is added to the archive without being compressed. - - using (ZipFile zip = new ZipFile(ZipFileToCreate)) - { - ZipEntry e1= zip.AddFile(@"notes\Readme.txt"); - ZipEntry e2= zip.AddFile(@"music\StopThisTrain.mp3"); - e2.CompressionMethod = CompressionMethod.None; - zip.Save(); - } - - - - Using zip As New ZipFile(ZipFileToCreate) - zip.AddFile("notes\Readme.txt") - Dim e2 as ZipEntry = zip.AddFile("music\StopThisTrain.mp3") - e2.CompressionMethod = CompressionMethod.None - zip.Save - End Using - - - - - - Sets the compression level to be used for the entry when saving the zip - archive. This applies only for CompressionMethod = DEFLATE. - - - - - When using the DEFLATE compression method, Varying the compression - level used on entries can affect the size-vs-speed tradeoff when - compression and decompressing data streams or files. - - - - If you do not set this property, the default compression level is used, - which normally gives a good balance of compression efficiency and - compression speed. In some tests, using BestCompression can - double the time it takes to compress, while delivering just a small - increase in compression efficiency. This behavior will vary with the - type of data you compress. If you are in doubt, just leave this setting - alone, and accept the default. - - - - When setting this property on a ZipEntry that is read from an - existing zip file, calling ZipFile.Save() will cause the new - CompressionLevel to be used on the entry in the newly saved zip file. - - - - Setting this property may have the side effect of modifying the - CompressionMethod property. If you set the CompressionLevel - to a value other than None, CompressionMethod will be set - to Deflate, if it was previously None. - - - - Setting this property has no effect if the CompressionMethod is something - other than Deflate or None. - - - - - - - - The compressed size of the file, in bytes, within the zip archive. - - - - When reading a ZipFile, this value is read in from the existing - zip file. When creating or updating a ZipFile, the compressed - size is computed during compression. Therefore the value on a - ZipEntry is valid after a call to Save() (or one of its - overloads) in that case. - - - - - - - The size of the file, in bytes, before compression, or after extraction. - - - - When reading a ZipFile, this value is read in from the existing - zip file. When creating or updating a ZipFile, the uncompressed - size is computed during compression. Therefore the value on a - ZipEntry is valid after a call to Save() (or one of its - overloads) in that case. - - - - - - - The ratio of compressed size to uncompressed size of the ZipEntry. - - - - - This is a ratio of the compressed size to the uncompressed size of the - entry, expressed as a double in the range of 0 to 100+. A value of 100 - indicates no compression at all. It could be higher than 100 when the - compression algorithm actually inflates the data, as may occur for small - files, or uncompressible data that is encrypted. - - - - You could format it for presentation to a user via a format string of - "{3,5:F0}%" to see it as a percentage. - - - - If the size of the original uncompressed file is 0, implying a - denominator of 0, the return value will be zero. - - - - This property is valid after reading in an existing zip file, or after - saving the ZipFile that contains the ZipEntry. You cannot know the - effect of a compression transform until you try it. - - - - - - - The 32-bit CRC (Cyclic Redundancy Check) on the contents of the ZipEntry. - - - - - You probably don't need to concern yourself with this. It is used - internally by DotNetZip to verify files or streams upon extraction. - - The value is a 32-bit - CRC using 0xEDB88320 for the polynomial. This is the same CRC-32 used in - PNG, MPEG-2, and other protocols and formats. It is a read-only property; when - creating a Zip archive, the CRC for each entry is set only after a call to - Save() on the containing ZipFile. When reading an existing zip file, the value - of this property reflects the stored CRC for the entry. - - - - - - True if the entry is a directory (not a file). - This is a readonly property on the entry. - - - - - A derived property that is true if the entry uses encryption. - - - - - This is a readonly property on the entry. When reading a zip file, - the value for the ZipEntry is determined by the data read - from the zip file. After saving a ZipFile, the value of this - property for each ZipEntry indicates whether encryption was - actually used (which will have been true if the was set and the property - was something other than . - - - - - - Set this to specify which encryption algorithm to use for the entry when - saving it to a zip archive. - - - - - - Set this property in order to encrypt the entry when the ZipFile is - saved. When setting this property, you must also set a on the entry. If you set a value other than on this property and do not set a - Password then the entry will not be encrypted. The ZipEntry - data is encrypted as the ZipFile is saved, when you call or one of its cousins on the containing - ZipFile instance. You do not need to specify the Encryption - when extracting entries from an archive. - - - - The Zip specification from PKWare defines a set of encryption algorithms, - and the data formats for the zip archive that support them, and PKWare - supports those algorithms in the tools it produces. Other vendors of tools - and libraries, such as WinZip or Xceed, typically support a - subset of the algorithms specified by PKWare. These tools can - sometimes support additional different encryption algorithms and data - formats, not specified by PKWare. The AES Encryption specified and - supported by WinZip is the most popular example. This library supports a - subset of the complete set of algorithms specified by PKWare and other - vendors. - - - - There is no common, ubiquitous multi-vendor standard for strong encryption - within zip files. There is broad support for so-called "traditional" Zip - encryption, sometimes called Zip 2.0 encryption, as specified - by PKWare, but this encryption is considered weak and - breakable. This library currently supports the Zip 2.0 "weak" encryption, - and also a stronger WinZip-compatible AES encryption, using either 128-bit - or 256-bit key strength. If you want DotNetZip to support an algorithm - that is not currently supported, call the author of this library and maybe - we can talk business. - - - - The class also has a property. In most cases you will use - that property when setting encryption. This property takes - precedence over any Encryption set on the ZipFile itself. - Typically, you would use the per-entry Encryption when most entries in the - zip archive use one encryption algorithm, and a few entries use a - different one. If all entries in the zip file use the same Encryption, - then it is simpler to just set this property on the ZipFile itself, when - creating a zip archive. - - - - Some comments on updating archives: If you read a ZipFile, you can - modify the Encryption on an encrypted entry: you can remove encryption - from an entry that was encrypted; you can encrypt an entry that was not - encrypted previously; or, you can change the encryption algorithm. The - changes in encryption are not made permanent until you call Save() on the - ZipFile. To effect changes in encryption, the entry content is - streamed through several transformations, depending on the modification - the application has requested. For example if the entry is not encrypted - and the application sets Encryption to PkzipWeak, then at - the time of Save(), the original entry is read and decompressed, - then re-compressed and encrypted. Conversely, if the original entry is - encrypted with PkzipWeak encryption, and the application sets the - Encryption property to WinZipAes128, then at the time of - Save(), the original entry is decrypted via PKZIP encryption and - decompressed, then re-compressed and re-encrypted with AES. This all - happens automatically within the library, but it can be time-consuming for - large entries. - - - - Additionally, when updating archives, it is not possible to change the - password when changing the encryption algorithm. To change both the - algorithm and the password, you need to Save() the zipfile twice. First - set the Encryption to None, then call Save(). Then set the - Encryption to the new value (not "None"), then call Save() - once again. - - - - The WinZip AES encryption algorithms are not supported on the .NET Compact - Framework. - - - - - - This example creates a zip archive that uses encryption, and then extracts - entries from the archive. When creating the zip archive, the ReadMe.txt - file is zipped without using a password or encryption. The other file - uses encryption. - - - // Create a zip archive with AES Encryption. - using (ZipFile zip = new ZipFile()) - { - zip.AddFile("ReadMe.txt") - ZipEntry e1= zip.AddFile("2008-Regional-Sales-Report.pdf"); - e1.Encryption= EncryptionAlgorithm.WinZipAes256; - e1.Password= "Top.Secret.No.Peeking!"; - zip.Save("EncryptedArchive.zip"); - } - - // Extract a zip archive that uses AES Encryption. - // You do not need to specify the algorithm during extraction. - using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) - { - // Specify the password that is used during extraction, for - // all entries that require a password: - zip.Password= "Top.Secret.No.Peeking!"; - zip.ExtractAll("extractDirectory"); - } - - - - ' Create a zip that uses Encryption. - Using zip As New ZipFile() - zip.AddFile("ReadMe.txt") - Dim e1 as ZipEntry - e1= zip.AddFile("2008-Regional-Sales-Report.pdf") - e1.Encryption= EncryptionAlgorithm.WinZipAes256 - e1.Password= "Top.Secret.No.Peeking!" - zip.Save("EncryptedArchive.zip") - End Using - - ' Extract a zip archive that uses AES Encryption. - ' You do not need to specify the algorithm during extraction. - Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) - ' Specify the password that is used during extraction, for - ' all entries that require a password: - zip.Password= "Top.Secret.No.Peeking!" - zip.ExtractAll("extractDirectory") - End Using - - - - - - Thrown in the setter if EncryptionAlgorithm.Unsupported is specified. - - - ZipEntry.Password - ZipFile.Encryption - - - - The Password to be used when encrypting a ZipEntry upon - ZipFile.Save(), or when decrypting an entry upon Extract(). - - - - - This is a write-only property on the entry. Set this to request that the - entry be encrypted when writing the zip archive, or set it to specify the - password to be used when extracting an existing entry that is encrypted. - - - - The password set here is implicitly used to encrypt the entry during the - operation, or to decrypt during the or operation. If you set - the Password on a ZipEntry after calling Save(), there is no - effect. - - - - Consider setting the property when using a - password. Answering concerns that the standard password protection - supported by all zip tools is weak, WinZip has extended the ZIP - specification with a way to use AES Encryption to protect entries in the - Zip file. Unlike the "PKZIP 2.0" encryption specified in the PKZIP - specification, AES - Encryption uses a standard, strong, tested, encryption - algorithm. DotNetZip can create zip archives that use WinZip-compatible - AES encryption, if you set the property. But, - archives created that use AES encryption may not be readable by all other - tools and libraries. For example, Windows Explorer cannot read a - "compressed folder" (a zip file) that uses AES encryption, though it can - read a zip file that uses "PKZIP encryption." - - - - The class also has a - property. This property takes precedence over any password set on the - ZipFile itself. Typically, you would use the per-entry Password when most - entries in the zip archive use one password, and a few entries use a - different password. If all entries in the zip file use the same password, - then it is simpler to just set this property on the ZipFile itself, - whether creating a zip archive or extracting a zip archive. - - - - Some comments on updating archives: If you read a ZipFile, you - cannot modify the password on any encrypted entry, except by extracting - the entry with the original password (if any), removing the original entry - via , and then adding a new - entry with a new Password. - - - - For example, suppose you read a ZipFile, and there is an encrypted - entry. Setting the Password property on that ZipEntry and then - calling Save() on the ZipFile does not update the password - on that entry in the archive. Neither is an exception thrown. Instead, - what happens during the Save() is the existing entry is copied - through to the new zip archive, in its original encrypted form. Upon - re-reading that archive, the entry can be decrypted with its original - password. - - - - If you read a ZipFile, and there is an un-encrypted entry, you can set the - Password on the entry and then call Save() on the ZipFile, and get - encryption on that entry. - - - - - - - This example creates a zip file with two entries, and then extracts the - entries from the zip file. When creating the zip file, the two files are - added to the zip file using password protection. Each entry uses a - different password. During extraction, each file is extracted with the - appropriate password. - - - // create a file with encryption - using (ZipFile zip = new ZipFile()) - { - ZipEntry entry; - entry= zip.AddFile("Declaration.txt"); - entry.Password= "123456!"; - entry = zip.AddFile("Report.xls"); - entry.Password= "1Secret!"; - zip.Save("EncryptedArchive.zip"); - } - - // extract entries that use encryption - using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) - { - ZipEntry entry; - entry = zip["Declaration.txt"]; - entry.Password = "123456!"; - entry.Extract("extractDir"); - entry = zip["Report.xls"]; - entry.Password = "1Secret!"; - entry.Extract("extractDir"); - } - - - - - Using zip As New ZipFile - Dim entry as ZipEntry - entry= zip.AddFile("Declaration.txt") - entry.Password= "123456!" - entry = zip.AddFile("Report.xls") - entry.Password= "1Secret!" - zip.Save("EncryptedArchive.zip") - End Using - - - ' extract entries that use encryption - Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) - Dim entry as ZipEntry - entry = zip("Declaration.txt") - entry.Password = "123456!" - entry.Extract("extractDir") - entry = zip("Report.xls") - entry.Password = "1Secret!" - entry.Extract("extractDir") - End Using - - - - - - - ZipFile.Password - - - - The action the library should take when extracting a file that already exists. - - - - - This property affects the behavior of the Extract methods (one of the - Extract() or ExtractWithPassword() overloads), when - extraction would would overwrite an existing filesystem file. If you do - not set this property, the library throws an exception when extracting - an entry would overwrite an existing file. - - - - This property has no effect when extracting to a stream, or when the file to be - extracted does not already exist. - - - - - - - This example shows how to set the ExtractExistingFile property in - an ExtractProgress event, in response to user input. The - ExtractProgress event is invoked if and only if the - ExtractExistingFile property was previously set to - ExtractExistingFileAction.InvokeExtractProgressEvent. - - public static void ExtractProgress(object sender, ExtractProgressEventArgs e) - { - if (e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry) - Console.WriteLine("extract {0} ", e.CurrentEntry.FileName); - - else if (e.EventType == ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite) - { - ZipEntry entry = e.CurrentEntry; - string response = null; - // Ask the user if he wants overwrite the file - do - { - Console.Write("Overwrite {0} in {1} ? (y/n/C) ", entry.FileName, e.ExtractLocation); - response = Console.ReadLine(); - Console.WriteLine(); - - } while (response != null && response[0]!='Y' && - response[0]!='N' && response[0]!='C'); - - if (response[0]=='C') - e.Cancel = true; - else if (response[0]=='Y') - entry.ExtractExistingFile = ExtractExistingFileAction.OverwriteSilently; - else - entry.ExtractExistingFile= ExtractExistingFileAction.DoNotOverwrite; - } - } - - - - - - The action to take when an error is encountered while - opening or reading files as they are saved into a zip archive. - - - - - Errors can occur within a call to ZipFile.Save, as the various files contained - in a ZipFile are being saved into the zip archive. During the - Save, DotNetZip will perform a File.Open on the file - associated to the ZipEntry, and then will read the entire contents of - the file as it is zipped. Either the open or the Read may fail, because - of lock conflicts or other reasons. Using this property, you can - specify the action to take when such errors occur. - - - - Typically you will NOT set this property on individual ZipEntry - instances. Instead, you will set the ZipFile.ZipErrorAction property on - the ZipFile instance, before adding any entries to the - ZipFile. If you do this, errors encountered on behalf of any of - the entries in the ZipFile will be handled the same way. - - - - But, if you use a handler, you will want - to set this property on the ZipEntry within the handler, to - communicate back to DotNetZip what you would like to do with the - particular error. - - - - - - - - - Indicates whether the entry was included in the most recent save. - - - An entry can be excluded or skipped from a save if there is an error - opening or reading the entry. - - - - - - A callback that allows the application to specify the compression to use - for a given entry that is about to be added to the zip archive. - - - - - See - - - - - - Set to indicate whether to use UTF-8 encoding for filenames and comments. - - - - - - If this flag is set, the comment and filename for the entry will be - encoded with UTF-8, as described in the Zip - specification, if necessary. "Necessary" means, the filename or - entry comment (if any) cannot be reflexively encoded and decoded using the - default code page, IBM437. - - - - Setting this flag to true is equivalent to setting to System.Text.Encoding.UTF8. - - - - This flag has no effect or relation to the text encoding used within the - file itself. - - - - - - - The text encoding to use for the FileName and Comment on this ZipEntry, - when the default encoding is insufficient. - - - - - - Don't use this property. See . - - - - - - - Specifies the alternate text encoding used by this ZipEntry - - - - The default text encoding used in Zip files for encoding filenames and - comments is IBM437, which is something like a superset of ASCII. In - cases where this is insufficient, applications can specify an - alternate encoding. - - - When creating a zip file, the usage of the alternate encoding is - governed by the property. - Typically you would set both properties to tell DotNetZip to employ an - encoding that is not IBM437 in the zipfile you are creating. - - - Keep in mind that because the ZIP specification states that the only - valid encodings to use are IBM437 and UTF-8, if you use something - other than that, then zip tools and libraries may not be able to - successfully read the zip archive you generate. - - - The zip specification states that applications should presume that - IBM437 is in use, except when a special bit is set, which indicates - UTF-8. There is no way to specify an arbitrary code page, within the - zip file itself. When you create a zip file encoded with gb2312 or - ibm861 or anything other than IBM437 or UTF-8, then the application - that reads the zip file needs to "know" which code page to use. In - some cases, the code page used when reading is chosen implicitly. For - example, WinRar uses the ambient code page for the host desktop - operating system. The pitfall here is that if you create a zip in - Copenhagen and send it to Tokyo, the reader of the zipfile may not be - able to decode successfully. - - - - This example shows how to create a zipfile encoded with a - language-specific encoding: - - using (var zip = new ZipFile()) - { - zip.AlternateEnoding = System.Text.Encoding.GetEncoding("ibm861"); - zip.AlternateEnodingUsage = ZipOption.Always; - zip.AddFileS(arrayOfFiles); - zip.Save("Myarchive-Encoded-in-IBM861.zip"); - } - - - - - - - Describes if and when this instance should apply - AlternateEncoding to encode the FileName and Comment, when - saving. - - - - - - Indicates whether an entry is marked as a text file. Be careful when - using on this property. Unless you have a good reason, you should - probably ignore this property. - - - - - The ZIP format includes a provision for specifying whether an entry in - the zip archive is a text or binary file. This property exposes that - metadata item. Be careful when using this property: It's not clear - that this property as a firm meaning, across tools and libraries. - - - - To be clear, when reading a zip file, the property value may or may - not be set, and its value may or may not be valid. Not all entries - that you may think of as "text" entries will be so marked, and entries - marked as "text" are not guaranteed in any way to be text entries. - Whether the value is set and set correctly depends entirely on the - application that produced the zip file. - - - - There are many zip tools available, and when creating zip files, some - of them "respect" the IsText metadata field, and some of them do not. - Unfortunately, even when an application tries to do "the right thing", - it's not always clear what "the right thing" is. - - - - There's no firm definition of just what it means to be "a text file", - and the zip specification does not help in this regard. Twenty years - ago, text was ASCII, each byte was less than 127. IsText meant, all - bytes in the file were less than 127. These days, it is not the case - that all text files have all bytes less than 127. Any unicode file - may have bytes that are above 0x7f. The zip specification has nothing - to say on this topic. Therefore, it's not clear what IsText really - means. - - - - This property merely tells a reading application what is stored in the - metadata for an entry, without guaranteeing its validity or its - meaning. - - - - When DotNetZip is used to create a zipfile, it attempts to set this - field "correctly." For example, if a file ends in ".txt", this field - will be set. Your application may override that default setting. When - writing a zip file, you must set the property before calling - Save() on the ZipFile. - - - - When reading a zip file, a more general way to decide just what kind - of file is contained in a particular entry is to use the file type - database stored in the operating system. The operating system stores - a table that says, a file with .jpg extension is a JPG image file, a - file with a .xml extension is an XML document, a file with a .txt is a - pure ASCII text document, and so on. To get this information on - Windows, you - need to read and parse the registry. - - - - - using (var zip = new ZipFile()) - { - var e = zip.UpdateFile("Descriptions.mme", ""); - e.IsText = true; - zip.Save(zipPath); - } - - - - Using zip As New ZipFile - Dim e2 as ZipEntry = zip.AddFile("Descriptions.mme", "") - e.IsText= True - zip.Save(zipPath) - End Using - - - - - Provides a string representation of the instance. - a string representation of the instance. - - - - Extract the entry to the filesystem, starting at the current - working directory. - - - - This method has a bunch of overloads! One of them is sure to - be the right one for you... If you don't like these, check - out the ExtractWithPassword() methods. - - - - - - - - - This method extracts an entry from a zip file into the current - working directory. The path of the entry as extracted is the full - path as specified in the zip archive, relative to the current - working directory. After the file is extracted successfully, the - file attributes and timestamps are set. - - - - The action taken when extraction an entry would overwrite an - existing file is determined by the property. - - - - Within the call to Extract(), the content for the entry is - written into a filesystem file, and then the last modified time of the - file is set according to the property on - the entry. See the remarks the property for - some details about the last modified time. - - - - - - - Extract the entry to a file in the filesystem, using the specified - behavior when extraction would overwrite an existing file. - - - - - See the remarks on the property, for some - details about how the last modified time of the file is set after - extraction. - - - - - The action to take if extraction would overwrite an existing file. - - - - - Extracts the entry to the specified stream. - - - - - The caller can specify any write-able stream, for example a , a , or ASP.NET's - Response.OutputStream. The content will be decrypted and - decompressed as necessary. If the entry is encrypted and no password - is provided, this method will throw. - - - The position on the stream is not reset by this method before it extracts. - You may want to call stream.Seek() before calling ZipEntry.Extract(). - - - - - the stream to which the entry should be extracted. - - - - - - Extract the entry to the filesystem, starting at the specified base - directory. - - - the pathname of the base directory - - - - - - This example extracts only the entries in a zip file that are .txt files, - into a directory called "textfiles". - - using (ZipFile zip = ZipFile.Read("PackedDocuments.zip")) - { - foreach (string s1 in zip.EntryFilenames) - { - if (s1.EndsWith(".txt")) - { - zip[s1].Extract("textfiles"); - } - } - } - - - Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip") - Dim s1 As String - For Each s1 In zip.EntryFilenames - If s1.EndsWith(".txt") Then - zip(s1).Extract("textfiles") - End If - Next - End Using - - - - - - - Using this method, existing entries in the filesystem will not be - overwritten. If you would like to force the overwrite of existing - files, see the property, or call - . - - - - See the remarks on the property, for some - details about how the last modified time of the created file is set. - - - - - - Extract the entry to the filesystem, starting at the specified base - directory, and using the specified behavior when extraction would - overwrite an existing file. - - - - - See the remarks on the property, for some - details about how the last modified time of the created file is set. - - - - - - String sZipPath = "Airborne.zip"; - String sFilePath = "Readme.txt"; - String sRootFolder = "Digado"; - using (ZipFile zip = ZipFile.Read(sZipPath)) - { - if (zip.EntryFileNames.Contains(sFilePath)) - { - // use the string indexer on the zip file - zip[sFileName].Extract(sRootFolder, - ExtractExistingFileAction.OverwriteSilently); - } - } - - - - Dim sZipPath as String = "Airborne.zip" - Dim sFilePath As String = "Readme.txt" - Dim sRootFolder As String = "Digado" - Using zip As ZipFile = ZipFile.Read(sZipPath) - If zip.EntryFileNames.Contains(sFilePath) - ' use the string indexer on the zip file - zip(sFilePath).Extract(sRootFolder, _ - ExtractExistingFileAction.OverwriteSilently) - End If - End Using - - - - the pathname of the base directory - - The action to take if extraction would overwrite an existing file. - - - - - Extract the entry to the filesystem, using the current working directory - and the specified password. - - - - This method has a bunch of overloads! One of them is sure to be - the right one for you... - - - - - - - - - Existing entries in the filesystem will not be overwritten. If you - would like to force the overwrite of existing files, see the property, or call - . - - - - See the remarks on the property for some - details about how the "last modified" time of the created file is - set. - - - - - In this example, entries that use encryption are extracted using a - particular password. - - using (var zip = ZipFile.Read(FilePath)) - { - foreach (ZipEntry e in zip) - { - if (e.UsesEncryption) - e.ExtractWithPassword("Secret!"); - else - e.Extract(); - } - } - - - Using zip As ZipFile = ZipFile.Read(FilePath) - Dim e As ZipEntry - For Each e In zip - If (e.UsesEncryption) - e.ExtractWithPassword("Secret!") - Else - e.Extract - End If - Next - End Using - - - The Password to use for decrypting the entry. - - - - Extract the entry to the filesystem, starting at the specified base - directory, and using the specified password. - - - - - - - - Existing entries in the filesystem will not be overwritten. If you - would like to force the overwrite of existing files, see the property, or call - . - - - - See the remarks on the property, for some - details about how the last modified time of the created file is set. - - - - The pathname of the base directory. - The Password to use for decrypting the entry. - - - - Extract the entry to a file in the filesystem, relative to the - current directory, using the specified behavior when extraction - would overwrite an existing file. - - - - - See the remarks on the property, for some - details about how the last modified time of the created file is set. - - - - The Password to use for decrypting the entry. - - - The action to take if extraction would overwrite an existing file. - - - - - Extract the entry to the filesystem, starting at the specified base - directory, and using the specified behavior when extraction would - overwrite an existing file. - - - - See the remarks on the property, for some - details about how the last modified time of the created file is set. - - - the pathname of the base directory - - The action to take if extraction would - overwrite an existing file. - - The Password to use for decrypting the entry. - - - - Extracts the entry to the specified stream, using the specified - Password. For example, the caller could extract to Console.Out, or - to a MemoryStream. - - - - - The caller can specify any write-able stream, for example a , a , or ASP.NET's - Response.OutputStream. The content will be decrypted and - decompressed as necessary. If the entry is encrypted and no password - is provided, this method will throw. - - - The position on the stream is not reset by this method before it extracts. - You may want to call stream.Seek() before calling ZipEntry.Extract(). - - - - - - the stream to which the entry should be extracted. - - - The password to use for decrypting the entry. - - - - - Opens a readable stream corresponding to the zip entry in the - archive. The stream decompresses and decrypts as necessary, as it - is read. - - - - - - DotNetZip offers a variety of ways to extract entries from a zip - file. This method allows an application to extract an entry by - reading a . - - - - The return value is of type . Use it as you would any - stream for reading. When an application calls on that stream, it will - receive data from the zip entry that is decrypted and decompressed - as necessary. - - - - CrcCalculatorStream adds one additional feature: it keeps a - CRC32 checksum on the bytes of the stream as it is read. The CRC - value is available in the property on the - CrcCalculatorStream. When the read is complete, your - application - should check this CRC against the - property on the ZipEntry to validate the content of the - ZipEntry. You don't have to validate the entry using the CRC, but - you should, to verify integrity. Check the example for how to do - this. - - - - If the entry is protected with a password, then you need to provide - a password prior to calling , either by - setting the property on the entry, or the - property on the ZipFile - itself. Or, you can use , the - overload of OpenReader that accepts a password parameter. - - - - If you want to extract entry data into a write-able stream that is - already opened, like a , do not - use this method. Instead, use . - - - - Your application may use only one stream created by OpenReader() at - a time, and you should not call other Extract methods before - completing your reads on a stream obtained from OpenReader(). This - is because there is really only one source stream for the compressed - content. A call to OpenReader() seeks in the source stream, to the - beginning of the compressed content. A subsequent call to - OpenReader() on a different entry will seek to a different position - in the source stream, as will a call to Extract() or one of its - overloads. This will corrupt the state for the decompressing stream - from the original call to OpenReader(). - - - - The OpenReader() method works only when the ZipEntry is - obtained from an instance of ZipFile. This method will throw - an exception if the ZipEntry is obtained from a . - - - - - This example shows how to open a zip archive, then read in a named - entry via a stream. After the read loop is complete, the code - compares the calculated during the read loop with the expected CRC - on the ZipEntry, to verify the extraction. - - using (ZipFile zip = new ZipFile(ZipFileToRead)) - { - ZipEntry e1= zip["Elevation.mp3"]; - using (Ionic.Zlib.CrcCalculatorStream s = e1.OpenReader()) - { - byte[] buffer = new byte[4096]; - int n, totalBytesRead= 0; - do { - n = s.Read(buffer,0, buffer.Length); - totalBytesRead+=n; - } while (n>0); - if (s.Crc32 != e1.Crc32) - throw new Exception(string.Format("The Zip Entry failed the CRC Check. (0x{0:X8}!=0x{1:X8})", s.Crc32, e1.Crc32)); - if (totalBytesRead != e1.UncompressedSize) - throw new Exception(string.Format("We read an unexpected number of bytes. ({0}!={1})", totalBytesRead, e1.UncompressedSize)); - } - } - - - Using zip As New ZipFile(ZipFileToRead) - Dim e1 As ZipEntry = zip.Item("Elevation.mp3") - Using s As Ionic.Zlib.CrcCalculatorStream = e1.OpenReader - Dim n As Integer - Dim buffer As Byte() = New Byte(4096) {} - Dim totalBytesRead As Integer = 0 - Do - n = s.Read(buffer, 0, buffer.Length) - totalBytesRead = (totalBytesRead + n) - Loop While (n > 0) - If (s.Crc32 <> e1.Crc32) Then - Throw New Exception(String.Format("The Zip Entry failed the CRC Check. (0x{0:X8}!=0x{1:X8})", s.Crc32, e1.Crc32)) - End If - If (totalBytesRead <> e1.UncompressedSize) Then - Throw New Exception(String.Format("We read an unexpected number of bytes. ({0}!={1})", totalBytesRead, e1.UncompressedSize)) - End If - End Using - End Using - - - - The Stream for reading. - - - - Opens a readable stream for an encrypted zip entry in the archive. - The stream decompresses and decrypts as necessary, as it is read. - - - - - See the documentation on the method for - full details. This overload allows the application to specify a - password for the ZipEntry to be read. - - - - The password to use for decrypting the entry. - The Stream for reading. - - - - Pass in either basedir or s, but not both. - In other words, you can extract to a stream or to a directory (filesystem), but not both! - The Password param is required for encrypted entries. - - - - - Extract to a stream - In other words, you can extract to a stream or to a directory (filesystem), but not both! - The Password param is required for encrypted entries. - - - - - Validates that the args are consistent; returning whether the caller can return - because it's done, or not (caller should continue) - - - - - Validates that the args are consistent; returning whether the caller can return - because it's done, or not (caller should continue) - - - - - Reads one ZipEntry from the given stream. The content for - the entry does not get decompressed or decrypted. This method - basically reads metadata, and seeks. - - the ZipContainer this entry belongs to. - - true of this is the first entry being read from the stream. - - the ZipEntry read from the stream. - - - - Finds a particular segment in the given extra field. - This is used when modifying a previously-generated - extra field, in particular when removing the AES crypto - segment in the extra field. - - - - - At current cursor position in the stream, read the extra - field, and set the properties on the ZipEntry instance - appropriately. This can be called when processing the - Extra field in the Central Directory, or in the local - header. - - - - - generate and return a byte array that encodes the filename - for the entry. - - - - side effects: generate and store into _CommentBytes the - byte array for any comment attached to the entry. Also - sets _actualEncoding to indicate the actual encoding - used. The same encoding is used for both filename and - comment. - - - - - - Stores the position of the entry source stream, or, if the position is - already stored, seeks to that position. - - - - - This method is called in prep for reading the source stream. If PKZIP - encryption is used, then we need to calc the CRC32 before doing the - encryption, because the CRC is used in the 12th byte of the PKZIP - encryption header. So, we need to be able to seek backward in the source - when saving the ZipEntry. This method is called from the place that - calculates the CRC, and also from the method that does the encryption of - the file data. - - - - The first time through, this method sets the _sourceStreamOriginalPosition - field. Subsequent calls to this method seek to that position. - - - - - - Copy metadata that may have been changed by the app. We do this when - resetting the zipFile instance. If the app calls Save() on a ZipFile, then - tries to party on that file some more, we may need to Reset() it , which - means re-reading the entries and then copying the metadata. I think. - - - - - Set the input stream and get its length, if possible. The length is - used for progress updates, AND, to allow an optimization in case of - a stream/file of zero length. In that case we skip the Encrypt and - compression Stream. (like DeflateStream or BZip2OutputStream) - - - - - Prepare the given stream for output - wrap it in a CountingStream, and - then in a CRC stream, and an encryptor and deflator as appropriate. - - - - Previously this was used in ZipEntry.Write(), but in an effort to - introduce some efficiencies in that method I've refactored to put the - code inline. This method still gets called by ZipOutputStream. - - - - - - An enum that specifies the type of timestamp available on the ZipEntry. - - - - - - The last modified time of a file can be stored in multiple ways in - a zip file, and they are not mutually exclusive: - - - - - In the so-called "DOS" format, which has a 2-second precision. Values - are rounded to the nearest even second. For example, if the time on the - file is 12:34:43, then it will be stored as 12:34:44. This first value - is accessible via the LastModified property. This value is always - present in the metadata for each zip entry. In some cases the value is - invalid, or zero. - - - - In the so-called "Windows" or "NTFS" format, as an 8-byte integer - quantity expressed as the number of 1/10 milliseconds (in other words - the number of 100 nanosecond units) since January 1, 1601 (UTC). This - format is how Windows represents file times. This time is accessible - via the ModifiedTime property. - - - - In the "Unix" format, a 4-byte quantity specifying the number of seconds since - January 1, 1970 UTC. - - - - In an older format, now deprecated but still used by some current - tools. This format is also a 4-byte quantity specifying the number of - seconds since January 1, 1970 UTC. - - - - - - This bit field describes which of the formats were found in a ZipEntry that was read. - - - - - - - Default value. - - - - - A DOS timestamp with 2-second precision. - - - - - A Windows timestamp with 100-ns precision. - - - - - A Unix timestamp with 1-second precision. - - - - - A Unix timestamp with 1-second precision, stored in InfoZip v1 format. This - format is outdated and is supported for reading archives only. - - - - - The method of compression to use for a particular ZipEntry. - - - - PKWare's - ZIP Specification describes a number of distinct - cmopression methods that can be used within a zip - file. DotNetZip supports a subset of them. - - - - - No compression at all. For COM environments, the value is 0 (zero). - - - - - DEFLATE compression, as described in IETF RFC - 1951. This is the "normal" compression used in zip - files. For COM environments, the value is 8. - - - - - BZip2 compression, a compression algorithm developed by Julian Seward. - For COM environments, the value is 12. - - - - - An enum that specifies the source of the ZipEntry. - - - - - Default value. Invalid on a bonafide ZipEntry. - - - - - The entry was instantiated by calling AddFile() or another method that - added an entry from the filesystem. - - - - - The entry was instantiated via or - . - - - - - The ZipEntry was instantiated by reading a zipfile. - - - - - The content for the ZipEntry will be or was provided by the WriteDelegate. - - - - - The content for the ZipEntry will be obtained from the stream dispensed by the OpenDelegate. - The entry was instantiated via . - - - - - The content for the ZipEntry will be or was obtained from a ZipOutputStream. - - - - - An enum providing the options when an error occurs during opening or reading - of a file or directory that is being saved to a zip file. - - - - - This enum describes the actions that the library can take when an error occurs - opening or reading a file, as it is being saved into a Zip archive. - - - - In some cases an error will occur when DotNetZip tries to open a file to be - added to the zip archive. In other cases, an error might occur after the - file has been successfully opened, while DotNetZip is reading the file. - - - - The first problem might occur when calling AddDirectory() on a directory - that contains a Clipper .dbf file; the file is locked by Clipper and - cannot be opened by another process. An example of the second problem is - the ERROR_LOCK_VIOLATION that results when a file is opened by another - process, but not locked, and a range lock has been taken on the file. - Microsoft Outlook takes range locks on .PST files. - - - - - - Throw an exception when an error occurs while zipping. This is the default - behavior. (For COM clients, this is a 0 (zero).) - - - - - When an error occurs during zipping, for example a file cannot be opened, - skip the file causing the error, and continue zipping. (For COM clients, - this is a 1.) - - - - - When an error occurs during zipping, for example a file cannot be opened, - retry the operation that caused the error. Be careful with this option. If - the error is not temporary, the library will retry forever. (For COM - clients, this is a 2.) - - - - - When an error occurs, invoke the zipError event. The event type used is - . A typical use of this option: - a GUI application may wish to pop up a dialog to allow the user to view the - error that occurred, and choose an appropriate action. After your - processing in the error event, if you want to skip the file, set on the - ZipProgressEventArgs.CurrentEntry to Skip. If you want the - exception to be thrown, set ZipErrorAction on the CurrentEntry - to Throw. If you want to cancel the zip, set - ZipProgressEventArgs.Cancel to true. Cancelling differs from using - Skip in that a cancel will not save any further entries, if there are any. - (For COM clients, the value of this enum is a 3.) - - - - - The ZipFile type represents a zip archive file. - - - - - This is the main type in the DotNetZip class library. This class reads and - writes zip files, as defined in the specification - for zip files described by PKWare. The compression for this - implementation is provided by a managed-code version of Zlib, included with - DotNetZip in the classes in the Ionic.Zlib namespace. - - - - This class provides a general purpose zip file capability. Use it to read, - create, or update zip files. When you want to create zip files using a - Stream type to write the zip file, you may want to consider the class. - - - - Both the ZipOutputStream class and the ZipFile class can - be used to create zip files. Both of them support many of the common zip - features, including Unicode, different compression methods and levels, - and ZIP64. They provide very similar performance when creating zip - files. - - - - The ZipFile class is generally easier to use than - ZipOutputStream and should be considered a higher-level interface. For - example, when creating a zip file via calls to the PutNextEntry() and - Write() methods on the ZipOutputStream class, the caller is - responsible for opening the file, reading the bytes from the file, writing - those bytes into the ZipOutputStream, setting the attributes on the - ZipEntry, and setting the created, last modified, and last accessed - timestamps on the zip entry. All of these things are done automatically by a - call to ZipFile.AddFile(). - For this reason, the ZipOutputStream is generally recommended for use - only when your application emits arbitrary data, not necessarily data from a - filesystem file, directly into a zip file, and does so using a Stream - metaphor. - - - - Aside from the differences in programming model, there are other - differences in capability between the two classes. - - - - - ZipFile can be used to read and extract zip files, in addition to - creating zip files. ZipOutputStream cannot read zip files. If you want - to use a stream to read zip files, check out the class. - - - - ZipOutputStream does not support the creation of segmented or spanned - zip files. - - - - ZipOutputStream cannot produce a self-extracting archive. - - - - - Be aware that the ZipFile class implements the interface. In order for ZipFile to - produce a valid zip file, you use use it within a using clause (Using - in VB), or call the Dispose() method explicitly. See the examples - for how to employ a using clause. - - - - - - - Adds an item, either a file or a directory, to a zip file archive. - - - - - This method is handy if you are adding things to zip archive and don't - want to bother distinguishing between directories or files. Any files are - added as single entries. A directory added through this method is added - recursively: all files and subdirectories contained within the directory - are added to the ZipFile. - - - - The name of the item may be a relative path or a fully-qualified - path. Remember, the items contained in ZipFile instance get written - to the disk only when you call or a similar - save method. - - - - The directory name used for the file within the archive is the same - as the directory name (potentially a relative path) specified in the - . - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - - - This method has two overloads. - - the name of the file or directory to add. - - The ZipEntry added. - - - - Adds an item, either a file or a directory, to a zip file archive, - explicitly specifying the directory path to be used in the archive. - - - - - If adding a directory, the add is recursive on all files and - subdirectories contained within it. - - - The name of the item may be a relative path or a fully-qualified path. - The item added by this call to the ZipFile is not read from the - disk nor written to the zip file archive until the application calls - Save() on the ZipFile. - - - - This version of the method allows the caller to explicitly specify the - directory path to be used in the archive, which would override the - "natural" path of the filesystem file. - - - - Encryption will be used on the file data if the Password has - been set on the ZipFile object, prior to calling this method. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - Thrown if the file or directory passed in does not exist. - - - the name of the file or directory to add. - - - - The name of the directory path to use within the zip archive. This path - need not refer to an extant directory in the current filesystem. If the - files within the zip are later extracted, this is the path used for the - extracted file. Passing null (Nothing in VB) will use the - path on the fileOrDirectoryName. Passing the empty string ("") will - insert the item at the root path within the archive. - - - - - - - - This example shows how to zip up a set of files into a flat hierarchy, - regardless of where in the filesystem the files originated. The resulting - zip archive will contain a toplevel directory named "flat", which itself - will contain files Readme.txt, MyProposal.docx, and Image1.jpg. A - subdirectory under "flat" called SupportFiles will contain all the files - in the "c:\SupportFiles" directory on disk. - - - String[] itemnames= { - "c:\\fixedContent\\Readme.txt", - "MyProposal.docx", - "c:\\SupportFiles", // a directory - "images\\Image1.jpg" - }; - - try - { - using (ZipFile zip = new ZipFile()) - { - for (int i = 1; i < itemnames.Length; i++) - { - // will add Files or Dirs, recurses and flattens subdirectories - zip.AddItem(itemnames[i],"flat"); - } - zip.Save(ZipToCreate); - } - } - catch (System.Exception ex1) - { - System.Console.Error.WriteLine("exception: {0}", ex1); - } - - - - Dim itemnames As String() = _ - New String() { "c:\fixedContent\Readme.txt", _ - "MyProposal.docx", _ - "SupportFiles", _ - "images\Image1.jpg" } - Try - Using zip As New ZipFile - Dim i As Integer - For i = 1 To itemnames.Length - 1 - ' will add Files or Dirs, recursing and flattening subdirectories. - zip.AddItem(itemnames(i), "flat") - Next i - zip.Save(ZipToCreate) - End Using - Catch ex1 As Exception - Console.Error.WriteLine("exception: {0}", ex1.ToString()) - End Try - - - The ZipEntry added. - - - - Adds a File to a Zip file archive. - - - - - This call collects metadata for the named file in the filesystem, - including the file attributes and the timestamp, and inserts that metadata - into the resulting ZipEntry. Only when the application calls Save() on - the ZipFile, does DotNetZip read the file from the filesystem and - then write the content to the zip file archive. - - - - This method will throw an exception if an entry with the same name already - exists in the ZipFile. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - In this example, three files are added to a Zip archive. The ReadMe.txt - file will be placed in the root of the archive. The .png file will be - placed in a folder within the zip called photos\personal. The pdf file - will be included into a folder within the zip called Desktop. - - - try - { - using (ZipFile zip = new ZipFile()) - { - zip.AddFile("c:\\photos\\personal\\7440-N49th.png"); - zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf"); - zip.AddFile("ReadMe.txt"); - - zip.Save("Package.zip"); - } - } - catch (System.Exception ex1) - { - System.Console.Error.WriteLine("exception: " + ex1); - } - - - - Try - Using zip As ZipFile = New ZipFile - zip.AddFile("c:\photos\personal\7440-N49th.png") - zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf") - zip.AddFile("ReadMe.txt") - zip.Save("Package.zip") - End Using - Catch ex1 As Exception - Console.Error.WriteLine("exception: {0}", ex1.ToString) - End Try - - - - This method has two overloads. - - - - - - - The name of the file to add. It should refer to a file in the filesystem. - The name of the file may be a relative path or a fully-qualified path. - - The ZipEntry corresponding to the File added. - - - - Adds a File to a Zip file archive, potentially overriding the path to be - used within the zip archive. - - - - - The file added by this call to the ZipFile is not written to the - zip file archive until the application calls Save() on the ZipFile. - - - - This method will throw an exception if an entry with the same name already - exists in the ZipFile. - - - - This version of the method allows the caller to explicitly specify the - directory path to be used in the archive. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - In this example, three files are added to a Zip archive. The ReadMe.txt - file will be placed in the root of the archive. The .png file will be - placed in a folder within the zip called images. The pdf file will be - included into a folder within the zip called files\docs, and will be - encrypted with the given password. - - - try - { - using (ZipFile zip = new ZipFile()) - { - // the following entry will be inserted at the root in the archive. - zip.AddFile("c:\\datafiles\\ReadMe.txt", ""); - // this image file will be inserted into the "images" directory in the archive. - zip.AddFile("c:\\photos\\personal\\7440-N49th.png", "images"); - // the following will result in a password-protected file called - // files\\docs\\2008-Regional-Sales-Report.pdf in the archive. - zip.Password = "EncryptMe!"; - zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf", "files\\docs"); - zip.Save("Archive.zip"); - } - } - catch (System.Exception ex1) - { - System.Console.Error.WriteLine("exception: {0}", ex1); - } - - - - Try - Using zip As ZipFile = New ZipFile - ' the following entry will be inserted at the root in the archive. - zip.AddFile("c:\datafiles\ReadMe.txt", "") - ' this image file will be inserted into the "images" directory in the archive. - zip.AddFile("c:\photos\personal\7440-N49th.png", "images") - ' the following will result in a password-protected file called - ' files\\docs\\2008-Regional-Sales-Report.pdf in the archive. - zip.Password = "EncryptMe!" - zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf", "files\documents") - zip.Save("Archive.zip") - End Using - Catch ex1 As Exception - Console.Error.WriteLine("exception: {0}", ex1) - End Try - - - - - - - - - The name of the file to add. The name of the file may be a relative path - or a fully-qualified path. - - - - Specifies a directory path to use to override any path in the fileName. - This path may, or may not, correspond to a real directory in the current - filesystem. If the files within the zip are later extracted, this is the - path used for the extracted file. Passing null (Nothing in - VB) will use the path on the fileName, if any. Passing the empty string - ("") will insert the item at the root path within the archive. - - - The ZipEntry corresponding to the file added. - - - - This method removes a collection of entries from the ZipFile. - - - - A collection of ZipEntry instances from this zip file to be removed. For - example, you can pass in an array of ZipEntry instances; or you can call - SelectEntries(), and then add or remove entries from that - ICollection<ZipEntry> (ICollection(Of ZipEntry) in VB), and pass - that ICollection to this method. - - - - - - - - This method removes a collection of entries from the ZipFile, by name. - - - - A collection of strings that refer to names of entries to be removed - from the ZipFile. For example, you can pass in an array or a - List of Strings that provide the names of entries to be removed. - - - - - - - - This method adds a set of files to the ZipFile. - - - - - Use this method to add a set of files to the zip archive, in one call. - For example, a list of files received from - System.IO.Directory.GetFiles() can be added to a zip archive in one - call. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - The collection of names of the files to add. Each string should refer to a - file in the filesystem. The name of the file may be a relative path or a - fully-qualified path. - - - - This example shows how to create a zip file, and add a few files into it. - - String ZipFileToCreate = "archive1.zip"; - String DirectoryToZip = "c:\\reports"; - using (ZipFile zip = new ZipFile()) - { - // Store all files found in the top level directory, into the zip archive. - String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); - zip.AddFiles(filenames); - zip.Save(ZipFileToCreate); - } - - - - Dim ZipFileToCreate As String = "archive1.zip" - Dim DirectoryToZip As String = "c:\reports" - Using zip As ZipFile = New ZipFile - ' Store all files found in the top level directory, into the zip archive. - Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) - zip.AddFiles(filenames) - zip.Save(ZipFileToCreate) - End Using - - - - - - - - Adds or updates a set of files in the ZipFile. - - - - - Any files that already exist in the archive are updated. Any files that - don't yet exist in the archive are added. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - The collection of names of the files to update. Each string should refer to a file in - the filesystem. The name of the file may be a relative path or a fully-qualified path. - - - - - - Adds a set of files to the ZipFile, using the - specified directory path in the archive. - - - - - Any directory structure that may be present in the - filenames contained in the list is "flattened" in the - archive. Each file in the list is added to the archive in - the specified top-level directory. - - - - For ZipFile properties including , , , , , , and , their respective values at the - time of this call will be applied to each ZipEntry added. - - - - - The names of the files to add. Each string should refer to - a file in the filesystem. The name of the file may be a - relative path or a fully-qualified path. - - - - Specifies a directory path to use to override any path in the file name. - Th is path may, or may not, correspond to a real directory in the current - filesystem. If the files within the zip are later extracted, this is the - path used for the extracted file. Passing null (Nothing in - VB) will use the path on each of the fileNames, if any. Passing - the empty string ("") will insert the item at the root path within the - archive. - - - - - - - Adds a set of files to the ZipFile, using the specified directory - path in the archive, and preserving the full directory structure in the - filenames. - - - - - - Think of the as a "root" or - base directory used in the archive for the files that get added. when - is true, the hierarchy of files - found in the filesystem will be placed, with the hierarchy intact, - starting at that root in the archive. When preserveDirHierarchy - is false, the path hierarchy of files is flattned, and the flattened - set of files gets placed in the root within the archive as specified in - directoryPathInArchive. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - - The names of the files to add. Each string should refer to a file in the - filesystem. The name of the file may be a relative path or a - fully-qualified path. - - - - Specifies a directory path to use as a prefix for each entry name. - This path may, or may not, correspond to a real directory in the current - filesystem. If the files within the zip are later extracted, this is the - path used for the extracted file. Passing null (Nothing in - VB) will use the path on each of the fileNames, if any. Passing - the empty string ("") will insert the item at the root path within the - archive. - - - - whether the entries in the zip archive will reflect the directory - hierarchy that is present in the various filenames. For example, if - includes two paths, - \Animalia\Chordata\Mammalia\Info.txt and - \Plantae\Magnoliophyta\Dicotyledon\Info.txt, then calling this method - with = false will - result in an exception because of a duplicate entry name, while - calling this method with = - true will result in the full direcory paths being included in - the entries added to the ZipFile. - - - - - - Adds or updates a set of files to the ZipFile, using the specified - directory path in the archive. - - - - - - Any files that already exist in the archive are updated. Any files that - don't yet exist in the archive are added. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - The names of the files to add or update. Each string should refer to a - file in the filesystem. The name of the file may be a relative path or a - fully-qualified path. - - - - Specifies a directory path to use to override any path in the file name. - This path may, or may not, correspond to a real directory in the current - filesystem. If the files within the zip are later extracted, this is the - path used for the extracted file. Passing null (Nothing in - VB) will use the path on each of the fileNames, if any. Passing - the empty string ("") will insert the item at the root path within the - archive. - - - - - - - Adds or Updates a File in a Zip file archive. - - - - - This method adds a file to a zip archive, or, if the file already exists - in the zip archive, this method Updates the content of that given filename - in the zip archive. The UpdateFile method might more accurately be - called "AddOrUpdateFile". - - - - Upon success, there is no way for the application to learn whether the file - was added versus updated. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - This example shows how to Update an existing entry in a zipfile. The first - call to UpdateFile adds the file to the newly-created zip archive. The - second call to UpdateFile updates the content for that file in the zip - archive. - - - using (ZipFile zip1 = new ZipFile()) - { - // UpdateFile might more accurately be called "AddOrUpdateFile" - zip1.UpdateFile("MyDocuments\\Readme.txt"); - zip1.UpdateFile("CustomerList.csv"); - zip1.Comment = "This zip archive has been created."; - zip1.Save("Content.zip"); - } - - using (ZipFile zip2 = ZipFile.Read("Content.zip")) - { - zip2.UpdateFile("Updates\\Readme.txt"); - zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed."; - zip2.Save(); - } - - - - Using zip1 As New ZipFile - ' UpdateFile might more accurately be called "AddOrUpdateFile" - zip1.UpdateFile("MyDocuments\Readme.txt") - zip1.UpdateFile("CustomerList.csv") - zip1.Comment = "This zip archive has been created." - zip1.Save("Content.zip") - End Using - - Using zip2 As ZipFile = ZipFile.Read("Content.zip") - zip2.UpdateFile("Updates\Readme.txt") - zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed." - zip2.Save - End Using - - - - - - - - - The name of the file to add or update. It should refer to a file in the - filesystem. The name of the file may be a relative path or a - fully-qualified path. - - - - The ZipEntry corresponding to the File that was added or updated. - - - - - Adds or Updates a File in a Zip file archive. - - - - - This method adds a file to a zip archive, or, if the file already exists - in the zip archive, this method Updates the content of that given filename - in the zip archive. - - - - This version of the method allows the caller to explicitly specify the - directory path to be used in the archive. The entry to be added or - updated is found by using the specified directory path, combined with the - basename of the specified filename. - - - - Upon success, there is no way for the application to learn if the file was - added versus updated. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - - - The name of the file to add or update. It should refer to a file in the - filesystem. The name of the file may be a relative path or a - fully-qualified path. - - - - Specifies a directory path to use to override any path in the - fileName. This path may, or may not, correspond to a real - directory in the current filesystem. If the files within the zip are - later extracted, this is the path used for the extracted file. Passing - null (Nothing in VB) will use the path on the - fileName, if any. Passing the empty string ("") will insert the - item at the root path within the archive. - - - - The ZipEntry corresponding to the File that was added or updated. - - - - - Add or update a directory in a zip archive. - - - - If the specified directory does not exist in the archive, then this method - is equivalent to calling AddDirectory(). If the specified - directory already exists in the archive, then this method updates any - existing entries, and adds any new entries. Any entries that are in the - zip archive but not in the specified directory, are left alone. In other - words, the contents of the zip file will be a union of the previous - contents and the new files. - - - - - - - - The path to the directory to be added to the zip archive, or updated in - the zip archive. - - - - The ZipEntry corresponding to the Directory that was added or updated. - - - - - Add or update a directory in the zip archive at the specified root - directory in the archive. - - - - If the specified directory does not exist in the archive, then this method - is equivalent to calling AddDirectory(). If the specified - directory already exists in the archive, then this method updates any - existing entries, and adds any new entries. Any entries that are in the - zip archive but not in the specified directory, are left alone. In other - words, the contents of the zip file will be a union of the previous - contents and the new files. - - - - - - - - The path to the directory to be added to the zip archive, or updated - in the zip archive. - - - - Specifies a directory path to use to override any path in the - directoryName. This path may, or may not, correspond to a real - directory in the current filesystem. If the files within the zip are - later extracted, this is the path used for the extracted file. Passing - null (Nothing in VB) will use the path on the - directoryName, if any. Passing the empty string ("") will insert - the item at the root path within the archive. - - - - The ZipEntry corresponding to the Directory that was added or updated. - - - - - Add or update a file or directory in the zip archive. - - - - - This is useful when the application is not sure or does not care if the - item to be added is a file or directory, and does not know or does not - care if the item already exists in the ZipFile. Calling this method - is equivalent to calling RemoveEntry() if an entry by the same name - already exists, followed calling by AddItem(). - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - - - the path to the file or directory to be added or updated. - - - - - Add or update a file or directory. - - - - - This method is useful when the application is not sure or does not care if - the item to be added is a file or directory, and does not know or does not - care if the item already exists in the ZipFile. Calling this method - is equivalent to calling RemoveEntry(), if an entry by that name - exists, and then calling AddItem(). - - - - This version of the method allows the caller to explicitly specify the - directory path to be used for the item being added to the archive. The - entry or entries that are added or updated will use the specified - DirectoryPathInArchive. Extracting the entry from the archive will - result in a file stored in that directory path. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - - - The path for the File or Directory to be added or updated. - - - Specifies a directory path to use to override any path in the - itemName. This path may, or may not, correspond to a real - directory in the current filesystem. If the files within the zip are - later extracted, this is the path used for the extracted file. Passing - null (Nothing in VB) will use the path on the - itemName, if any. Passing the empty string ("") will insert the - item at the root path within the archive. - - - - - Adds a named entry into the zip archive, taking content for the entry - from a string. - - - - Calling this method creates an entry using the given fileName and - directory path within the archive. There is no need for a file by the - given name to exist in the filesystem; the name is used within the zip - archive only. The content for the entry is encoded using the default text - encoding for the machine. - - - - The content of the file, should it be extracted from the zip. - - - - The name, including any path, to use for the entry within the archive. - - - The ZipEntry added. - - - - This example shows how to add an entry to the zipfile, using a string as - content for that entry. - - - string Content = "This string will be the content of the Readme.txt file in the zip archive."; - using (ZipFile zip1 = new ZipFile()) - { - zip1.AddFile("MyDocuments\\Resume.doc", "files"); - zip1.AddEntry("Readme.txt", Content); - zip1.Comment = "This zip file was created at " + System.DateTime.Now.ToString("G"); - zip1.Save("Content.zip"); - } - - - - Public Sub Run() - Dim Content As String = "This string will be the content of the Readme.txt file in the zip archive." - Using zip1 As ZipFile = New ZipFile - zip1.AddEntry("Readme.txt", Content) - zip1.AddFile("MyDocuments\Resume.doc", "files") - zip1.Comment = ("This zip file was created at " & DateTime.Now.ToString("G")) - zip1.Save("Content.zip") - End Using - End Sub - - - - - - Adds a named entry into the zip archive, taking content for the entry - from a string, and using the specified text encoding. - - - - - - Calling this method creates an entry using the given fileName and - directory path within the archive. There is no need for a file by the - given name to exist in the filesystem; the name is used within the zip - archive only. - - - - The content for the entry, a string value, is encoded using the given - text encoding. A BOM (byte-order-mark) is emitted into the file, if the - Encoding parameter is set for that. - - - - Most Encoding classes support a constructor that accepts a boolean, - indicating whether to emit a BOM or not. For example see . - - - - - - The name, including any path, to use within the archive for the entry. - - - - The content of the file, should it be extracted from the zip. - - - - The text encoding to use when encoding the string. Be aware: This is - distinct from the text encoding used to encode the fileName, as specified - in . - - - The ZipEntry added. - - - - - Create an entry in the ZipFile using the given Stream - as input. The entry will have the given filename. - - - - - - The application should provide an open, readable stream; in this case it - will be read during the call to or one of - its overloads. - - - - The passed stream will be read from its current position. If - necessary, callers should set the position in the stream before - calling AddEntry(). This might be appropriate when using this method - with a MemoryStream, for example. - - - - In cases where a large number of streams will be added to the - ZipFile, the application may wish to avoid maintaining all of the - streams open simultaneously. To handle this situation, the application - should use the - overload. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - This example adds a single entry to a ZipFile via a Stream. - - - - String zipToCreate = "Content.zip"; - String fileNameInArchive = "Content-From-Stream.bin"; - using (System.IO.Stream streamToRead = MyStreamOpener()) - { - using (ZipFile zip = new ZipFile()) - { - ZipEntry entry= zip.AddEntry(fileNameInArchive, streamToRead); - zip.AddFile("Readme.txt"); - zip.Save(zipToCreate); // the stream is read implicitly here - } - } - - - - Dim zipToCreate As String = "Content.zip" - Dim fileNameInArchive As String = "Content-From-Stream.bin" - Using streamToRead as System.IO.Stream = MyStreamOpener() - Using zip As ZipFile = New ZipFile() - Dim entry as ZipEntry = zip.AddEntry(fileNameInArchive, streamToRead) - zip.AddFile("Readme.txt") - zip.Save(zipToCreate) '' the stream is read implicitly, here - End Using - End Using - - - - - - - The name, including any path, which is shown in the zip file for the added - entry. - - - The input stream from which to grab content for the file - - The ZipEntry added. - - - - Add a ZipEntry for which content is written directly by the application. - - - - - When the application needs to write the zip entry data, use this - method to add the ZipEntry. For example, in the case that the - application wishes to write the XML representation of a DataSet into - a ZipEntry, the application can use this method to do so. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - About progress events: When using the WriteDelegate, DotNetZip does - not issue any SaveProgress events with EventType = - Saving_EntryBytesRead. (This is because it is the - application's code that runs in WriteDelegate - there's no way for - DotNetZip to know when to issue a EntryBytesRead event.) - Applications that want to update a progress bar or similar status - indicator should do so from within the WriteDelegate - itself. DotNetZip will issue the other SaveProgress events, - including - Saving_Started, - - Saving_BeforeWriteEntry, and - Saving_AfterWriteEntry. - - - - Note: When you use PKZip encryption, it's normally necessary to - compute the CRC of the content to be encrypted, before compressing or - encrypting it. Therefore, when using PKZip encryption with a - WriteDelegate, the WriteDelegate CAN BE called twice: once to compute - the CRC, and the second time to potentially compress and - encrypt. Surprising, but true. This is because PKWARE specified that - the encryption initialization data depends on the CRC. - If this happens, for each call of the delegate, your - application must stream the same entry data in its entirety. If your - application writes different data during the second call, it will - result in a corrupt zip file. - - - - The double-read behavior happens with all types of entries, not only - those that use WriteDelegate. It happens if you add an entry from a - filesystem file, or using a string, or a stream, or an opener/closer - pair. But in those cases, DotNetZip takes care of reading twice; in - the case of the WriteDelegate, the application code gets invoked - twice. Be aware. - - - - As you can imagine, this can cause performance problems for large - streams, and it can lead to correctness problems when you use a - WriteDelegate. This is a pretty big pitfall. There are two - ways to avoid it. First, and most preferred: don't use PKZIP - encryption. If you use the WinZip AES encryption, this problem - doesn't occur, because the encryption protocol doesn't require the CRC - up front. Second: if you do choose to use PKZIP encryption, write out - to a non-seekable stream (like standard output, or the - Response.OutputStream in an ASP.NET application). In this case, - DotNetZip will use an alternative encryption protocol that does not - rely on the CRC of the content. This also implies setting bit 3 in - the zip entry, which still presents problems for some zip tools. - - - - In the future I may modify DotNetZip to *always* use bit 3 when PKZIP - encryption is in use. This seems like a win overall, but there will - be some work involved. If you feel strongly about it, visit the - DotNetZip forums and vote up the Workitem - tracking this issue. - - - - - the name of the entry to add - the delegate which will write the entry content - the ZipEntry added - - - - This example shows an application filling a DataSet, then saving the - contents of that DataSet as XML, into a ZipEntry in a ZipFile, using an - anonymous delegate in C#. The DataSet XML is never saved to a disk file. - - - var c1= new System.Data.SqlClient.SqlConnection(connstring1); - var da = new System.Data.SqlClient.SqlDataAdapter() - { - SelectCommand= new System.Data.SqlClient.SqlCommand(strSelect, c1) - }; - - DataSet ds1 = new DataSet(); - da.Fill(ds1, "Invoices"); - - using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) - { - zip.AddEntry(zipEntryName, (name,stream) => ds1.WriteXml(stream) ); - zip.Save(zipFileName); - } - - - - - - This example uses an anonymous method in C# as the WriteDelegate to provide - the data for the ZipEntry. The example is a bit contrived - the - AddFile() method is a simpler way to insert the contents of a file - into an entry in a zip file. On the other hand, if there is some sort of - processing or transformation of the file contents required before writing, - the application could use the WriteDelegate to do it, in this way. - - - using (var input = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite )) - { - using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) - { - zip.AddEntry(zipEntryName, (name,output) => - { - byte[] buffer = new byte[BufferSize]; - int n; - while ((n = input.Read(buffer, 0, buffer.Length)) != 0) - { - // could transform the data here... - output.Write(buffer, 0, n); - // could update a progress bar here - } - }); - - zip.Save(zipFileName); - } - } - - - - - - This example uses a named delegate in VB to write data for the given - ZipEntry (VB9 does not have anonymous delegates). The example here is a bit - contrived - a simpler way to add the contents of a file to a ZipEntry is to - simply use the appropriate AddFile() method. The key scenario for - which the WriteDelegate makes sense is saving a DataSet, in XML - format, to the zip file. The DataSet can write XML to a stream, and the - WriteDelegate is the perfect place to write into the zip file. There may be - other data structures that can write to a stream, but cannot be read as a - stream. The WriteDelegate would be appropriate for those cases as - well. - - - Private Sub WriteEntry (ByVal name As String, ByVal output As Stream) - Using input As FileStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - Dim n As Integer = -1 - Dim buffer As Byte() = New Byte(BufferSize){} - Do While n <> 0 - n = input.Read(buffer, 0, buffer.Length) - output.Write(buffer, 0, n) - Loop - End Using - End Sub - - Public Sub Run() - Using zip = New ZipFile - zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry)) - zip.Save(zipFileName) - End Using - End Sub - - - - - - Add an entry, for which the application will provide a stream - containing the entry data, on a just-in-time basis. - - - - - In cases where the application wishes to open the stream that - holds the content for the ZipEntry, on a just-in-time basis, the - application can use this method. The application provides an - opener delegate that will be called by the DotNetZip library to - obtain a readable stream that can be read to get the bytes for - the given entry. Typically, this delegate opens a stream. - Optionally, the application can provide a closer delegate as - well, which will be called by DotNetZip when all bytes have been - read from the entry. - - - - These delegates are called from within the scope of the call to - ZipFile.Save(). - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - This example uses anonymous methods in C# to open and close the - source stream for the content for a zip entry. - - - using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) - { - zip.AddEntry(zipEntryName, - (name) => File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ), - (name, stream) => stream.Close() - ); - - zip.Save(zipFileName); - } - - - - - - - This example uses delegates in VB.NET to open and close the - the source stream for the content for a zip entry. VB 9.0 lacks - support for "Sub" lambda expressions, and so the CloseDelegate must - be an actual, named Sub. - - - - Function MyStreamOpener(ByVal entryName As String) As Stream - '' This simply opens a file. You probably want to do somethinig - '' more involved here: open a stream to read from a database, - '' open a stream on an HTTP connection, and so on. - Return File.OpenRead(entryName) - End Function - - Sub MyStreamCloser(entryName As String, stream As Stream) - stream.Close() - End Sub - - Public Sub Run() - Dim dirToZip As String = "fodder" - Dim zipFileToCreate As String = "Archive.zip" - Dim opener As OpenDelegate = AddressOf MyStreamOpener - Dim closer As CloseDelegate = AddressOf MyStreamCloser - Dim numFilestoAdd As Int32 = 4 - Using zip As ZipFile = New ZipFile - Dim i As Integer - For i = 0 To numFilesToAdd - 1 - zip.AddEntry(String.Format("content-{0:000}.txt"), opener, closer) - Next i - zip.Save(zipFileToCreate) - End Using - End Sub - - - - - the name of the entry to add - - the delegate that will be invoked by ZipFile.Save() to get the - readable stream for the given entry. ZipFile.Save() will call - read on this stream to obtain the data for the entry. This data - will then be compressed and written to the newly created zip - file. - - - the delegate that will be invoked to close the stream. This may - be null (Nothing in VB), in which case no call is makde to close - the stream. - - the ZipEntry added - - - - - Updates the given entry in the ZipFile, using the given - string as content for the ZipEntry. - - - - - - Calling this method is equivalent to removing the ZipEntry for - the given file name and directory path, if it exists, and then calling - . See the documentation for - that method for further explanation. The string content is encoded - using the default encoding for the machine. This encoding is distinct - from the encoding used for the filename itself. See - . - - - - - - The name, including any path, to use within the archive for the entry. - - - - The content of the file, should it be extracted from the zip. - - - The ZipEntry added. - - - - - Updates the given entry in the ZipFile, using the given string as - content for the ZipEntry. - - - - Calling this method is equivalent to removing the ZipEntry for the - given file name and directory path, if it exists, and then calling . See the - documentation for that method for further explanation. - - - - The name, including any path, to use within the archive for the entry. - - - - The content of the file, should it be extracted from the zip. - - - - The text encoding to use when encoding the string. Be aware: This is - distinct from the text encoding used to encode the filename. See . - - - The ZipEntry added. - - - - - Updates the given entry in the ZipFile, using the given delegate - as the source for content for the ZipEntry. - - - - Calling this method is equivalent to removing the ZipEntry for the - given file name and directory path, if it exists, and then calling . See the - documentation for that method for further explanation. - - - - The name, including any path, to use within the archive for the entry. - - - the delegate which will write the entry content. - - The ZipEntry added. - - - - - Updates the given entry in the ZipFile, using the given delegates - to open and close the stream that provides the content for the ZipEntry. - - - - Calling this method is equivalent to removing the ZipEntry for the - given file name and directory path, if it exists, and then calling . See the - documentation for that method for further explanation. - - - - The name, including any path, to use within the archive for the entry. - - - - the delegate that will be invoked to open the stream - - - the delegate that will be invoked to close the stream - - - The ZipEntry added or updated. - - - - - Updates the given entry in the ZipFile, using the given stream as - input, and the given filename and given directory Path. - - - - - Calling the method is equivalent to calling RemoveEntry() if an - entry by the same name already exists, and then calling AddEntry() - with the given fileName and stream. - - - - The stream must be open and readable during the call to - ZipFile.Save. You can dispense the stream on a just-in-time basis - using the property. Check the - documentation of that property for more information. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to the - ZipEntry added. - - - - - - - - - The name, including any path, to use within the archive for the entry. - - - The input stream from which to read file data. - The ZipEntry added. - - - - Add an entry into the zip archive using the given filename and - directory path within the archive, and the given content for the - file. No file is created in the filesystem. - - - The data to use for the entry. - - - The name, including any path, to use within the archive for the entry. - - - The ZipEntry added. - - - - Updates the given entry in the ZipFile, using the given byte - array as content for the entry. - - - - Calling this method is equivalent to removing the ZipEntry - for the given filename and directory path, if it exists, and then - calling . See the - documentation for that method for further explanation. - - - - The name, including any path, to use within the archive for the entry. - - - The content to use for the ZipEntry. - - The ZipEntry added. - - - - - Adds the contents of a filesystem directory to a Zip file archive. - - - - - - The name of the directory may be a relative path or a fully-qualified - path. Any files within the named directory are added to the archive. Any - subdirectories within the named directory are also added to the archive, - recursively. - - - - Top-level entries in the named directory will appear as top-level entries - in the zip archive. Entries in subdirectories in the named directory will - result in entries in subdirectories in the zip archive. - - - - If you want the entries to appear in a containing directory in the zip - archive itself, then you should call the AddDirectory() overload that - allows you to explicitly specify a directory path for use in the archive. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - - - - - - This method has 2 overloads. - - The name of the directory to add. - The ZipEntry added. - - - - Adds the contents of a filesystem directory to a Zip file archive, - overriding the path to be used for entries in the archive. - - - - - The name of the directory may be a relative path or a fully-qualified - path. The add operation is recursive, so that any files or subdirectories - within the name directory are also added to the archive. - - - - Top-level entries in the named directory will appear as top-level entries - in the zip archive. Entries in subdirectories in the named directory will - result in entries in subdirectories in the zip archive. - - - - For ZipFile properties including , , , , , - , and , their - respective values at the time of this call will be applied to each - ZipEntry added. - - - - - - - In this code, calling the ZipUp() method with a value of "c:\reports" for - the directory parameter will result in a zip file structure in which all - entries are contained in a toplevel "reports" directory. - - - - public void ZipUp(string targetZip, string directory) - { - using (var zip = new ZipFile()) - { - zip.AddDirectory(directory, System.IO.Path.GetFileName(directory)); - zip.Save(targetZip); - } - } - - - - - - - - The name of the directory to add. - - - Specifies a directory path to use to override any path in the - DirectoryName. This path may, or may not, correspond to a real directory - in the current filesystem. If the zip is later extracted, this is the - path used for the extracted file or directory. Passing null - (Nothing in VB) or the empty string ("") will insert the items at - the root path within the archive. - - - The ZipEntry added. - - - - Creates a directory in the zip archive. - - - - - - Use this when you want to create a directory in the archive but there is - no corresponding filesystem representation for that directory. - - - - You will probably not need to do this in your code. One of the only times - you will want to do this is if you want an empty directory in the zip - archive. The reason: if you add a file to a zip archive that is stored - within a multi-level directory, all of the directory tree is implicitly - created in the zip archive. - - - - - - The name of the directory to create in the archive. - - The ZipEntry added. - - - - Checks a zip file to see if its directory is consistent. - - - - - - In cases of data error, the directory within a zip file can get out - of synch with the entries in the zip file. This method checks the - given zip file and returns true if this has occurred. - - - This method may take a long time to run for large zip files. - - - This method is not supported in the Reduced version of DotNetZip. - - - - Developers using COM can use the ComHelper.CheckZip(String) - method. - - - - - The filename to of the zip file to check. - - true if the named zip file checks OK. Otherwise, false. - - - - - - - Checks a zip file to see if its directory is consistent, - and optionally fixes the directory if necessary. - - - - - - In cases of data error, the directory within a zip file can get out of - synch with the entries in the zip file. This method checks the given - zip file, and returns true if this has occurred. It also optionally - fixes the zipfile, saving the fixed copy in Name_Fixed.zip. - - - - This method may take a long time to run for large zip files. It - will take even longer if the file actually needs to be fixed, and if - fixIfNecessary is true. - - - - This method is not supported in the Reduced version of DotNetZip. - - - - - The filename to of the zip file to check. - - If true, the method will fix the zip file if - necessary. - - - a TextWriter in which messages generated while checking will be written. - - - true if the named zip is OK; false if the file needs to be fixed. - - - - - - - Rewrite the directory within a zipfile. - - - - - - In cases of data error, the directory in a zip file can get out of - synch with the entries in the zip file. This method attempts to fix - the zip file if this has occurred. - - - This can take a long time for large zip files. - - This won't work if the zip file uses a non-standard - code page - neither IBM437 nor UTF-8. - - - This method is not supported in the Reduced or Compact Framework - versions of DotNetZip. - - - - Developers using COM can use the ComHelper.FixZipDirectory(String) - method. - - - - - The filename to of the zip file to fix. - - - - - - - Verify the password on a zip file. - - - - - Keep in mind that passwords in zipfiles are applied to - zip entries, not to the entire zip file. So testing a - zipfile for a particular password doesn't work in the - general case. On the other hand, it's often the case - that a single password will be used on all entries in a - zip file. This method works for that case. - - - There is no way to check a password without doing the - decryption. So this code decrypts and extracts the given - zipfile into - - - - The filename to of the zip file to fix. - - The password to check. - - a bool indicating whether the password matches. - - - - Provides a human-readable string with information about the ZipFile. - - - - - The information string contains 10 lines or so, about each ZipEntry, - describing whether encryption is in use, the compressed and uncompressed - length of the entry, the offset of the entry, and so on. As a result the - information string can be very long for zip files that contain many - entries. - - - This information is mostly useful for diagnostic purposes. - - - - - - Indicates whether to perform a full scan of the zip file when reading it. - - - - - - You almost never want to use this property. - - - - When reading a zip file, if this flag is true (True in - VB), the entire zip archive will be scanned and searched for entries. - For large archives, this can take a very, long time. The much more - efficient default behavior is to read the zip directory, which is - stored at the end of the zip file. But, in some cases the directory is - corrupted and you need to perform a full scan of the zip file to - determine the contents of the zip file. This property lets you do - that, when necessary. - - - - This flag is effective only when calling . Normally you would read a ZipFile with the - static ZipFile.Read - method. But you can't set the FullScan property on the - ZipFile instance when you use a static factory method like - ZipFile.Read. - - - - - - - This example shows how to read a zip file using the full scan approach, - and then save it, thereby producing a corrected zip file. - - - using (var zip = new ZipFile()) - { - zip.FullScan = true; - zip.Initialize(zipFileName); - zip.Save(newName); - } - - - - Using zip As New ZipFile - zip.FullScan = True - zip.Initialize(zipFileName) - zip.Save(newName) - End Using - - - - - - - Whether to sort the ZipEntries before saving the file. - - - - The default is false. If you have a large number of zip entries, the sort - alone can consume significant time. - - - - - using (var zip = new ZipFile()) - { - zip.AddFiles(filesToAdd); - zip.SortEntriesBeforeSaving = true; - zip.Save(name); - } - - - - Using zip As New ZipFile - zip.AddFiles(filesToAdd) - zip.SortEntriesBeforeSaving = True - zip.Save(name) - End Using - - - - - - - Indicates whether NTFS Reparse Points, like junctions, should be - traversed during calls to AddDirectory(). - - - - By default, calls to AddDirectory() will traverse NTFS reparse - points, like mounted volumes, and directory junctions. An example - of a junction is the "My Music" directory in Windows Vista. In some - cases you may not want DotNetZip to traverse those directories. In - that case, set this property to false. - - - - - using (var zip = new ZipFile()) - { - zip.AddDirectoryWillTraverseReparsePoints = false; - zip.AddDirectory(dirToZip,"fodder"); - zip.Save(zipFileToCreate); - } - - - - - - Size of the IO buffer used while saving. - - - - - - First, let me say that you really don't need to bother with this. It is - here to allow for optimizations that you probably won't make! It will work - fine if you don't set or get this property at all. Ok? - - - - Now that we have that out of the way, the fine print: This - property affects the size of the buffer that is used for I/O for each - entry contained in the zip file. When a file is read in to be compressed, - it uses a buffer given by the size here. When you update a zip file, the - data for unmodified entries is copied from the first zip file to the - other, through a buffer given by the size here. - - - - Changing the buffer size affects a few things: first, for larger buffer - sizes, the memory used by the ZipFile, obviously, will be larger - during I/O operations. This may make operations faster for very much - larger files. Last, for any given entry, when you use a larger buffer - there will be fewer progress events during I/O operations, because there's - one progress event generated for each time the buffer is filled and then - emptied. - - - - The default buffer size is 8k. Increasing the buffer size may speed - things up as you compress larger files. But there are no hard-and-fast - rules here, eh? You won't know til you test it. And there will be a - limit where ever larger buffers actually slow things down. So as I said - in the beginning, it's probably best if you don't set or get this property - at all. - - - - - - This example shows how you might set a large buffer size for efficiency when - dealing with zip entries that are larger than 1gb. - - using (ZipFile zip = new ZipFile()) - { - zip.SaveProgress += this.zip1_SaveProgress; - zip.AddDirectory(directoryToZip, ""); - zip.UseZip64WhenSaving = Zip64Option.Always; - zip.BufferSize = 65536*8; // 65536 * 8 = 512k - zip.Save(ZipFileToCreate); - } - - - - - - Size of the work buffer to use for the ZLIB codec during compression. - - - - - When doing ZLIB or Deflate compression, the library fills a buffer, - then passes it to the compressor for compression. Then the library - reads out the compressed bytes. This happens repeatedly until there - is no more uncompressed data to compress. This property sets the - size of the buffer that will be used for chunk-wise compression. In - order for the setting to take effect, your application needs to set - this property before calling one of the ZipFile.Save() - overloads. - - - Setting this affects the performance and memory efficiency of - compression and decompression. For larger files, setting this to a - larger size may improve compression performance, but the exact - numbers vary depending on available memory, the size of the streams - you are compressing, and a bunch of other variables. I don't have - good firm recommendations on how to set it. You'll have to test it - yourself. Or just leave it alone and accept the default. - - - - - - Indicates whether extracted files should keep their paths as - stored in the zip archive. - - - - - This property affects Extraction. It is not used when creating zip - archives. - - - - With this property set to false, the default, extracting entries - from a zip file will create files in the filesystem that have the full - path associated to the entry within the zip file. With this property set - to true, extracting entries from the zip file results in files - with no path: the folders are "flattened." - - - - An example: suppose the zip file contains entries /directory1/file1.txt and - /directory2/file2.txt. With FlattenFoldersOnExtract set to false, - the files created will be \directory1\file1.txt and \directory2\file2.txt. - With the property set to true, the files created are file1.txt and file2.txt. - - - - - - - The compression strategy to use for all entries. - - - - Set the Strategy used by the ZLIB-compatible compressor, when - compressing entries using the DEFLATE method. Different compression - strategies work better on different sorts of data. The strategy - parameter can affect the compression ratio and the speed of - compression but not the correctness of the compresssion. For more - information see Ionic.Zlib.CompressionStrategy. - - - - - The name of the ZipFile, on disk. - - - - - - When the ZipFile instance was created by reading an archive using - one of the ZipFile.Read methods, this property represents the name - of the zip file that was read. When the ZipFile instance was - created by using the no-argument constructor, this value is null - (Nothing in VB). - - - - If you use the no-argument constructor, and you then explicitly set this - property, when you call , this name will - specify the name of the zip file created. Doing so is equivalent to - calling . When instantiating a - ZipFile by reading from a stream or byte array, the Name - property remains null. When saving to a stream, the Name - property is implicitly set to null. - - - - - - Sets the compression level to be used for entries subsequently added to - the zip archive. - - - - - Varying the compression level used on entries can affect the - size-vs-speed tradeoff when compression and decompressing data streams - or files. - - - - As with some other properties on the ZipFile class, like , , and , setting this property on a ZipFile - instance will cause the specified CompressionLevel to be used on all - items that are subsequently added to the - ZipFile instance. If you set this property after you have added - items to the ZipFile, but before you have called Save(), - those items will not use the specified compression level. - - - - If you do not set this property, the default compression level is used, - which normally gives a good balance of compression efficiency and - compression speed. In some tests, using BestCompression can - double the time it takes to compress, while delivering just a small - increase in compression efficiency. This behavior will vary with the - type of data you compress. If you are in doubt, just leave this setting - alone, and accept the default. - - - - - - The compression method for the zipfile. - - - - By default, the compression method is CompressionMethod.Deflate. - - - - - - - A comment attached to the zip archive. - - - - - - This property is read/write. It allows the application to specify a - comment for the ZipFile, or read the comment for the - ZipFile. After setting this property, changes are only made - permanent when you call a Save() method. - - - - According to PKWARE's - zip specification, the comment is not encrypted, even if there is a - password set on the zip file. - - - - The specification does not describe how to indicate the encoding used - on a comment string. Many "compliant" zip tools and libraries use - IBM437 as the code page for comments; DotNetZip, too, follows that - practice. On the other hand, there are situations where you want a - Comment to be encoded with something else, for example using code page - 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the - comment following the same procedure it follows for encoding - filenames: (a) if is - Never, it uses the default encoding (IBM437). (b) if is Always, it always uses the - alternate encoding (). (c) if is AsNecessary, it uses the - alternate encoding only if the default encoding is not sufficient for - encoding the comment - in other words if decoding the result does not - produce the original string. This decision is taken at the time of - the call to ZipFile.Save(). - - - - When creating a zip archive using this library, it is possible to change - the value of between each - entry you add, and between adding entries and the call to - Save(). Don't do this. It will likely result in a zip file that is - not readable by any tool or application. For best interoperability, leave - alone, or specify it only - once, before adding any entries to the ZipFile instance. - - - - - - - Specifies whether the Creation, Access, and Modified times for entries - added to the zip file will be emitted in “Windows format” - when the zip archive is saved. - - - - - An application creating a zip archive can use this flag to explicitly - specify that the file times for the entries should or should not be stored - in the zip archive in the format used by Windows. By default this flag is - true, meaning the Windows-format times are stored in the zip - archive. - - - - When adding an entry from a file or directory, the Creation (), Access (), and Modified () times for the given entry are - automatically set from the filesystem values. When adding an entry from a - stream or string, all three values are implicitly set to - DateTime.Now. Applications can also explicitly set those times by - calling . - - - - PKWARE's - zip specification describes multiple ways to format these times in a - zip file. One is the format Windows applications normally use: 100ns ticks - since January 1, 1601 UTC. The other is a format Unix applications typically - use: seconds since January 1, 1970 UTC. Each format can be stored in an - "extra field" in the zip entry when saving the zip archive. The former - uses an extra field with a Header Id of 0x000A, while the latter uses a - header ID of 0x5455, although you probably don't need to know that. - - - - Not all tools and libraries can interpret these fields. Windows - compressed folders is one that can read the Windows Format timestamps, - while I believe the Infozip - tools can read the Unix format timestamps. Some tools and libraries - may be able to read only one or the other. DotNetZip can read or write - times in either or both formats. - - - - The times stored are taken from , , and . - - - - The value set here applies to all entries subsequently added to the - ZipFile. - - - - This property is not mutually exclusive of the property. It is possible and - legal and valid to produce a zip file that contains timestamps encoded in - the Unix format as well as in the Windows format, in addition to the LastModified time attached to each - entry in the archive, a time that is always stored in "DOS format". And, - notwithstanding the names PKWare uses for these time formats, any of them - can be read and written by any computer, on any operating system. But, - there are no guarantees that a program running on Mac or Linux will - gracefully handle a zip file with "Windows" formatted times, or that an - application that does not use DotNetZip but runs on Windows will be able to - handle file times in Unix format. - - - - When in doubt, test. Sorry, I haven't got a complete list of tools and - which sort of timestamps they can use and will tolerate. If you get any - good information and would like to pass it on, please do so and I will - include that information in this documentation. - - - - - This example shows how to save a zip file that contains file timestamps - in a format normally used by Unix. - - using (var zip = new ZipFile()) - { - // produce a zip file the Mac will like - zip.EmitTimesInWindowsFormatWhenSaving = false; - zip.EmitTimesInUnixFormatWhenSaving = true; - zip.AddDirectory(directoryToZip, "files"); - zip.Save(outputFile); - } - - - - Using zip As New ZipFile - '' produce a zip file the Mac will like - zip.EmitTimesInWindowsFormatWhenSaving = False - zip.EmitTimesInUnixFormatWhenSaving = True - zip.AddDirectory(directoryToZip, "files") - zip.Save(outputFile) - End Using - - - - - - - - - Specifies whether the Creation, Access, and Modified times - for entries added to the zip file will be emitted in "Unix(tm) - format" when the zip archive is saved. - - - - - An application creating a zip archive can use this flag to explicitly - specify that the file times for the entries should or should not be stored - in the zip archive in the format used by Unix. By default this flag is - false, meaning the Unix-format times are not stored in the zip - archive. - - - - When adding an entry from a file or directory, the Creation (), Access (), and Modified () times for the given entry are - automatically set from the filesystem values. When adding an entry from a - stream or string, all three values are implicitly set to DateTime.Now. - Applications can also explicitly set those times by calling . - - - - PKWARE's - zip specification describes multiple ways to format these times in a - zip file. One is the format Windows applications normally use: 100ns ticks - since January 1, 1601 UTC. The other is a format Unix applications - typically use: seconds since January 1, 1970 UTC. Each format can be - stored in an "extra field" in the zip entry when saving the zip - archive. The former uses an extra field with a Header Id of 0x000A, while - the latter uses a header ID of 0x5455, although you probably don't need to - know that. - - - - Not all tools and libraries can interpret these fields. Windows - compressed folders is one that can read the Windows Format timestamps, - while I believe the Infozip - tools can read the Unix format timestamps. Some tools and libraries may be - able to read only one or the other. DotNetZip can read or write times in - either or both formats. - - - - The times stored are taken from , , and . - - - - This property is not mutually exclusive of the property. It is possible and - legal and valid to produce a zip file that contains timestamps encoded in - the Unix format as well as in the Windows format, in addition to the LastModified time attached to each - entry in the zip archive, a time that is always stored in "DOS - format". And, notwithstanding the names PKWare uses for these time - formats, any of them can be read and written by any computer, on any - operating system. But, there are no guarantees that a program running on - Mac or Linux will gracefully handle a zip file with "Windows" formatted - times, or that an application that does not use DotNetZip but runs on - Windows will be able to handle file times in Unix format. - - - - When in doubt, test. Sorry, I haven't got a complete list of tools and - which sort of timestamps they can use and will tolerate. If you get any - good information and would like to pass it on, please do so and I will - include that information in this documentation. - - - - - - - - - Indicates whether verbose output is sent to the during AddXxx() and - ReadXxx() operations. - - - - This is a synthetic property. It returns true if the is non-null. - - - - - Returns true if an entry by the given name exists in the ZipFile. - - - the name of the entry to find - true if an entry with the given name exists; otherwise false. - - - - - Indicates whether to perform case-sensitive matching on the filename when - retrieving entries in the zipfile via the string-based indexer. - - - - The default value is false, which means don't do case-sensitive - matching. In other words, retrieving zip["ReadMe.Txt"] is the same as - zip["readme.txt"]. It really makes sense to set this to true only - if you are not running on Windows, which has case-insensitive - filenames. But since this library is not built for non-Windows platforms, - in most cases you should just leave this property alone. - - - - - Indicates whether to ignore duplicate files (report only the first entry) - when loading a zipfile. - - - - The default value is false, which will try to make all files - available (duplicates will have a "copy" suffix appended to their name). - Setting this to true prior to using Initialize to read a - zipfile will prevent this and instead just ignore the duplicates. - - - - - Indicates whether to encode entry filenames and entry comments using Unicode - (UTF-8). - - - - - The - PKWare zip specification provides for encoding file names and file - comments in either the IBM437 code page, or in UTF-8. This flag selects - the encoding according to that specification. By default, this flag is - false, and filenames and comments are encoded into the zip file in the - IBM437 codepage. Setting this flag to true will specify that filenames - and comments that cannot be encoded with IBM437 will be encoded with - UTF-8. - - - - Zip files created with strict adherence to the PKWare specification with - respect to UTF-8 encoding can contain entries with filenames containing - any combination of Unicode characters, including the full range of - characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other - alphabets. However, because at this time, the UTF-8 portion of the PKWare - specification is not broadly supported by other zip libraries and - utilities, such zip files may not be readable by your favorite zip tool or - archiver. In other words, interoperability will decrease if you set this - flag to true. - - - - In particular, Zip files created with strict adherence to the PKWare - specification with respect to UTF-8 encoding will not work well with - Explorer in Windows XP or Windows Vista, because Windows compressed - folders, as far as I know, do not support UTF-8 in zip files. Vista can - read the zip files, but shows the filenames incorrectly. Unpacking from - Windows Vista Explorer will result in filenames that have rubbish - characters in place of the high-order UTF-8 bytes. - - - - Also, zip files that use UTF-8 encoding will not work well with Java - applications that use the java.util.zip classes, as of v5.0 of the Java - runtime. The Java runtime does not correctly implement the PKWare - specification in this regard. - - - - As a result, we have the unfortunate situation that "correct" behavior by - the DotNetZip library with regard to Unicode encoding of filenames during - zip creation will result in zip files that are readable by strictly - compliant and current tools (for example the most recent release of the - commercial WinZip tool); but these zip files will not be readable by - various other tools or libraries, including Windows Explorer. - - - - The DotNetZip library can read and write zip files with UTF8-encoded - entries, according to the PKware spec. If you use DotNetZip for both - creating and reading the zip file, and you use UTF-8, there will be no - loss of information in the filenames. For example, using a self-extractor - created by this library will allow you to unpack files correctly with no - loss of information in the filenames. - - - - If you do not set this flag, it will remain false. If this flag is false, - your ZipFile will encode all filenames and comments using the - IBM437 codepage. This can cause "loss of information" on some filenames, - but the resulting zipfile will be more interoperable with other - utilities. As an example of the loss of information, diacritics can be - lost. The o-tilde character will be down-coded to plain o. The c with a - cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c. - Likewise, the O-stroke character (Unicode 248), used in Danish and - Norwegian, will be down-coded to plain o. Chinese characters cannot be - represented in codepage IBM437; when using the default encoding, Chinese - characters in filenames will be represented as ?. These are all examples - of "information loss". - - - - The loss of information associated to the use of the IBM437 encoding is - inconvenient, and can also lead to runtime errors. For example, using - IBM437, any sequence of 4 Chinese characters will be encoded as ????. If - your application creates a ZipFile, then adds two files, each with - names of four Chinese characters each, this will result in a duplicate - filename exception. In the case where you add a single file with a name - containing four Chinese characters, calling Extract() on the entry that - has question marks in the filename will result in an exception, because - the question mark is not legal for use within filenames on Windows. These - are just a few examples of the problems associated to loss of information. - - - - This flag is independent of the encoding of the content within the entries - in the zip file. Think of the zip file as a container - it supports an - encoding. Within the container are other "containers" - the file entries - themselves. The encoding within those entries is independent of the - encoding of the zip archive container for those entries. - - - - Rather than specify the encoding in a binary fashion using this flag, an - application can specify an arbitrary encoding via the property. Setting the encoding - explicitly when creating zip archives will result in non-compliant zip - files that, curiously, are fairly interoperable. The challenge is, the - PKWare specification does not provide for a way to specify that an entry - in a zip archive uses a code page that is neither IBM437 nor UTF-8. - Therefore if you set the encoding explicitly when creating a zip archive, - you must take care upon reading the zip archive to use the same code page. - If you get it wrong, the behavior is undefined and may result in incorrect - filenames, exceptions, stomach upset, hair loss, and acne. - - - - - - - Specify whether to use ZIP64 extensions when saving a zip archive. - - - - - - When creating a zip file, the default value for the property is . is - safest, in the sense that you will not get an Exception if a pre-ZIP64 - limit is exceeded. - - - - You may set the property at any time before calling Save(). - - - - When reading a zip file via the Zipfile.Read() method, DotNetZip - will properly read ZIP64-endowed zip archives, regardless of the value of - this property. DotNetZip will always read ZIP64 archives. This property - governs only whether DotNetZip will write them. Therefore, when updating - archives, be careful about setting this property after reading an archive - that may use ZIP64 extensions. - - - - An interesting question is, if you have set this property to - AsNecessary, and then successfully saved, does the resulting - archive use ZIP64 extensions or not? To learn this, check the property, after calling Save(). - - - - Have you thought about - donating? - - - - - - - - Indicates whether the archive requires ZIP64 extensions. - - - - - - This property is null (or Nothing in VB) if the archive has - not been saved, and there are fewer than 65334 ZipEntry items - contained in the archive. - - - - The Value is true if any of the following four conditions holds: - the uncompressed size of any entry is larger than 0xFFFFFFFF; the - compressed size of any entry is larger than 0xFFFFFFFF; the relative - offset of any entry within the zip archive is larger than 0xFFFFFFFF; or - there are more than 65534 entries in the archive. (0xFFFFFFFF = - 4,294,967,295). The result may not be known until a Save() is attempted - on the zip archive. The Value of this - property may be set only AFTER one of the Save() methods has been called. - - - - If none of the four conditions holds, and the archive has been saved, then - the Value is false. - - - - A Value of false does not indicate that the zip archive, as saved, - does not use ZIP64. It merely indicates that ZIP64 is not required. An - archive may use ZIP64 even when not required if the property is set to , or if the property is set to and the output stream was not - seekable. Use the property to determine if - the most recent Save() method resulted in an archive that utilized - the ZIP64 extensions. - - - - - - - - - Indicates whether the most recent Save() operation used ZIP64 extensions. - - - - - The use of ZIP64 extensions within an archive is not always necessary, and - for interoperability concerns, it may be desired to NOT use ZIP64 if - possible. The property can be - set to use ZIP64 extensions only when necessary. In those cases, - Sometimes applications want to know whether a Save() actually used ZIP64 - extensions. Applications can query this read-only property to learn - whether ZIP64 has been used in a just-saved ZipFile. - - - - The value is null (or Nothing in VB) if the archive has not - been saved. - - - - Non-null values (HasValue is true) indicate whether ZIP64 - extensions were used during the most recent Save() operation. The - ZIP64 extensions may have been used as required by any particular entry - because of its uncompressed or compressed size, or because the archive is - larger than 4294967295 bytes, or because there are more than 65534 entries - in the archive, or because the UseZip64WhenSaving property was set - to , or because the - UseZip64WhenSaving property was set to and the output stream was not seekable. - The value of this property does not indicate the reason the ZIP64 - extensions were used. - - - - - - - - - Indicates whether the most recent Read() operation read a zip file that uses - ZIP64 extensions. - - - - This property will return null (Nothing in VB) if you've added an entry after reading - the zip file. - - - - - The text encoding to use when writing new entries to the ZipFile, - for those entries that cannot be encoded with the default (IBM437) - encoding; or, the text encoding that was used when reading the entries - from the ZipFile. - - - - - In its - zip specification, PKWare describes two options for encoding - filenames and comments: using IBM437 or UTF-8. But, some archiving tools - or libraries do not follow the specification, and instead encode - characters using the system default code page. For example, WinRAR when - run on a machine in Shanghai may encode filenames with the Big-5 Chinese - (950) code page. This behavior is contrary to the Zip specification, but - it occurs anyway. - - - - When using DotNetZip to write zip archives that will be read by one of - these other archivers, set this property to specify the code page to use - when encoding the and for each ZipEntry in the zip file, for - values that cannot be encoded with the default codepage for zip files, - IBM437. This is why this property is "provisional". In all cases, IBM437 - is used where possible, in other words, where no loss of data would - result. It is possible, therefore, to have a given entry with a - Comment encoded in IBM437 and a FileName encoded with the - specified "provisional" codepage. - - - - Be aware that a zip file created after you've explicitly set the property to a value other than - IBM437 may not be compliant to the PKWare specification, and may not be - readable by compliant archivers. On the other hand, many (most?) - archivers are non-compliant and can read zip files created in arbitrary - code pages. The trick is to use or specify the proper codepage when - reading the zip. - - - - When creating a zip archive using this library, it is possible to change - the value of between each - entry you add, and between adding entries and the call to - Save(). Don't do this. It will likely result in a zipfile that is - not readable. For best interoperability, either leave alone, or specify it only once, - before adding any entries to the ZipFile instance. There is one - exception to this recommendation, described later. - - - - When using an arbitrary, non-UTF8 code page for encoding, there is no - standard way for the creator application - whether DotNetZip, WinZip, - WinRar, or something else - to formally specify in the zip file which - codepage has been used for the entries. As a result, readers of zip files - are not able to inspect the zip file and determine the codepage that was - used for the entries contained within it. It is left to the application - or user to determine the necessary codepage when reading zip files encoded - this way. In other words, if you explicitly specify the codepage when you - create the zipfile, you must explicitly specify the same codepage when - reading the zipfile. - - - - The way you specify the code page to use when reading a zip file varies - depending on the tool or library you use to read the zip. In DotNetZip, - you use a ZipFile.Read() method that accepts an encoding parameter. It - isn't possible with Windows Explorer, as far as I know, to specify an - explicit codepage to use when reading a zip. If you use an incorrect - codepage when reading a zipfile, you will get entries with filenames that - are incorrect, and the incorrect filenames may even contain characters - that are not legal for use within filenames in Windows. Extracting entries - with illegal characters in the filenames will lead to exceptions. It's too - bad, but this is just the way things are with code pages in zip - files. Caveat Emptor. - - - - Example: Suppose you create a zipfile that contains entries with - filenames that have Danish characters. If you use equal to "iso-8859-1" (cp 28591), - the filenames will be correctly encoded in the zip. But, to read that - zipfile correctly, you have to specify the same codepage at the time you - read it. If try to read that zip file with Windows Explorer or another - application that is not flexible with respect to the codepage used to - decode filenames in zipfiles, you will get a filename like "Inf�.txt". - - - - When using DotNetZip to read a zip archive, and the zip archive uses an - arbitrary code page, you must specify the encoding to use before or when - the Zipfile is READ. This means you must use a ZipFile.Read() - method that allows you to specify a System.Text.Encoding parameter. Setting - the ProvisionalAlternateEncoding property after your application has read in - the zip archive will not affect the entry names of entries that have already - been read in. - - - - And now, the exception to the rule described above. One strategy for - specifying the code page for a given zip file is to describe the code page - in a human-readable form in the Zip comment. For example, the comment may - read "Entries in this archive are encoded in the Big5 code page". For - maximum interoperability, the zip comment in this case should be encoded - in the default, IBM437 code page. In this case, the zip comment is - encoded using a different page than the filenames. To do this, Specify - ProvisionalAlternateEncoding to your desired region-specific code - page, once before adding any entries, and then reset - ProvisionalAlternateEncoding to IBM437 before setting the property and calling Save(). - - - - - This example shows how to read a zip file using the Big-5 Chinese code page - (950), and extract each entry in the zip file. For this code to work as - desired, the Zipfile must have been created using the big5 code page - (CP950). This is typical, for example, when using WinRar on a machine with - CP950 set as the default code page. In that case, the names of entries - within the Zip archive will be stored in that code page, and reading the zip - archive must be done using that code page. If the application did not use - the correct code page in ZipFile.Read(), then names of entries within the - zip archive would not be correctly retrieved. - - using (var zip = ZipFile.Read(zipFileName, System.Text.Encoding.GetEncoding("big5"))) - { - // retrieve and extract an entry using a name encoded with CP950 - zip[MyDesiredEntry].Extract("unpack"); - } - - - - Using zip As ZipFile = ZipFile.Read(ZipToExtract, System.Text.Encoding.GetEncoding("big5")) - ' retrieve and extract an entry using a name encoded with CP950 - zip(MyDesiredEntry).Extract("unpack") - End Using - - - - DefaultEncoding - - - - A Text Encoding to use when encoding the filenames and comments for - all the ZipEntry items, during a ZipFile.Save() operation. - - - - Whether the encoding specified here is used during the save depends - on . - - - - - - A flag that tells if and when this instance should apply - AlternateEncoding to encode the filenames and comments associated to - of ZipEntry objects contained within this instance. - - - - - Gets or sets the TextWriter to which status messages are delivered - for the instance. - - - - If the TextWriter is set to a non-null value, then verbose output is sent - to the TextWriter during Add, Read, Save and - Extract operations. Typically, console applications might use - Console.Out and graphical or headless applications might use a - System.IO.StringWriter. The output of this is suitable for viewing - by humans. - - - - - In this example, a console application instantiates a ZipFile, then - sets the StatusMessageTextWriter to Console.Out. At that - point, all verbose status messages for that ZipFile are sent to the - console. - - - - using (ZipFile zip= ZipFile.Read(FilePath)) - { - zip.StatusMessageTextWriter= System.Console.Out; - // messages are sent to the console during extraction - zip.ExtractAll(); - } - - - - Using zip As ZipFile = ZipFile.Read(FilePath) - zip.StatusMessageTextWriter= System.Console.Out - 'Status Messages will be sent to the console during extraction - zip.ExtractAll() - End Using - - - - In this example, a Windows Forms application instantiates a - ZipFile, then sets the StatusMessageTextWriter to a - StringWriter. At that point, all verbose status messages for that - ZipFile are sent to the StringWriter. - - - - var sw = new System.IO.StringWriter(); - using (ZipFile zip= ZipFile.Read(FilePath)) - { - zip.StatusMessageTextWriter= sw; - zip.ExtractAll(); - } - Console.WriteLine("{0}", sw.ToString()); - - - - Dim sw as New System.IO.StringWriter - Using zip As ZipFile = ZipFile.Read(FilePath) - zip.StatusMessageTextWriter= sw - zip.ExtractAll() - End Using - 'Status Messages are now available in sw - - - - - - - Gets or sets the name for the folder to store the temporary file - this library writes when saving a zip archive. - - - - - This library will create a temporary file when saving a Zip archive to a - file. This file is written when calling one of the Save() methods - that does not save to a stream, or one of the SaveSelfExtractor() - methods. - - - - By default, the library will create the temporary file in the directory - specified for the file itself, via the property or via - the method. - - - - Setting this property allows applications to override this default - behavior, so that the library will create the temporary file in the - specified folder. For example, to have the library create the temporary - file in the current working directory, regardless where the ZipFile - is saved, specfy ".". To revert to the default behavior, set this - property to null (Nothing in VB). - - - - When setting the property to a non-null value, the folder specified must - exist; if it does not an exception is thrown. The application should have - write and delete permissions on the folder. The permissions are not - explicitly checked ahead of time; if the application does not have the - appropriate rights, an exception will be thrown at the time Save() - is called. - - - - There is no temporary file created when reading a zip archive. When - saving to a Stream, there is no temporary file created. For example, if - the application is an ASP.NET application and calls Save() - specifying the Response.OutputStream as the output stream, there is - no temporary file created. - - - - - Thrown when setting the property if the directory does not exist. - - - - - - Sets the password to be used on the ZipFile instance. - - - - - - When writing a zip archive, this password is applied to the entries, not - to the zip archive itself. It applies to any ZipEntry subsequently - added to the ZipFile, using one of the AddFile, - AddDirectory, AddEntry, or AddItem methods, etc. - When reading a zip archive, this property applies to any entry - subsequently extracted from the ZipFile using one of the Extract - methods on the ZipFile class. - - - - When writing a zip archive, keep this in mind: though the password is set - on the ZipFile object, according to the Zip spec, the "directory" of the - archive - in other words the list of entries or files contained in the archive - is - not encrypted with the password, or protected in any way. If you set the - Password property, the password actually applies to individual entries - that are added to the archive, subsequent to the setting of this property. - The list of filenames in the archive that is eventually created will - appear in clear text, but the contents of the individual files are - encrypted. This is how Zip encryption works. - - - - One simple way around this limitation is to simply double-wrap sensitive - filenames: Store the files in a zip file, and then store that zip file - within a second, "outer" zip file. If you apply a password to the outer - zip file, then readers will be able to see that the outer zip file - contains an inner zip file. But readers will not be able to read the - directory or file list of the inner zip file. - - - - If you set the password on the ZipFile, and then add a set of files - to the archive, then each entry is encrypted with that password. You may - also want to change the password between adding different entries. If you - set the password, add an entry, then set the password to null - (Nothing in VB), and add another entry, the first entry is - encrypted and the second is not. If you call AddFile(), then set - the Password property, then call ZipFile.Save, the file - added will not be password-protected, and no warning will be generated. - - - - When setting the Password, you may also want to explicitly set the property, to specify how to encrypt the entries added - to the ZipFile. If you set the Password to a non-null value and do not - set , then PKZip 2.0 ("Weak") encryption is used. - This encryption is relatively weak but is very interoperable. If you set - the password to a null value (Nothing in VB), Encryption is - reset to None. - - - - All of the preceding applies to writing zip archives, in other words when - you use one of the Save methods. To use this property when reading or an - existing ZipFile, do the following: set the Password property on the - ZipFile, then call one of the Extract() overloads on the . In this case, the entry is extracted using the - Password that is specified on the ZipFile instance. If you - have not set the Password property, then the password is - null, and the entry is extracted with no password. - - - - If you set the Password property on the ZipFile, then call - Extract() an entry that has not been encrypted with a password, the - password is not used for that entry, and the ZipEntry is extracted - as normal. In other words, the password is used only if necessary. - - - - The class also has a Password property. It takes precedence - over this property on the ZipFile. Typically, you would use the - per-entry Password when most entries in the zip archive use one password, - and a few entries use a different password. If all entries in the zip - file use the same password, then it is simpler to just set this property - on the ZipFile itself, whether creating a zip archive or extracting - a zip archive. - - - - - - - This example creates a zip file, using password protection for the - entries, and then extracts the entries from the zip file. When creating - the zip file, the Readme.txt file is not protected with a password, but - the other two are password-protected as they are saved. During extraction, - each file is extracted with the appropriate password. - - - // create a file with encryption - using (ZipFile zip = new ZipFile()) - { - zip.AddFile("ReadMe.txt"); - zip.Password= "!Secret1"; - zip.AddFile("MapToTheSite-7440-N49th.png"); - zip.AddFile("2008-Regional-Sales-Report.pdf"); - zip.Save("EncryptedArchive.zip"); - } - - // extract entries that use encryption - using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) - { - zip.Password= "!Secret1"; - zip.ExtractAll("extractDir"); - } - - - - - Using zip As New ZipFile - zip.AddFile("ReadMe.txt") - zip.Password = "123456!" - zip.AddFile("MapToTheSite-7440-N49th.png") - zip.Password= "!Secret1"; - zip.AddFile("2008-Regional-Sales-Report.pdf") - zip.Save("EncryptedArchive.zip") - End Using - - - ' extract entries that use encryption - Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) - zip.Password= "!Secret1" - zip.ExtractAll("extractDir") - End Using - - - - - - ZipFile.Encryption - ZipEntry.Password - - - - The action the library should take when extracting a file that already - exists. - - - - - This property affects the behavior of the Extract methods (one of the - Extract() or ExtractWithPassword() overloads), when - extraction would would overwrite an existing filesystem file. If you do - not set this property, the library throws an exception when extracting an - entry would overwrite an existing file. - - - - This property has no effect when extracting to a stream, or when the file - to be extracted does not already exist. - - - - - - - The action the library should take when an error is encountered while - opening or reading files as they are saved into a zip archive. - - - - - Errors can occur as a file is being saved to the zip archive. For - example, the File.Open may fail, or a File.Read may fail, because of - lock conflicts or other reasons. - - - - The first problem might occur after having called AddDirectory() on a - directory that contains a Clipper .dbf file; the file is locked by - Clipper and cannot be opened for read by another process. An example of - the second problem might occur when trying to zip a .pst file that is in - use by Microsoft Outlook. Outlook locks a range on the file, which allows - other processes to open the file, but not read it in its entirety. - - - - This property tells DotNetZip what you would like to do in the case of - these errors. The primary options are: ZipErrorAction.Throw to - throw an exception (this is the default behavior if you don't set this - property); ZipErrorAction.Skip to Skip the file for which there - was an error and continue saving; ZipErrorAction.Retry to Retry - the entry that caused the problem; or - ZipErrorAction.InvokeErrorEvent to invoke an event handler. - - - - This property is implicitly set to ZipErrorAction.InvokeErrorEvent - if you add a handler to the event. If you set - this property to something other than - ZipErrorAction.InvokeErrorEvent, then the ZipError - event is implicitly cleared. What it means is you can set one or the - other (or neither), depending on what you want, but you never need to set - both. - - - - As with some other properties on the ZipFile class, like , , and , setting this property on a ZipFile - instance will cause the specified ZipErrorAction to be used on all - items that are subsequently added to the - ZipFile instance. If you set this property after you have added - items to the ZipFile, but before you have called Save(), - those items will not use the specified error handling action. - - - - If you want to handle any errors that occur with any entry in the zip - file in the same way, then set this property once, before adding any - entries to the zip archive. - - - - If you set this property to ZipErrorAction.Skip and you'd like to - learn which files may have been skipped after a Save(), you can - set the on the ZipFile before - calling Save(). A message will be emitted into that writer for - each skipped file, if any. - - - - - - This example shows how to tell DotNetZip to skip any files for which an - error is generated during the Save(). - - Public Sub SaveZipFile() - Dim SourceFolder As String = "fodder" - Dim DestFile As String = "eHandler.zip" - Dim sw as New StringWriter - Using zipArchive As ZipFile = New ZipFile - ' Tell DotNetZip to skip any files for which it encounters an error - zipArchive.ZipErrorAction = ZipErrorAction.Skip - zipArchive.StatusMessageTextWriter = sw - zipArchive.AddDirectory(SourceFolder) - zipArchive.Save(DestFile) - End Using - ' examine sw here to see any messages - End Sub - - - - - - - - - - The Encryption to use for entries added to the ZipFile. - - - - - Set this when creating a zip archive, or when updating a zip archive. The - specified Encryption is applied to the entries subsequently added to the - ZipFile instance. Applications do not need to set the - Encryption property when reading or extracting a zip archive. - - - - If you set this to something other than EncryptionAlgorithm.None, you - will also need to set the . - - - - As with some other properties on the ZipFile class, like and , setting this - property on a ZipFile instance will cause the specified - EncryptionAlgorithm to be used on all items - that are subsequently added to the ZipFile instance. In other - words, if you set this property after you have added items to the - ZipFile, but before you have called Save(), those items will - not be encrypted or protected with a password in the resulting zip - archive. To get a zip archive with encrypted entries, set this property, - along with the property, before calling - AddFile, AddItem, or AddDirectory (etc.) on the - ZipFile instance. - - - - If you read a ZipFile, you can modify the Encryption on an - encrypted entry, only by setting the Encryption property on the - ZipEntry itself. Setting the Encryption property on the - ZipFile, once it has been created via a call to - ZipFile.Read(), does not affect entries that were previously read. - - - - For example, suppose you read a ZipFile, and there is an encrypted - entry. Setting the Encryption property on that ZipFile and - then calling Save() on the ZipFile does not update the - Encryption used for the entries in the archive. Neither is an - exception thrown. Instead, what happens during the Save() is that - all previously existing entries are copied through to the new zip archive, - with whatever encryption and password that was used when originally - creating the zip archive. Upon re-reading that archive, to extract - entries, applications should use the original password or passwords, if - any. - - - - Suppose an application reads a ZipFile, and there is an encrypted - entry. Setting the Encryption property on that ZipFile and - then adding new entries (via AddFile(), AddEntry(), etc) - and then calling Save() on the ZipFile does not update the - Encryption on any of the entries that had previously been in the - ZipFile. The Encryption property applies only to the - newly-added entries. - - - - - - - This example creates a zip archive that uses encryption, and then extracts - entries from the archive. When creating the zip archive, the ReadMe.txt - file is zipped without using a password or encryption. The other files - use encryption. - - - - // Create a zip archive with AES Encryption. - using (ZipFile zip = new ZipFile()) - { - zip.AddFile("ReadMe.txt"); - zip.Encryption= EncryptionAlgorithm.WinZipAes256; - zip.Password= "Top.Secret.No.Peeking!"; - zip.AddFile("7440-N49th.png"); - zip.AddFile("2008-Regional-Sales-Report.pdf"); - zip.Save("EncryptedArchive.zip"); - } - - // Extract a zip archive that uses AES Encryption. - // You do not need to specify the algorithm during extraction. - using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) - { - zip.Password= "Top.Secret.No.Peeking!"; - zip.ExtractAll("extractDirectory"); - } - - - - ' Create a zip that uses Encryption. - Using zip As New ZipFile() - zip.Encryption= EncryptionAlgorithm.WinZipAes256 - zip.Password= "Top.Secret.No.Peeking!" - zip.AddFile("ReadMe.txt") - zip.AddFile("7440-N49th.png") - zip.AddFile("2008-Regional-Sales-Report.pdf") - zip.Save("EncryptedArchive.zip") - End Using - - ' Extract a zip archive that uses AES Encryption. - ' You do not need to specify the algorithm during extraction. - Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) - zip.Password= "Top.Secret.No.Peeking!" - zip.ExtractAll("extractDirectory") - End Using - - - - - ZipFile.Password - ZipEntry.Encryption - - - - A callback that allows the application to specify the compression level - to use for entries subsequently added to the zip archive. - - - - - - With this callback, the DotNetZip library allows the application to - determine whether compression will be used, at the time of the - Save. This may be useful if the application wants to favor - speed over size, and wants to defer the decision until the time of - Save. - - - - Typically applications set the property on - the ZipFile or on each ZipEntry to determine the level of - compression used. This is done at the time the entry is added to the - ZipFile. Setting the property to - Ionic.Zlib.CompressionLevel.None means no compression will be used. - - - - This callback allows the application to defer the decision on the - CompressionLevel to use, until the time of the call to - ZipFile.Save(). The callback is invoked once per ZipEntry, - at the time the data for the entry is being written out as part of a - Save() operation. The application can use whatever criteria it - likes in determining the level to return. For example, an application may - wish that no .mp3 files should be compressed, because they are already - compressed and the extra compression is not worth the CPU time incurred, - and so can return None for all .mp3 entries. - - - - The library determines whether compression will be attempted for an entry - this way: If the entry is a zero length file, or a directory, no - compression is used. Otherwise, if this callback is set, it is invoked - and the CompressionLevel is set to the return value. If this - callback has not been set, then the previously set value for - CompressionLevel is used. - - - - - - - The maximum size of an output segment, when saving a split Zip file. - - - - Make sure you do not read from this field if you've set the value using - - - - Set this to a non-zero value before calling or to specify that the ZipFile should be saved as a - split archive, also sometimes called a spanned archive. Some also - call them multi-file archives. - - - - A split zip archive is saved in a set of discrete filesystem files, - rather than in a single file. This is handy when transmitting the - archive in email or some other mechanism that has a limit to the size of - each file. The first file in a split archive will be named - basename.z01, the second will be named basename.z02, and - so on. The final file is named basename.zip. According to the zip - specification from PKWare, the minimum value is 65536, for a 64k segment - size. The maximum number of segments allows in a split archive is 99. - - - - The value of this property determines the maximum size of a split - segment when writing a split archive. For example, suppose you have a - ZipFile that would save to a single file of 200k. If you set the - MaxOutputSegmentSize to 65536 before calling Save(), you - will get four distinct output files. On the other hand if you set this - property to 256k, then you will get a single-file archive for that - ZipFile. - - - - The size of each split output file will be as large as possible, up to - the maximum size set here. The zip specification requires that some data - fields in a zip archive may not span a split boundary, and an output - segment may be smaller than the maximum if necessary to avoid that - problem. Also, obviously the final segment of the archive may be smaller - than the maximum segment size. Segments will never be larger than the - value set with this property. - - - - You can save a split Zip file only when saving to a regular filesystem - file. It's not possible to save a split zip file as a self-extracting - archive, nor is it possible to save a split zip file to a stream. When - saving to a SFX or to a Stream, this property is ignored. - - - - About interoperability: Split or spanned zip files produced by DotNetZip - can be read by WinZip or PKZip, and vice-versa. Segmented zip files may - not be readable by other tools, if those other tools don't support zip - spanning or splitting. When in doubt, test. I don't believe Windows - Explorer can extract a split archive. - - - - This property has no effect when reading a split archive. You can read - a split archive in the normal way with DotNetZip. - - - - When saving a zip file, if you want a regular zip file rather than a - split zip file, don't set this property, or set it to Zero. - - - - If you read a split archive, with and - then subsequently call ZipFile.Save(), unless you set this - property before calling Save(), you will get a normal, - single-file archive. - - - - - - - - The maximum size of an output segment, when saving a split Zip file. - - - - If you set this value, make sure you do not accidently use in your code - - - - Set this to a non-zero value before calling or to specify that the ZipFile should be saved as a - split archive, also sometimes called a spanned archive. Some also - call them multi-file archives. - - - - A split zip archive is saved in a set of discrete filesystem files, - rather than in a single file. This is handy when transmitting the - archive in email or some other mechanism that has a limit to the size of - each file. The first file in a split archive will be named - basename.z01, the second will be named basename.z02, and - so on. The final file is named basename.zip. According to the zip - specification from PKWare, the minimum value is 65536, for a 64k segment - size. The maximum number of segments allows in a split archive is 99. - - - - The value of this property determines the maximum size of a split - segment when writing a split archive. For example, suppose you have a - ZipFile that would save to a single file of 200k. If you set the - MaxOutputSegmentSize to 65536 before calling Save(), you - will get four distinct output files. On the other hand if you set this - property to 256k, then you will get a single-file archive for that - ZipFile. - - - - The size of each split output file will be as large as possible, up to - the maximum size set here. The zip specification requires that some data - fields in a zip archive may not span a split boundary, and an output - segment may be smaller than the maximum if necessary to avoid that - problem. Also, obviously the final segment of the archive may be smaller - than the maximum segment size. Segments will never be larger than the - value set with this property. - - - - You can save a split Zip file only when saving to a regular filesystem - file. It's not possible to save a split zip file as a self-extracting - archive, nor is it possible to save a split zip file to a stream. When - saving to a SFX or to a Stream, this property is ignored. - - - - About interoperability: Split or spanned zip files produced by DotNetZip - can be read by WinZip or PKZip, and vice-versa. Segmented zip files may - not be readable by other tools, if those other tools don't support zip - spanning or splitting. When in doubt, test. I don't believe Windows - Explorer can extract a split archive. - - - - This property has no effect when reading a split archive. You can read - a split archive in the normal way with DotNetZip. - - - - When saving a zip file, if you want a regular zip file rather than a - split zip file, don't set this property, or set it to Zero. - - - - If you read a split archive, with and - then subsequently call ZipFile.Save(), unless you set this - property before calling Save(), you will get a normal, - single-file archive. - - - - - - - - Returns the number of segments used in the most recent Save() operation. - - - - This is normally zero, unless you have set the property. If you have set , and then you save a file, after the call to - Save() completes, you can read this value to learn the number of segments that - were created. - - - If you call Save("Archive.zip"), and it creates 5 segments, then you - will have filesystem files named Archive.z01, Archive.z02, Archive.z03, - Archive.z04, and Archive.zip, and the value of this property will be 5. - - - - - - - The size threshold for an entry, above which a parallel deflate is used. - - - - - - DotNetZip will use multiple threads to compress any ZipEntry, - if the entry is larger than the given size. Zero means "always - use parallel deflate", while -1 means "never use parallel - deflate". The default value for this property is 512k. Aside - from the special values of 0 and 1, the minimum value is 65536. - - - - If the entry size cannot be known before compression, as with a - read-forward stream, then Parallel deflate will never be - performed, unless the value of this property is zero. - - - - A parallel deflate operations will speed up the compression of - large files, on computers with multiple CPUs or multiple CPU - cores. For files above 1mb, on a dual core or dual-cpu (2p) - machine, the time required to compress the file can be 70% of the - single-threaded deflate. For very large files on 4p machines the - compression can be done in 30% of the normal time. The downside - is that parallel deflate consumes extra memory during the deflate, - and the deflation is not as effective. - - - - Parallel deflate tends to yield slightly less compression when - compared to as single-threaded deflate; this is because the original - data stream is split into multiple independent buffers, each of which - is compressed in parallel. But because they are treated - independently, there is no opportunity to share compression - dictionaries. For that reason, a deflated stream may be slightly - larger when compressed using parallel deflate, as compared to a - traditional single-threaded deflate. Sometimes the increase over the - normal deflate is as much as 5% of the total compressed size. For - larger files it can be as small as 0.1%. - - - - Multi-threaded compression does not give as much an advantage when - using Encryption. This is primarily because encryption tends to slow - down the entire pipeline. Also, multi-threaded compression gives less - of an advantage when using lower compression levels, for example . You may have to - perform some tests to determine the best approach for your situation. - - - - - - - - - - The maximum number of buffer pairs to use when performing - parallel compression. - - - - - This property sets an upper limit on the number of memory - buffer pairs to create when performing parallel - compression. The implementation of the parallel - compression stream allocates multiple buffers to - facilitate parallel compression. As each buffer fills up, - the stream uses - ThreadPool.QueueUserWorkItem() to compress those - buffers in a background threadpool thread. After a buffer - is compressed, it is re-ordered and written to the output - stream. - - - - A higher number of buffer pairs enables a higher degree of - parallelism, which tends to increase the speed of compression on - multi-cpu computers. On the other hand, a higher number of buffer - pairs also implies a larger memory consumption, more active worker - threads, and a higher cpu utilization for any compression. This - property enables the application to limit its memory consumption and - CPU utilization behavior depending on requirements. - - - - For each compression "task" that occurs in parallel, there are 2 - buffers allocated: one for input and one for output. This property - sets a limit for the number of pairs. The total amount of storage - space allocated for buffering will then be (N*S*2), where N is the - number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer - pairs per CPU core, so if your machine has 4 cores, and you retain - the default buffer size of 128k, then the - ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer - memory in total, or 4mb, in blocks of 128kb. If you then set this - property to 8, then the number will be 8 * 2 * 128kb of buffer - memory, or 2mb. - - - - CPU utilization will also go up with additional buffers, because a - larger number of buffer pairs allows a larger number of background - threads to compress in parallel. If you find that parallel - compression is consuming too much memory or CPU, you can adjust this - value downward. - - - - The default value is 16. Different values may deliver better or - worse results, depending on your priorities and the dynamic - performance characteristics of your storage and compute resources. - - - - This property is not the number of buffer pairs to use; it is an - upper limit. An illustration: Suppose you have an application that - uses the default value of this property (which is 16), and it runs - on a machine with 2 CPU cores. In that case, DotNetZip will allocate - 4 buffer pairs per CPU core, for a total of 8 pairs. The upper - limit specified by this property has no effect. - - - - The application can set this value at any time - before calling ZipFile.Save(). - - - - - - - - Provides a string representation of the instance. - a string representation of the instance. - - - - Returns the version number on the DotNetZip assembly. - - - - - This property is exposed as a convenience. Callers could also get the - version value by retrieving GetName().Version on the - System.Reflection.Assembly object pointing to the DotNetZip - assembly. But sometimes it is not clear which assembly is being loaded. - This property makes it clear. - - - This static property is primarily useful for diagnostic purposes. - - - - - - Creates a new ZipFile instance, using the specified filename. - - - - - Applications can use this constructor to create a new ZipFile for writing, - or to slurp in an existing zip archive for read and update purposes. - - - - To create a new zip archive, an application can call this constructor, - passing the name of a file that does not exist. The name may be a fully - qualified path. Then the application can add directories or files to the - ZipFile via AddDirectory(), AddFile(), AddItem() - and then write the zip archive to the disk by calling Save(). The - zip file is not actually opened and written to the disk until the - application calls ZipFile.Save(). At that point the new zip file - with the given name is created. - - - - If you won't know the name of the Zipfile until the time you call - ZipFile.Save(), or if you plan to save to a stream (which has no - name), then you should use the no-argument constructor. - - - - The application can also call this constructor to read an existing zip - archive. passing the name of a valid zip file that does exist. But, it's - better form to use the static method, - passing the name of the zip file, because using ZipFile.Read() in - your code communicates very clearly what you are doing. In either case, - the file is then read into the ZipFile instance. The app can then - enumerate the entries or can modify the zip file, for example adding - entries, removing entries, changing comments, and so on. - - - - One advantage to this parameterized constructor: it allows applications to - use the same code to add items to a zip archive, regardless of whether the - zip file exists. - - - - Instances of the ZipFile class are not multi-thread safe. You may - not party on a single instance with multiple threads. You may have - multiple threads that each use a distinct ZipFile instance, or you - can synchronize multi-thread access to a single instance. - - - - By the way, since DotNetZip is so easy to use, don't you think you should - donate $5 or $10? - - - - - - Thrown if name refers to an existing file that is not a valid zip file. - - - - This example shows how to create a zipfile, and add a few files into it. - - String ZipFileToCreate = "archive1.zip"; - String DirectoryToZip = "c:\\reports"; - using (ZipFile zip = new ZipFile()) - { - // Store all files found in the top level directory, into the zip archive. - String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); - zip.AddFiles(filenames, "files"); - zip.Save(ZipFileToCreate); - } - - - - Dim ZipFileToCreate As String = "archive1.zip" - Dim DirectoryToZip As String = "c:\reports" - Using zip As ZipFile = New ZipFile() - Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) - zip.AddFiles(filenames, "files") - zip.Save(ZipFileToCreate) - End Using - - - - The filename to use for the new zip archive. - - - - - Creates a new ZipFile instance, using the specified name for the - filename, and the specified Encoding. - - - - - See the documentation on the ZipFile - constructor that accepts a single string argument for basic - information on all the ZipFile constructors. - - - - The Encoding is used as the default alternate encoding for entries with - filenames or comments that cannot be encoded with the IBM437 code page. - This is equivalent to setting the property on the ZipFile - instance after construction. - - - - Instances of the ZipFile class are not multi-thread safe. You may - not party on a single instance with multiple threads. You may have - multiple threads that each use a distinct ZipFile instance, or you - can synchronize multi-thread access to a single instance. - - - - - - Thrown if name refers to an existing file that is not a valid zip file. - - - The filename to use for the new zip archive. - The Encoding is used as the default alternate - encoding for entries with filenames or comments that cannot be encoded - with the IBM437 code page. - - - - Create a zip file, without specifying a target filename or stream to save to. - - - - - See the documentation on the ZipFile - constructor that accepts a single string argument for basic - information on all the ZipFile constructors. - - - - After instantiating with this constructor and adding entries to the - archive, the application should call or - to save to a file or a - stream, respectively. The application can also set the - property and then call the no-argument method. (This - is the preferred approach for applications that use the library through - COM interop.) If you call the no-argument method - without having set the Name of the ZipFile, either through - the parameterized constructor or through the explicit property , the - Save() will throw, because there is no place to save the file. - - - Instances of the ZipFile class are not multi-thread safe. You may - have multiple threads that each use a distinct ZipFile instance, or - you can synchronize multi-thread access to a single instance. - - - - - This example creates a Zip archive called Backup.zip, containing all the files - in the directory DirectoryToZip. Files within subdirectories are not zipped up. - - using (ZipFile zip = new ZipFile()) - { - // Store all files found in the top level directory, into the zip archive. - // note: this code does not recurse subdirectories! - String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); - zip.AddFiles(filenames, "files"); - zip.Save("Backup.zip"); - } - - - - Using zip As New ZipFile - ' Store all files found in the top level directory, into the zip archive. - ' note: this code does not recurse subdirectories! - Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) - zip.AddFiles(filenames, "files") - zip.Save("Backup.zip") - End Using - - - - - - Create a zip file, specifying a text Encoding, but without specifying a - target filename or stream to save to. - - - - - See the documentation on the ZipFile - constructor that accepts a single string argument for basic - information on all the ZipFile constructors. - - - - - - The Encoding is used as the default alternate encoding for entries with - filenames or comments that cannot be encoded with the IBM437 code page. - - - - - Creates a new ZipFile instance, using the specified name for the - filename, and the specified status message writer. - - - - - See the documentation on the ZipFile - constructor that accepts a single string argument for basic - information on all the ZipFile constructors. - - - - This version of the constructor allows the caller to pass in a TextWriter, - to which verbose messages will be written during extraction or creation of - the zip archive. A console application may wish to pass - System.Console.Out to get messages on the Console. A graphical or headless - application may wish to capture the messages in a different - TextWriter, for example, a StringWriter, and then display - the messages in a TextBox, or generate an audit log of ZipFile operations. - - - - To encrypt the data for the files added to the ZipFile instance, - set the Password property after creating the ZipFile instance. - - - - Instances of the ZipFile class are not multi-thread safe. You may - not party on a single instance with multiple threads. You may have - multiple threads that each use a distinct ZipFile instance, or you - can synchronize multi-thread access to a single instance. - - - - - - Thrown if name refers to an existing file that is not a valid zip file. - - - - - using (ZipFile zip = new ZipFile("Backup.zip", Console.Out)) - { - // Store all files found in the top level directory, into the zip archive. - // note: this code does not recurse subdirectories! - // Status messages will be written to Console.Out - String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); - zip.AddFiles(filenames); - zip.Save(); - } - - - - Using zip As New ZipFile("Backup.zip", Console.Out) - ' Store all files found in the top level directory, into the zip archive. - ' note: this code does not recurse subdirectories! - ' Status messages will be written to Console.Out - Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) - zip.AddFiles(filenames) - zip.Save() - End Using - - - - The filename to use for the new zip archive. - A TextWriter to use for writing - verbose status messages. - - - - Creates a new ZipFile instance, using the specified name for the - filename, the specified status message writer, and the specified Encoding. - - - - - This constructor works like the ZipFile - constructor that accepts a single string argument. See that - reference for detail on what this constructor does. - - - - This version of the constructor allows the caller to pass in a - TextWriter, and an Encoding. The TextWriter will collect - verbose messages that are generated by the library during extraction or - creation of the zip archive. A console application may wish to pass - System.Console.Out to get messages on the Console. A graphical or - headless application may wish to capture the messages in a different - TextWriter, for example, a StringWriter, and then display - the messages in a TextBox, or generate an audit log of - ZipFile operations. - - - - The Encoding is used as the default alternate encoding for entries - with filenames or comments that cannot be encoded with the IBM437 code - page. This is a equivalent to setting the property on the ZipFile - instance after construction. - - - - To encrypt the data for the files added to the ZipFile instance, - set the Password property after creating the ZipFile - instance. - - - - Instances of the ZipFile class are not multi-thread safe. You may - not party on a single instance with multiple threads. You may have - multiple threads that each use a distinct ZipFile instance, or you - can synchronize multi-thread access to a single instance. - - - - - - Thrown if fileName refers to an existing file that is not a valid zip file. - - - The filename to use for the new zip archive. - A TextWriter to use for writing verbose - status messages. - - The Encoding is used as the default alternate encoding for entries with - filenames or comments that cannot be encoded with the IBM437 code page. - - - - - Initialize a ZipFile instance by reading in a zip file. - - - - - - This method is primarily useful from COM Automation environments, when - reading or extracting zip files. In COM, it is not possible to invoke - parameterized constructors for a class. A COM Automation application can - update a zip file by using the default (no argument) - constructor, then calling Initialize() to read the contents - of an on-disk zip archive into the ZipFile instance. - - - - .NET applications are encouraged to use the ZipFile.Read() methods - for better clarity. - - - - the name of the existing zip file to read in. - - - - This is an integer indexer into the Zip archive. - - - - - This property is read-only. - - - - Internally, the ZipEntry instances that belong to the - ZipFile are stored in a Dictionary. When you use this - indexer the first time, it creates a read-only - List<ZipEntry> from the Dictionary.Values Collection. - If at any time you modify the set of entries in the ZipFile, - either by adding an entry, removing an entry, or renaming an - entry, a new List will be created, and the numeric indexes for the - remaining entries may be different. - - - - This means you cannot rename any ZipEntry from - inside an enumeration of the zip file. - - - - The index value. - - - - - - The ZipEntry within the Zip archive at the specified index. If the - entry does not exist in the archive, this indexer throws. - - - - - - This is a name-based indexer into the Zip archive. - - - - - This property is read-only. - - - - The property on the ZipFile - determines whether retrieval via this indexer is done via case-sensitive - comparisons. By default, retrieval is not case sensitive. This makes - sense on Windows, in which filesystems are not case sensitive. - - - - Regardless of case-sensitivity, it is not always the case that - this[value].FileName == value. In other words, the FileName - property of the ZipEntry retrieved with this indexer, may or may - not be equal to the index value. - - - - This is because DotNetZip performs a normalization of filenames passed to - this indexer, before attempting to retrieve the item. That normalization - includes: removal of a volume letter and colon, swapping backward slashes - for forward slashes. So, zip["dir1\\entry1.txt"].FileName == - "dir1/entry.txt". - - - - Directory entries in the zip file may be retrieved via this indexer only - with names that have a trailing slash. DotNetZip automatically appends a - trailing slash to the names of any directory entries added to a zip. - - - - - - This example extracts only the entries in a zip file that are .txt files. - - using (ZipFile zip = ZipFile.Read("PackedDocuments.zip")) - { - foreach (string s1 in zip.EntryFilenames) - { - if (s1.EndsWith(".txt")) - zip[s1].Extract("textfiles"); - } - } - - - Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip") - Dim s1 As String - For Each s1 In zip.EntryFilenames - If s1.EndsWith(".txt") Then - zip(s1).Extract("textfiles") - End If - Next - End Using - - - - - - Thrown if the caller attempts to assign a non-null value to the indexer. - - - - The name of the file, including any directory path, to retrieve from the - zip. The filename match is not case-sensitive by default; you can use the - property to change this behavior. The - pathname can use forward-slashes or backward slashes. - - - - The ZipEntry within the Zip archive, given by the specified - filename. If the named entry does not exist in the archive, this indexer - returns null (Nothing in VB). - - - - - - The list of filenames for the entries contained within the zip archive. - - - - According to the ZIP specification, the names of the entries use forward - slashes in pathnames. If you are scanning through the list, you may have - to swap forward slashes for backslashes. - - - - - - This example shows one way to test if a filename is already contained - within a zip archive. - - String zipFileToRead= "PackedDocuments.zip"; - string candidate = "DatedMaterial.xps"; - using (ZipFile zip = new ZipFile(zipFileToRead)) - { - if (zip.EntryFilenames.Contains(candidate)) - Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", - candidate, - zipFileName); - else - Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", - candidate, - zipFileName); - Console.WriteLine(); - } - - - Dim zipFileToRead As String = "PackedDocuments.zip" - Dim candidate As String = "DatedMaterial.xps" - Using zip As ZipFile.Read(ZipFileToRead) - If zip.EntryFilenames.Contains(candidate) Then - Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", _ - candidate, _ - zipFileName) - Else - Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", _ - candidate, _ - zipFileName) - End If - Console.WriteLine - End Using - - - - - The list of strings for the filenames contained within the Zip archive. - - - - - - Returns the readonly collection of entries in the Zip archive. - - - - - - If there are no entries in the current ZipFile, the value returned is a - non-null zero-element collection. If there are entries in the zip file, - the elements are returned in no particular order. - - - This is the implied enumerator on the ZipFile class. If you use a - ZipFile instance in a context that expects an enumerator, you will - get this collection. - - - - - - - Returns a readonly collection of entries in the Zip archive, sorted by FileName. - - - - If there are no entries in the current ZipFile, the value returned - is a non-null zero-element collection. If there are entries in the zip - file, the elements are returned sorted by the name of the entry. - - - - - This example fills a Windows Forms ListView with the entries in a zip file. - - - using (ZipFile zip = ZipFile.Read(zipFile)) - { - foreach (ZipEntry entry in zip.EntriesSorted) - { - ListViewItem item = new ListViewItem(n.ToString()); - n++; - string[] subitems = new string[] { - entry.FileName.Replace("/","\\"), - entry.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), - entry.UncompressedSize.ToString(), - String.Format("{0,5:F0}%", entry.CompressionRatio), - entry.CompressedSize.ToString(), - (entry.UsesEncryption) ? "Y" : "N", - String.Format("{0:X8}", entry.Crc)}; - - foreach (String s in subitems) - { - ListViewItem.ListViewSubItem subitem = new ListViewItem.ListViewSubItem(); - subitem.Text = s; - item.SubItems.Add(subitem); - } - - this.listView1.Items.Add(item); - } - } - - - - - - - - Returns the number of entries in the Zip archive. - - - - - Removes the given ZipEntry from the zip archive. - - - - - After calling RemoveEntry, the application must call Save to - make the changes permanent. - - - - - Thrown if the specified ZipEntry does not exist in the ZipFile. - - - - In this example, all entries in the zip archive dating from before - December 31st, 2007, are removed from the archive. This is actually much - easier if you use the RemoveSelectedEntries method. But I needed an - example for RemoveEntry, so here it is. - - String ZipFileToRead = "ArchiveToModify.zip"; - System.DateTime Threshold = new System.DateTime(2007,12,31); - using (ZipFile zip = ZipFile.Read(ZipFileToRead)) - { - var EntriesToRemove = new System.Collections.Generic.List<ZipEntry>(); - foreach (ZipEntry e in zip) - { - if (e.LastModified < Threshold) - { - // We cannot remove the entry from the list, within the context of - // an enumeration of said list. - // So we add the doomed entry to a list to be removed later. - EntriesToRemove.Add(e); - } - } - - // actually remove the doomed entries. - foreach (ZipEntry zombie in EntriesToRemove) - zip.RemoveEntry(zombie); - - zip.Comment= String.Format("This zip archive was updated at {0}.", - System.DateTime.Now.ToString("G")); - - // save with a different name - zip.Save("Archive-Updated.zip"); - } - - - - Dim ZipFileToRead As String = "ArchiveToModify.zip" - Dim Threshold As New DateTime(2007, 12, 31) - Using zip As ZipFile = ZipFile.Read(ZipFileToRead) - Dim EntriesToRemove As New System.Collections.Generic.List(Of ZipEntry) - Dim e As ZipEntry - For Each e In zip - If (e.LastModified < Threshold) Then - ' We cannot remove the entry from the list, within the context of - ' an enumeration of said list. - ' So we add the doomed entry to a list to be removed later. - EntriesToRemove.Add(e) - End If - Next - - ' actually remove the doomed entries. - Dim zombie As ZipEntry - For Each zombie In EntriesToRemove - zip.RemoveEntry(zombie) - Next - zip.Comment = String.Format("This zip archive was updated at {0}.", DateTime.Now.ToString("G")) - 'save as a different name - zip.Save("Archive-Updated.zip") - End Using - - - - - The ZipEntry to remove from the zip. - - - - - - - - Removes the ZipEntry with the given filename from the zip archive. - - - - - After calling RemoveEntry, the application must call Save to - make the changes permanent. - - - - - - Thrown if the ZipFile is not updatable. - - - - Thrown if a ZipEntry with the specified filename does not exist in - the ZipFile. - - - - - This example shows one way to remove an entry with a given filename from - an existing zip archive. - - - String zipFileToRead= "PackedDocuments.zip"; - string candidate = "DatedMaterial.xps"; - using (ZipFile zip = ZipFile.Read(zipFileToRead)) - { - if (zip.EntryFilenames.Contains(candidate)) - { - zip.RemoveEntry(candidate); - zip.Comment= String.Format("The file '{0}' has been removed from this archive.", - Candidate); - zip.Save(); - } - } - - - Dim zipFileToRead As String = "PackedDocuments.zip" - Dim candidate As String = "DatedMaterial.xps" - Using zip As ZipFile = ZipFile.Read(zipFileToRead) - If zip.EntryFilenames.Contains(candidate) Then - zip.RemoveEntry(candidate) - zip.Comment = String.Format("The file '{0}' has been removed from this archive.", Candidate) - zip.Save - End If - End Using - - - - - The name of the file, including any directory path, to remove from the zip. - The filename match is not case-sensitive by default; you can use the - CaseSensitiveRetrieval property to change this behavior. The - pathname can use forward-slashes or backward slashes. - - - - - - Closes the read and write streams associated - to the ZipFile, if necessary. - - - - The Dispose() method is generally employed implicitly, via a using(..) {..} - statement. (Using...End Using in VB) If you do not employ a using - statement, insure that your application calls Dispose() explicitly. For - example, in a Powershell application, or an application that uses the COM - interop interface, you must call Dispose() explicitly. - - - - This example extracts an entry selected by name, from the Zip file to the - Console. - - using (ZipFile zip = ZipFile.Read(zipfile)) - { - foreach (ZipEntry e in zip) - { - if (WantThisEntry(e.FileName)) - zip.Extract(e.FileName, Console.OpenStandardOutput()); - } - } // Dispose() is called implicitly here. - - - - Using zip As ZipFile = ZipFile.Read(zipfile) - Dim e As ZipEntry - For Each e In zip - If WantThisEntry(e.FileName) Then - zip.Extract(e.FileName, Console.OpenStandardOutput()) - End If - Next - End Using ' Dispose is implicity called here - - - - - - Disposes any managed resources, if the flag is set, then marks the - instance disposed. This method is typically not called explicitly from - application code. - - - - Applications should call the no-arg Dispose method. - - - - indicates whether the method should dispose streams or not. - - - - - Default size of the buffer used for IO. - - - - - An event handler invoked when a Save() starts, before and after each - entry has been written to the archive, when a Save() completes, and - during other Save events. - - - - - Depending on the particular event, different properties on the parameter are set. The following - table summarizes the available EventTypes and the conditions under - which this event handler is invoked with a - SaveProgressEventArgs with the given EventType. - - - - - value of EntryType - Meaning and conditions - - - - ZipProgressEventType.Saving_Started - Fired when ZipFile.Save() begins. - - - - - ZipProgressEventType.Saving_BeforeSaveEntry - - Fired within ZipFile.Save(), just before writing data for each - particular entry. - - - - - ZipProgressEventType.Saving_AfterSaveEntry - - Fired within ZipFile.Save(), just after having finished writing data - for each particular entry. - - - - - ZipProgressEventType.Saving_Completed - Fired when ZipFile.Save() has completed. - - - - - ZipProgressEventType.Saving_AfterSaveTempArchive - - Fired after the temporary file has been created. This happens only - when saving to a disk file. This event will not be invoked when - saving to a stream. - - - - - ZipProgressEventType.Saving_BeforeRenameTempArchive - - Fired just before renaming the temporary file to the permanent - location. This happens only when saving to a disk file. This event - will not be invoked when saving to a stream. - - - - - ZipProgressEventType.Saving_AfterRenameTempArchive - - Fired just after renaming the temporary file to the permanent - location. This happens only when saving to a disk file. This event - will not be invoked when saving to a stream. - - - - - ZipProgressEventType.Saving_AfterCompileSelfExtractor - - Fired after a self-extracting archive has finished compiling. This - EventType is used only within SaveSelfExtractor(). - - - - - ZipProgressEventType.Saving_BytesRead - - Set during the save of a particular entry, to update progress of the - Save(). When this EventType is set, the BytesTransferred is the - number of bytes that have been read from the source stream. The - TotalBytesToTransfer is the number of bytes in the uncompressed - file. - - - - - - - - - This example uses an anonymous method to handle the - SaveProgress event, by updating a progress bar. - - - progressBar1.Value = 0; - progressBar1.Max = listbox1.Items.Count; - using (ZipFile zip = new ZipFile()) - { - // listbox1 contains a list of filenames - zip.AddFiles(listbox1.Items); - - // do the progress bar: - zip.SaveProgress += (sender, e) => { - if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) { - progressBar1.PerformStep(); - } - }; - - zip.Save(fs); - } - - - - - This example uses a named method as the - SaveProgress event handler, to update the user, in a - console-based application. - - - static bool justHadByteUpdate= false; - public static void SaveProgress(object sender, SaveProgressEventArgs e) - { - if (e.EventType == ZipProgressEventType.Saving_Started) - Console.WriteLine("Saving: {0}", e.ArchiveName); - - else if (e.EventType == ZipProgressEventType.Saving_Completed) - { - justHadByteUpdate= false; - Console.WriteLine(); - Console.WriteLine("Done: {0}", e.ArchiveName); - } - - else if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) - { - if (justHadByteUpdate) - Console.WriteLine(); - Console.WriteLine(" Writing: {0} ({1}/{2})", - e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal); - justHadByteUpdate= false; - } - - else if (e.EventType == ZipProgressEventType.Saving_EntryBytesRead) - { - if (justHadByteUpdate) - Console.SetCursorPosition(0, Console.CursorTop); - Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, - e.BytesTransferred / (0.01 * e.TotalBytesToTransfer )); - justHadByteUpdate= true; - } - } - - public static ZipUp(string targetZip, string directory) - { - using (var zip = new ZipFile()) { - zip.SaveProgress += SaveProgress; - zip.AddDirectory(directory); - zip.Save(targetZip); - } - } - - - - - Public Sub ZipUp(ByVal targetZip As String, ByVal directory As String) - Using zip As ZipFile = New ZipFile - AddHandler zip.SaveProgress, AddressOf MySaveProgress - zip.AddDirectory(directory) - zip.Save(targetZip) - End Using - End Sub - - Private Shared justHadByteUpdate As Boolean = False - - Public Shared Sub MySaveProgress(ByVal sender As Object, ByVal e As SaveProgressEventArgs) - If (e.EventType Is ZipProgressEventType.Saving_Started) Then - Console.WriteLine("Saving: {0}", e.ArchiveName) - - ElseIf (e.EventType Is ZipProgressEventType.Saving_Completed) Then - justHadByteUpdate = False - Console.WriteLine - Console.WriteLine("Done: {0}", e.ArchiveName) - - ElseIf (e.EventType Is ZipProgressEventType.Saving_BeforeWriteEntry) Then - If justHadByteUpdate Then - Console.WriteLine - End If - Console.WriteLine(" Writing: {0} ({1}/{2})", e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal) - justHadByteUpdate = False - - ElseIf (e.EventType Is ZipProgressEventType.Saving_EntryBytesRead) Then - If justHadByteUpdate Then - Console.SetCursorPosition(0, Console.CursorTop) - End If - Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, _ - e.TotalBytesToTransfer, _ - (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))) - justHadByteUpdate = True - End If - End Sub - - - - - - This is a more complete example of using the SaveProgress - events in a Windows Forms application, with a - Thread object. - - - delegate void SaveEntryProgress(SaveProgressEventArgs e); - delegate void ButtonClick(object sender, EventArgs e); - - public class WorkerOptions - { - public string ZipName; - public string Folder; - public string Encoding; - public string Comment; - public int ZipFlavor; - public Zip64Option Zip64; - } - - private int _progress2MaxFactor; - private bool _saveCanceled; - private long _totalBytesBeforeCompress; - private long _totalBytesAfterCompress; - private Thread _workerThread; - - - private void btnZipup_Click(object sender, EventArgs e) - { - KickoffZipup(); - } - - private void btnCancel_Click(object sender, EventArgs e) - { - if (this.lblStatus.InvokeRequired) - { - this.lblStatus.Invoke(new ButtonClick(this.btnCancel_Click), new object[] { sender, e }); - } - else - { - _saveCanceled = true; - lblStatus.Text = "Canceled..."; - ResetState(); - } - } - - private void KickoffZipup() - { - _folderName = tbDirName.Text; - - if (_folderName == null || _folderName == "") return; - if (this.tbZipName.Text == null || this.tbZipName.Text == "") return; - - // check for existence of the zip file: - if (System.IO.File.Exists(this.tbZipName.Text)) - { - var dlgResult = MessageBox.Show(String.Format("The file you have specified ({0}) already exists." + - " Do you want to overwrite this file?", this.tbZipName.Text), - "Confirmation is Required", MessageBoxButtons.YesNo, MessageBoxIcon.Question); - if (dlgResult != DialogResult.Yes) return; - System.IO.File.Delete(this.tbZipName.Text); - } - - _saveCanceled = false; - _nFilesCompleted = 0; - _totalBytesAfterCompress = 0; - _totalBytesBeforeCompress = 0; - this.btnOk.Enabled = false; - this.btnOk.Text = "Zipping..."; - this.btnCancel.Enabled = true; - lblStatus.Text = "Zipping..."; - - var options = new WorkerOptions - { - ZipName = this.tbZipName.Text, - Folder = _folderName, - Encoding = "ibm437" - }; - - if (this.comboBox1.SelectedIndex != 0) - { - options.Encoding = this.comboBox1.SelectedItem.ToString(); - } - - if (this.radioFlavorSfxCmd.Checked) - options.ZipFlavor = 2; - else if (this.radioFlavorSfxGui.Checked) - options.ZipFlavor = 1; - else options.ZipFlavor = 0; - - if (this.radioZip64AsNecessary.Checked) - options.Zip64 = Zip64Option.AsNecessary; - else if (this.radioZip64Always.Checked) - options.Zip64 = Zip64Option.Always; - else options.Zip64 = Zip64Option.Never; - - options.Comment = String.Format("Encoding:{0} || Flavor:{1} || ZIP64:{2}\r\nCreated at {3} || {4}\r\n", - options.Encoding, - FlavorToString(options.ZipFlavor), - options.Zip64.ToString(), - System.DateTime.Now.ToString("yyyy-MMM-dd HH:mm:ss"), - this.Text); - - if (this.tbComment.Text != TB_COMMENT_NOTE) - options.Comment += this.tbComment.Text; - - _workerThread = new Thread(this.DoSave); - _workerThread.Name = "Zip Saver thread"; - _workerThread.Start(options); - this.Cursor = Cursors.WaitCursor; - } - - - private void DoSave(Object p) - { - WorkerOptions options = p as WorkerOptions; - try - { - using (var zip1 = new ZipFile()) - { - zip1.ProvisionalAlternateEncoding = System.Text.Encoding.GetEncoding(options.Encoding); - zip1.Comment = options.Comment; - zip1.AddDirectory(options.Folder); - _entriesToZip = zip1.EntryFileNames.Count; - SetProgressBars(); - zip1.SaveProgress += this.zip1_SaveProgress; - - zip1.UseZip64WhenSaving = options.Zip64; - - if (options.ZipFlavor == 1) - zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.WinFormsApplication); - else if (options.ZipFlavor == 2) - zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.ConsoleApplication); - else - zip1.Save(options.ZipName); - } - } - catch (System.Exception exc1) - { - MessageBox.Show(String.Format("Exception while zipping: {0}", exc1.Message)); - btnCancel_Click(null, null); - } - } - - - - void zip1_SaveProgress(object sender, SaveProgressEventArgs e) - { - switch (e.EventType) - { - case ZipProgressEventType.Saving_AfterWriteEntry: - StepArchiveProgress(e); - break; - case ZipProgressEventType.Saving_EntryBytesRead: - StepEntryProgress(e); - break; - case ZipProgressEventType.Saving_Completed: - SaveCompleted(); - break; - case ZipProgressEventType.Saving_AfterSaveTempArchive: - // this event only occurs when saving an SFX file - TempArchiveSaved(); - break; - } - if (_saveCanceled) - e.Cancel = true; - } - - - - private void StepArchiveProgress(SaveProgressEventArgs e) - { - if (this.progressBar1.InvokeRequired) - { - this.progressBar1.Invoke(new SaveEntryProgress(this.StepArchiveProgress), new object[] { e }); - } - else - { - if (!_saveCanceled) - { - _nFilesCompleted++; - this.progressBar1.PerformStep(); - _totalBytesAfterCompress += e.CurrentEntry.CompressedSize; - _totalBytesBeforeCompress += e.CurrentEntry.UncompressedSize; - - // reset the progress bar for the entry: - this.progressBar2.Value = this.progressBar2.Maximum = 1; - - this.Update(); - } - } - } - - - private void StepEntryProgress(SaveProgressEventArgs e) - { - if (this.progressBar2.InvokeRequired) - { - this.progressBar2.Invoke(new SaveEntryProgress(this.StepEntryProgress), new object[] { e }); - } - else - { - if (!_saveCanceled) - { - if (this.progressBar2.Maximum == 1) - { - // reset - Int64 max = e.TotalBytesToTransfer; - _progress2MaxFactor = 0; - while (max > System.Int32.MaxValue) - { - max /= 2; - _progress2MaxFactor++; - } - this.progressBar2.Maximum = (int)max; - lblStatus.Text = String.Format("{0} of {1} files...({2})", - _nFilesCompleted + 1, _entriesToZip, e.CurrentEntry.FileName); - } - - int xferred = e.BytesTransferred >> _progress2MaxFactor; - - this.progressBar2.Value = (xferred >= this.progressBar2.Maximum) - ? this.progressBar2.Maximum - : xferred; - - this.Update(); - } - } - } - - private void SaveCompleted() - { - if (this.lblStatus.InvokeRequired) - { - this.lblStatus.Invoke(new MethodInvoker(this.SaveCompleted)); - } - else - { - lblStatus.Text = String.Format("Done, Compressed {0} files, {1:N0}% of original.", - _nFilesCompleted, (100.00 * _totalBytesAfterCompress) / _totalBytesBeforeCompress); - ResetState(); - } - } - - private void ResetState() - { - this.btnCancel.Enabled = false; - this.btnOk.Enabled = true; - this.btnOk.Text = "Zip it!"; - this.progressBar1.Value = 0; - this.progressBar2.Value = 0; - this.Cursor = Cursors.Default; - if (!_workerThread.IsAlive) - _workerThread.Join(); - } - - - - - - - - - - - An event handler invoked before, during, and after the reading of a zip archive. - - - - - Depending on the particular event being signaled, different properties on the - parameter are set. The following table - summarizes the available EventTypes and the conditions under which this - event handler is invoked with a ReadProgressEventArgs with the given EventType. - - - - - value of EntryType - Meaning and conditions - - - - ZipProgressEventType.Reading_Started - Fired just as ZipFile.Read() begins. Meaningful properties: ArchiveName. - - - - - ZipProgressEventType.Reading_Completed - Fired when ZipFile.Read() has completed. Meaningful properties: ArchiveName. - - - - - ZipProgressEventType.Reading_ArchiveBytesRead - Fired while reading, updates the number of bytes read for the entire archive. - Meaningful properties: ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer. - - - - - ZipProgressEventType.Reading_BeforeReadEntry - Indicates an entry is about to be read from the archive. - Meaningful properties: ArchiveName, EntriesTotal. - - - - - ZipProgressEventType.Reading_AfterReadEntry - Indicates an entry has just been read from the archive. - Meaningful properties: ArchiveName, EntriesTotal, CurrentEntry. - - - - - - - - - - - - - An event handler invoked before, during, and after extraction of - entries in the zip archive. - - - - - Depending on the particular event, different properties on the parameter are set. The following - table summarizes the available EventTypes and the conditions under - which this event handler is invoked with a - ExtractProgressEventArgs with the given EventType. - - - - - value of EntryType - Meaning and conditions - - - - ZipProgressEventType.Extracting_BeforeExtractAll - - Set when ExtractAll() begins. The ArchiveName, Overwrite, and - ExtractLocation properties are meaningful. - - - - ZipProgressEventType.Extracting_AfterExtractAll - - Set when ExtractAll() has completed. The ArchiveName, Overwrite, - and ExtractLocation properties are meaningful. - - - - - ZipProgressEventType.Extracting_BeforeExtractEntry - - Set when an Extract() on an entry in the ZipFile has begun. - Properties that are meaningful: ArchiveName, EntriesTotal, - CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted. - - - - - ZipProgressEventType.Extracting_AfterExtractEntry - - Set when an Extract() on an entry in the ZipFile has completed. - Properties that are meaningful: ArchiveName, EntriesTotal, - CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted. - - - - - ZipProgressEventType.Extracting_EntryBytesWritten - - Set within a call to Extract() on an entry in the ZipFile, as data - is extracted for the entry. Properties that are meaningful: - ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer. - - - - - ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite - - Set within a call to Extract() on an entry in the ZipFile, when the - extraction would overwrite an existing file. This event type is used - only when ExtractExistingFileAction on the ZipFile or - ZipEntry is set to InvokeExtractProgressEvent. - - - - - - - - - - private static bool justHadByteUpdate = false; - public static void ExtractProgress(object sender, ExtractProgressEventArgs e) - { - if(e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten) - { - if (justHadByteUpdate) - Console.SetCursorPosition(0, Console.CursorTop); - - Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, - e.BytesTransferred / (0.01 * e.TotalBytesToTransfer )); - justHadByteUpdate = true; - } - else if(e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry) - { - if (justHadByteUpdate) - Console.WriteLine(); - Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName); - justHadByteUpdate= false; - } - } - - public static ExtractZip(string zipToExtract, string directory) - { - string TargetDirectory= "extract"; - using (var zip = ZipFile.Read(zipToExtract)) { - zip.ExtractProgress += ExtractProgress; - foreach (var e in zip1) - { - e.Extract(TargetDirectory, true); - } - } - } - - - - Public Shared Sub Main(ByVal args As String()) - Dim ZipToUnpack As String = "C1P3SML.zip" - Dim TargetDir As String = "ExtractTest_Extract" - Console.WriteLine("Extracting file {0} to {1}", ZipToUnpack, TargetDir) - Using zip1 As ZipFile = ZipFile.Read(ZipToUnpack) - AddHandler zip1.ExtractProgress, AddressOf MyExtractProgress - Dim e As ZipEntry - For Each e In zip1 - e.Extract(TargetDir, True) - Next - End Using - End Sub - - Private Shared justHadByteUpdate As Boolean = False - - Public Shared Sub MyExtractProgress(ByVal sender As Object, ByVal e As ExtractProgressEventArgs) - If (e.EventType = ZipProgressEventType.Extracting_EntryBytesWritten) Then - If ExtractTest.justHadByteUpdate Then - Console.SetCursorPosition(0, Console.CursorTop) - End If - Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))) - ExtractTest.justHadByteUpdate = True - ElseIf (e.EventType = ZipProgressEventType.Extracting_BeforeExtractEntry) Then - If ExtractTest.justHadByteUpdate Then - Console.WriteLine - End If - Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName) - ExtractTest.justHadByteUpdate = False - End If - End Sub - - - - - - - - - - An event handler invoked before, during, and after Adding entries to a zip archive. - - - - Adding a large number of entries to a zip file can take a long - time. For example, when calling on a - directory that contains 50,000 files, it could take 3 minutes or so. - This event handler allws an application to track the progress of the Add - operation, and to optionally cancel a lengthy Add operation. - - - - - - int _numEntriesToAdd= 0; - int _numEntriesAdded= 0; - void AddProgressHandler(object sender, AddProgressEventArgs e) - { - switch (e.EventType) - { - case ZipProgressEventType.Adding_Started: - Console.WriteLine("Adding files to the zip..."); - break; - case ZipProgressEventType.Adding_AfterAddEntry: - _numEntriesAdded++; - Console.WriteLine(String.Format("Adding file {0}/{1} :: {2}", - _numEntriesAdded, _numEntriesToAdd, e.CurrentEntry.FileName)); - break; - case ZipProgressEventType.Adding_Completed: - Console.WriteLine("Added all files"); - break; - } - } - - void CreateTheZip() - { - using (ZipFile zip = new ZipFile()) - { - zip.AddProgress += AddProgressHandler; - zip.AddDirectory(System.IO.Path.GetFileName(DirToZip)); - zip.Save(ZipFileToCreate); - } - } - - - - - - Private Sub AddProgressHandler(ByVal sender As Object, ByVal e As AddProgressEventArgs) - Select Case e.EventType - Case ZipProgressEventType.Adding_Started - Console.WriteLine("Adding files to the zip...") - Exit Select - Case ZipProgressEventType.Adding_AfterAddEntry - Console.WriteLine(String.Format("Adding file {0}", e.CurrentEntry.FileName)) - Exit Select - Case ZipProgressEventType.Adding_Completed - Console.WriteLine("Added all files") - Exit Select - End Select - End Sub - - Sub CreateTheZip() - Using zip as ZipFile = New ZipFile - AddHandler zip.AddProgress, AddressOf AddProgressHandler - zip.AddDirectory(System.IO.Path.GetFileName(DirToZip)) - zip.Save(ZipFileToCreate); - End Using - End Sub - - - - - - - - - - - - An event that is raised when an error occurs during open or read of files - while saving a zip archive. - - - - - Errors can occur as a file is being saved to the zip archive. For - example, the File.Open may fail, or a File.Read may fail, because of - lock conflicts or other reasons. If you add a handler to this event, - you can handle such errors in your own code. If you don't add a - handler, the library will throw an exception if it encounters an I/O - error during a call to Save(). - - - - Setting a handler implicitly sets to - ZipErrorAction.InvokeErrorEvent. - - - - The handler you add applies to all items that are - subsequently added to the ZipFile instance. If you set this - property after you have added items to the ZipFile, but before you - have called Save(), errors that occur while saving those items - will not cause the error handler to be invoked. - - - - If you want to handle any errors that occur with any entry in the zip - file using the same error handler, then add your error handler once, - before adding any entries to the zip archive. - - - - In the error handler method, you need to set the property on the - ZipErrorEventArgs.CurrentEntry. This communicates back to - DotNetZip what you would like to do with this particular error. Within - an error handler, if you set the ZipEntry.ZipErrorAction property - on the ZipEntry to ZipErrorAction.InvokeErrorEvent or if - you don't set it at all, the library will throw the exception. (It is the - same as if you had set the ZipEntry.ZipErrorAction property on the - ZipEntry to ZipErrorAction.Throw.) If you set the - ZipErrorEventArgs.Cancel to true, the entire Save() will be - canceled. - - - - In the case that you use ZipErrorAction.Skip, implying that - you want to skip the entry for which there's been an error, DotNetZip - tries to seek backwards in the output stream, and truncate all bytes - written on behalf of that particular entry. This works only if the - output stream is seekable. It will not work, for example, when using - ASPNET's Response.OutputStream. - - - - - - - This example shows how to use an event handler to handle - errors during save of the zip file. - - - public static void MyZipError(object sender, ZipErrorEventArgs e) - { - Console.WriteLine("Error saving {0}...", e.FileName); - Console.WriteLine(" Exception: {0}", e.exception); - ZipEntry entry = e.CurrentEntry; - string response = null; - // Ask the user whether he wants to skip this error or not - do - { - Console.Write("Retry, Skip, Throw, or Cancel ? (R/S/T/C) "); - response = Console.ReadLine(); - Console.WriteLine(); - - } while (response != null && - response[0]!='S' && response[0]!='s' && - response[0]!='R' && response[0]!='r' && - response[0]!='T' && response[0]!='t' && - response[0]!='C' && response[0]!='c'); - - e.Cancel = (response[0]=='C' || response[0]=='c'); - - if (response[0]=='S' || response[0]=='s') - entry.ZipErrorAction = ZipErrorAction.Skip; - else if (response[0]=='R' || response[0]=='r') - entry.ZipErrorAction = ZipErrorAction.Retry; - else if (response[0]=='T' || response[0]=='t') - entry.ZipErrorAction = ZipErrorAction.Throw; - } - - public void SaveTheFile() - { - string directoryToZip = "fodder"; - string directoryInArchive = "files"; - string zipFileToCreate = "Archive.zip"; - using (var zip = new ZipFile()) - { - // set the event handler before adding any entries - zip.ZipError += MyZipError; - zip.AddDirectory(directoryToZip, directoryInArchive); - zip.Save(zipFileToCreate); - } - } - - - - Private Sub MyZipError(ByVal sender As Object, ByVal e As Ionic.Zip.ZipErrorEventArgs) - ' At this point, the application could prompt the user for an action to take. - ' But in this case, this application will simply automatically skip the file, in case of error. - Console.WriteLine("Zip Error, entry {0}", e.CurrentEntry.FileName) - Console.WriteLine(" Exception: {0}", e.exception) - ' set the desired ZipErrorAction on the CurrentEntry to communicate that to DotNetZip - e.CurrentEntry.ZipErrorAction = Zip.ZipErrorAction.Skip - End Sub - - Public Sub SaveTheFile() - Dim directoryToZip As String = "fodder" - Dim directoryInArchive As String = "files" - Dim zipFileToCreate as String = "Archive.zip" - Using zipArchive As ZipFile = New ZipFile - ' set the event handler before adding any entries - AddHandler zipArchive.ZipError, AddressOf MyZipError - zipArchive.AddDirectory(directoryToZip, directoryInArchive) - zipArchive.Save(zipFileToCreate) - End Using - End Sub - - - - - - - - - Extracts all of the items in the zip archive, to the specified path in the - filesystem. The path can be relative or fully-qualified. - - - - - This method will extract all entries in the ZipFile to the - specified path. - - - - If an extraction of a file from the zip archive would overwrite an - existing file in the filesystem, the action taken is dictated by the - ExtractExistingFile property, which overrides any setting you may have - made on individual ZipEntry instances. By default, if you have not - set that property on the ZipFile instance, the entry will not - be extracted, the existing file will not be overwritten and an - exception will be thrown. To change this, set the property, or use the - overload that allows you to - specify an ExtractExistingFileAction parameter. - - - - The action to take when an extract would overwrite an existing file - applies to all entries. If you want to set this on a per-entry basis, - then you must use one of the ZipEntry.Extract methods. - - - - This method will send verbose output messages to the , if it is set on the ZipFile - instance. - - - - You may wish to take advantage of the ExtractProgress event. - - - - About timestamps: When extracting a file entry from a zip archive, the - extracted file gets the last modified time of the entry as stored in - the archive. The archive may also store extended file timestamp - information, including last accessed and created times. If these are - present in the ZipEntry, then the extracted file will also get - these times. - - - - A Directory entry is somewhat different. It will get the times as - described for a file entry, but, if there are file entries in the zip - archive that, when extracted, appear in the just-created directory, - then when those file entries are extracted, the last modified and last - accessed times of the directory will change, as a side effect. The - result is that after an extraction of a directory and a number of - files within the directory, the last modified and last accessed - timestamps on the directory will reflect the time that the last file - was extracted into the directory, rather than the time stored in the - zip archive for the directory. - - - - To compensate, when extracting an archive with ExtractAll, - DotNetZip will extract all the file and directory entries as described - above, but it will then make a second pass on the directories, and - reset the times on the directories to reflect what is stored in the - zip archive. - - - - This compensation is performed only within the context of an - ExtractAll. If you call ZipEntry.Extract on a directory - entry, the timestamps on directory in the filesystem will reflect the - times stored in the zip. If you then call ZipEntry.Extract on - a file entry, which is extracted into the directory, the timestamps on - the directory will be updated to the current time. - - - - - This example extracts all the entries in a zip archive file, to the - specified target directory. The extraction will overwrite any - existing files silently. - - - String TargetDirectory= "unpack"; - using(ZipFile zip= ZipFile.Read(ZipFileToExtract)) - { - zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently; - zip.ExtractAll(TargetDirectory); - } - - - - Dim TargetDirectory As String = "unpack" - Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) - zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently - zip.ExtractAll(TargetDirectory) - End Using - - - - - - - - The path to which the contents of the zipfile will be extracted. - The path can be relative or fully-qualified. - - - - - - Extracts all of the items in the zip archive, to the specified path in the - filesystem, using the specified behavior when extraction would overwrite an - existing file. - - - - - - This method will extract all entries in the ZipFile to the specified - path. For an extraction that would overwrite an existing file, the behavior - is dictated by , which overrides any - setting you may have made on individual ZipEntry instances. - - - - The action to take when an extract would overwrite an existing file - applies to all entries. If you want to set this on a per-entry basis, - then you must use or one of the similar methods. - - - - Calling this method is equivalent to setting the property and then calling . - - - - This method will send verbose output messages to the - , if it is set on the ZipFile instance. - - - - - This example extracts all the entries in a zip archive file, to the - specified target directory. It does not overwrite any existing files. - - String TargetDirectory= "c:\\unpack"; - using(ZipFile zip= ZipFile.Read(ZipFileToExtract)) - { - zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite); - } - - - - Dim TargetDirectory As String = "c:\unpack" - Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) - zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite) - End Using - - - - - The path to which the contents of the zipfile will be extracted. - The path can be relative or fully-qualified. - - - - The action to take if extraction would overwrite an existing file. - - - - - - Reads a zip file archive and returns the instance. - - - - - The stream is read using the default System.Text.Encoding, which is the - IBM437 codepage. - - - - - Thrown if the ZipFile cannot be read. The implementation of this method - relies on System.IO.File.OpenRead, which can throw a variety of exceptions, - including specific exceptions if a file is not found, an unauthorized access - exception, exceptions for poorly formatted filenames, and so on. - - - - The name of the zip archive to open. This can be a fully-qualified or relative - pathname. - - - . - - The instance read from the zip archive. - - - - - Reads a zip file archive from the named filesystem file using the - specified options. - - - - - This version of the Read() method allows the caller to pass - in a TextWriter an Encoding, via an instance of the - ReadOptions class. The ZipFile is read in using the - specified encoding for entries where UTF-8 encoding is not - explicitly specified. - - - - - - - This example shows how to read a zip file using the Big-5 Chinese - code page (950), and extract each entry in the zip file, while - sending status messages out to the Console. - - - - For this code to work as intended, the zipfile must have been - created using the big5 code page (CP950). This is typical, for - example, when using WinRar on a machine with CP950 set as the - default code page. In that case, the names of entries within the - Zip archive will be stored in that code page, and reading the zip - archive must be done using that code page. If the application did - not use the correct code page in ZipFile.Read(), then names of - entries within the zip archive would not be correctly retrieved. - - - - string zipToExtract = "MyArchive.zip"; - string extractDirectory = "extract"; - var options = new ReadOptions - { - StatusMessageWriter = System.Console.Out, - Encoding = System.Text.Encoding.GetEncoding(950) - }; - using (ZipFile zip = ZipFile.Read(zipToExtract, options)) - { - foreach (ZipEntry e in zip) - { - e.Extract(extractDirectory); - } - } - - - - - Dim zipToExtract as String = "MyArchive.zip" - Dim extractDirectory as String = "extract" - Dim options as New ReadOptions - options.Encoding = System.Text.Encoding.GetEncoding(950) - options.StatusMessageWriter = System.Console.Out - Using zip As ZipFile = ZipFile.Read(zipToExtract, options) - Dim e As ZipEntry - For Each e In zip - e.Extract(extractDirectory) - Next - End Using - - - - - - - - This example shows how to read a zip file using the default - code page, to remove entries that have a modified date before a given threshold, - sending status messages out to a StringWriter. - - - - var options = new ReadOptions - { - StatusMessageWriter = new System.IO.StringWriter() - }; - using (ZipFile zip = ZipFile.Read("PackedDocuments.zip", options)) - { - var Threshold = new DateTime(2007,7,4); - // We cannot remove the entry from the list, within the context of - // an enumeration of said list. - // So we add the doomed entry to a list to be removed later. - // pass 1: mark the entries for removal - var MarkedEntries = new System.Collections.Generic.List<ZipEntry>(); - foreach (ZipEntry e in zip) - { - if (e.LastModified < Threshold) - MarkedEntries.Add(e); - } - // pass 2: actually remove the entry. - foreach (ZipEntry zombie in MarkedEntries) - zip.RemoveEntry(zombie); - zip.Comment = "This archive has been updated."; - zip.Save(); - } - // can now use contents of sw, eg store in an audit log - - - - Dim options as New ReadOptions - options.StatusMessageWriter = New System.IO.StringWriter - Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip", options) - Dim Threshold As New DateTime(2007, 7, 4) - ' We cannot remove the entry from the list, within the context of - ' an enumeration of said list. - ' So we add the doomed entry to a list to be removed later. - ' pass 1: mark the entries for removal - Dim MarkedEntries As New System.Collections.Generic.List(Of ZipEntry) - Dim e As ZipEntry - For Each e In zip - If (e.LastModified < Threshold) Then - MarkedEntries.Add(e) - End If - Next - ' pass 2: actually remove the entry. - Dim zombie As ZipEntry - For Each zombie In MarkedEntries - zip.RemoveEntry(zombie) - Next - zip.Comment = "This archive has been updated." - zip.Save - End Using - ' can now use contents of sw, eg store in an audit log - - - - - Thrown if the zipfile cannot be read. The implementation of - this method relies on System.IO.File.OpenRead, which - can throw a variety of exceptions, including specific - exceptions if a file is not found, an unauthorized access - exception, exceptions for poorly formatted filenames, and so - on. - - - - The name of the zip archive to open. - This can be a fully-qualified or relative pathname. - - - - The set of options to use when reading the zip file. - - - The ZipFile instance read from the zip archive. - - - - - - - Reads a zip file archive using the specified text encoding, the specified - TextWriter for status messages, and the specified ReadProgress event handler, - and returns the instance. - - - - The name of the zip archive to open. - This can be a fully-qualified or relative pathname. - - - - An event handler for Read operations. - - - - The System.IO.TextWriter to use for writing verbose status messages - during operations on the zip archive. A console application may wish to - pass System.Console.Out to get messages on the Console. A graphical - or headless application may wish to capture the messages in a different - TextWriter, such as a System.IO.StringWriter. - - - - The System.Text.Encoding to use when reading in the zip archive. Be - careful specifying the encoding. If the value you use here is not the same - as the Encoding used when the zip archive was created (possibly by a - different archiver) you will get unexpected results and possibly exceptions. - - - The instance read from the zip archive. - - - - - Reads a zip archive from a stream. - - - - - - When reading from a file, it's probably easier to just use - ZipFile.Read(String, ReadOptions). This - overload is useful when when the zip archive content is - available from an already-open stream. The stream must be - open and readable and seekable when calling this method. The - stream is left open when the reading is completed. - - - - Using this overload, the stream is read using the default - System.Text.Encoding, which is the IBM437 - codepage. If you want to specify the encoding to use when - reading the zipfile content, see - ZipFile.Read(Stream, ReadOptions). This - - - - Reading of zip content begins at the current position in the - stream. This means if you have a stream that concatenates - regular data and zip data, if you position the open, readable - stream at the start of the zip data, you will be able to read - the zip archive using this constructor, or any of the ZipFile - constructors that accept a as - input. Some examples of where this might be useful: the zip - content is concatenated at the end of a regular EXE file, as - some self-extracting archives do. (Note: SFX files produced - by DotNetZip do not work this way; they can be read as normal - ZIP files). Another example might be a stream being read from - a database, where the zip content is embedded within an - aggregate stream of data. - - - - - - - This example shows how to Read zip content from a stream, and - extract one entry into a different stream. In this example, - the filename "NameOfEntryInArchive.doc", refers only to the - name of the entry within the zip archive. A file by that - name is not created in the filesystem. The I/O is done - strictly with the given streams. - - - - using (ZipFile zip = ZipFile.Read(InputStream)) - { - zip.Extract("NameOfEntryInArchive.doc", OutputStream); - } - - - - Using zip as ZipFile = ZipFile.Read(InputStream) - zip.Extract("NameOfEntryInArchive.doc", OutputStream) - End Using - - - - the stream containing the zip data. - - The ZipFile instance read from the stream - - - - - Reads a zip file archive from the given stream using the - specified options. - - - - - - When reading from a file, it's probably easier to just use - ZipFile.Read(String, ReadOptions). This - overload is useful when when the zip archive content is - available from an already-open stream. The stream must be - open and readable and seekable when calling this method. The - stream is left open when the reading is completed. - - - - Reading of zip content begins at the current position in the - stream. This means if you have a stream that concatenates - regular data and zip data, if you position the open, readable - stream at the start of the zip data, you will be able to read - the zip archive using this constructor, or any of the ZipFile - constructors that accept a as - input. Some examples of where this might be useful: the zip - content is concatenated at the end of a regular EXE file, as - some self-extracting archives do. (Note: SFX files produced - by DotNetZip do not work this way; they can be read as normal - ZIP files). Another example might be a stream being read from - a database, where the zip content is embedded within an - aggregate stream of data. - - - - the stream containing the zip data. - - - The set of options to use when reading the zip file. - - - - Thrown if the zip archive cannot be read. - - - The ZipFile instance read from the stream. - - - - - - - Reads a zip archive from a stream, using the specified text Encoding, the - specified TextWriter for status messages, - and the specified ReadProgress event handler. - - - - - Reading of zip content begins at the current position in the stream. This - means if you have a stream that concatenates regular data and zip data, if - you position the open, readable stream at the start of the zip data, you - will be able to read the zip archive using this constructor, or any of the - ZipFile constructors that accept a as - input. Some examples of where this might be useful: the zip content is - concatenated at the end of a regular EXE file, as some self-extracting - archives do. (Note: SFX files produced by DotNetZip do not work this - way). Another example might be a stream being read from a database, where - the zip content is embedded within an aggregate stream of data. - - - - the stream containing the zip data. - - - The System.IO.TextWriter to which verbose status messages are written - during operations on the ZipFile. For example, in a console - application, System.Console.Out works, and will get a message for each entry - added to the ZipFile. If the TextWriter is null, no verbose messages - are written. - - - - The text encoding to use when reading entries that do not have the UTF-8 - encoding bit set. Be careful specifying the encoding. If the value you use - here is not the same as the Encoding used when the zip archive was created - (possibly by a different archiver) you will get unexpected results and - possibly exceptions. See the - property for more information. - - - - An event handler for Read operations. - - - an instance of ZipFile - - - - Checks the given file to see if it appears to be a valid zip file. - - - - - Calling this method is equivalent to calling with the testExtract parameter set to false. - - - - The file to check. - true if the file appears to be a zip file. - - - - Checks a file to see if it is a valid zip file. - - - - - This method opens the specified zip file, reads in the zip archive, - verifying the ZIP metadata as it reads. - - - - If everything succeeds, then the method returns true. If anything fails - - for example if an incorrect signature or CRC is found, indicating a - corrupt file, the the method returns false. This method also returns - false for a file that does not exist. - - - - If is true, as part of its check, this - method reads in the content for each entry, expands it, and checks CRCs. - This provides an additional check beyond verifying the zip header and - directory data. - - - - If is true, and if any of the zip entries - are protected with a password, this method will return false. If you want - to verify a ZipFile that has entries which are protected with a - password, you will need to do that manually. - - - - - The zip file to check. - true if the caller wants to extract each entry. - true if the file contains a valid zip file. - - - - Checks a stream to see if it contains a valid zip archive. - - - - - This method reads the zip archive contained in the specified stream, verifying - the ZIP metadata as it reads. If testExtract is true, this method also extracts - each entry in the archive, dumping all the bits into . - - - - If everything succeeds, then the method returns true. If anything fails - - for example if an incorrect signature or CRC is found, indicating a corrupt - file, the the method returns false. This method also returns false for a - file that does not exist. - - - - If testExtract is true, this method reads in the content for each - entry, expands it, and checks CRCs. This provides an additional check - beyond verifying the zip header data. - - - - If testExtract is true, and if any of the zip entries are protected - with a password, this method will return false. If you want to verify a - ZipFile that has entries which are protected with a password, you will need - to do that manually. - - - - - - The stream to check. - true if the caller wants to extract each entry. - true if the stream contains a valid zip archive. - - - - Delete file with retry on UnauthorizedAccessException. - - - - - When calling File.Delete() on a file that has been "recently" - created, the call sometimes fails with - UnauthorizedAccessException. This method simply retries the Delete 3 - times with a sleep between tries. - - - - the name of the file to be deleted - - - - Saves the Zip archive to a file, specified by the Name property of the - ZipFile. - - - - - The ZipFile instance is written to storage, typically a zip file - in a filesystem, only when the caller calls Save. In the typical - case, the Save operation writes the zip content to a temporary file, and - then renames the temporary file to the desired name. If necessary, this - method will delete a pre-existing file before the rename. - - - - The property is specified either explicitly, - or implicitly using one of the parameterized ZipFile constructors. For - COM Automation clients, the Name property must be set explicitly, - because COM Automation clients cannot call parameterized constructors. - - - - When using a filesystem file for the Zip output, it is possible to call - Save multiple times on the ZipFile instance. With each - call the zip content is re-written to the same output file. - - - - Data for entries that have been added to the ZipFile instance is - written to the output when the Save method is called. This means - that the input streams for those entries must be available at the time - the application calls Save. If, for example, the application - adds entries with AddEntry using a dynamically-allocated - MemoryStream, the memory stream must not have been disposed - before the call to Save. See the property for more discussion of the - availability requirements of the input stream for an entry, and an - approach for providing just-in-time stream lifecycle management. - - - - - - - - Thrown if you haven't specified a location or stream for saving the zip, - either in the constructor or by setting the Name property, or if you try - to save a regular zip archive to a filename with a .exe extension. - - - - Thrown if or is non-zero, and the number - of segments that would be generated for the spanned zip file during the - save operation exceeds 99. If this happens, you need to increase the - segment size. - - - - - - Save the file to a new zipfile, with the given name. - - - - - This method allows the application to explicitly specify the name of the zip - file when saving. Use this when creating a new zip file, or when - updating a zip archive. - - - - An application can also save a zip archive in several places by calling this - method multiple times in succession, with different filenames. - - - - The ZipFile instance is written to storage, typically a zip file in a - filesystem, only when the caller calls Save. The Save operation writes - the zip content to a temporary file, and then renames the temporary file - to the desired name. If necessary, this method will delete a pre-existing file - before the rename. - - - - - - Thrown if you specify a directory for the filename. - - - - The name of the zip archive to save to. Existing files will - be overwritten with great prejudice. - - - - This example shows how to create and Save a zip file. - - using (ZipFile zip = new ZipFile()) - { - zip.AddDirectory(@"c:\reports\January"); - zip.Save("January.zip"); - } - - - - Using zip As New ZipFile() - zip.AddDirectory("c:\reports\January") - zip.Save("January.zip") - End Using - - - - - - This example shows how to update a zip file. - - using (ZipFile zip = ZipFile.Read("ExistingArchive.zip")) - { - zip.AddFile("NewData.csv"); - zip.Save("UpdatedArchive.zip"); - } - - - - Using zip As ZipFile = ZipFile.Read("ExistingArchive.zip") - zip.AddFile("NewData.csv") - zip.Save("UpdatedArchive.zip") - End Using - - - - - - - Save the zip archive to the specified stream. - - - - - The ZipFile instance is written to storage - typically a zip file - in a filesystem, but using this overload, the storage can be anything - accessible via a writable stream - only when the caller calls Save. - - - - Use this method to save the zip content to a stream directly. A common - scenario is an ASP.NET application that dynamically generates a zip file - and allows the browser to download it. The application can call - Save(Response.OutputStream) to write a zipfile directly to the - output stream, without creating a zip file on the disk on the ASP.NET - server. - - - - Be careful when saving a file to a non-seekable stream, including - Response.OutputStream. When DotNetZip writes to a non-seekable - stream, the zip archive is formatted in such a way that may not be - compatible with all zip tools on all platforms. It's a perfectly legal - and compliant zip file, but some people have reported problems opening - files produced this way using the Mac OS archive utility. - - - - - - - This example saves the zipfile content into a MemoryStream, and - then gets the array of bytes from that MemoryStream. - - - using (var zip = new Ionic.Zip.ZipFile()) - { - zip.CompressionLevel= Ionic.Zlib.CompressionLevel.BestCompression; - zip.Password = "VerySecret."; - zip.Encryption = EncryptionAlgorithm.WinZipAes128; - zip.AddFile(sourceFileName); - MemoryStream output = new MemoryStream(); - zip.Save(output); - - byte[] zipbytes = output.ToArray(); - } - - - - - - This example shows a pitfall you should avoid. DO NOT read - from a stream, then try to save to the same stream. DO - NOT DO THIS: - - - - using (var fs = new FileStream(filename, FileMode.Open)) - { - using (var zip = Ionic.Zip.ZipFile.Read(inputStream)) - { - zip.AddEntry("Name1.txt", "this is the content"); - zip.Save(inputStream); // NO NO NO!! - } - } - - - - Better like this: - - - - using (var zip = Ionic.Zip.ZipFile.Read(filename)) - { - zip.AddEntry("Name1.txt", "this is the content"); - zip.Save(); // YES! - } - - - - - - The System.IO.Stream to write to. It must be - writable. If you created the ZipFile instance by calling - ZipFile.Read(), this stream must not be the same stream - you passed to ZipFile.Read(). - - - - - Adds to the ZipFile a set of files from the current working directory on - disk, that conform to the specified criteria. - - - - - This method selects files from the the current working directory matching - the specified criteria, and adds them to the ZipFile. - - - - Specify the criteria in statements of 3 elements: a noun, an operator, and - a value. Consider the string "name != *.doc" . The noun is "name". The - operator is "!=", implying "Not Equal". The value is "*.doc". That - criterion, in English, says "all files with a name that does not end in - the .doc extension." - - - - Supported nouns include "name" (or "filename") for the filename; "atime", - "mtime", and "ctime" for last access time, last modfied time, and created - time of the file, respectively; "attributes" (or "attrs") for the file - attributes; "size" (or "length") for the file length (uncompressed), and - "type" for the type of object, either a file or a directory. The - "attributes", "name" and "type" nouns both support = and != as operators. - The "size", "atime", "mtime", and "ctime" nouns support = and !=, and - >, >=, <, <= as well. The times are taken to be expressed in - local time. - - - - Specify values for the file attributes as a string with one or more of the - characters H,R,S,A,I,L in any order, implying file attributes of Hidden, - ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint (symbolic - link) respectively. - - - - To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as the - format. If you omit the HH:mm:ss portion, it is assumed to be 00:00:00 - (midnight). - - - - The value for a size criterion is expressed in integer quantities of bytes, - kilobytes (use k or kb after the number), megabytes (m or mb), or gigabytes - (g or gb). - - - - The value for a name is a pattern to match against the filename, potentially - including wildcards. The pattern follows CMD.exe glob rules: * implies one - or more of any character, while ? implies one character. If the name - pattern contains any slashes, it is matched to the entire filename, - including the path; otherwise, it is matched against only the filename - without the path. This means a pattern of "*\*.*" matches all files one - directory level deep, while a pattern of "*.*" matches all files in all - directories. - - - - To specify a name pattern that includes spaces, use single quotes around the - pattern. A pattern of "'* *.*'" will match all files that have spaces in - the filename. The full criteria string for that would be "name = '* *.*'" . - - - - The value for a type criterion is either F (implying a file) or D (implying - a directory). - - - - Some examples: - - - - - criteria - Files retrieved - - - - name != *.xls - any file with an extension that is not .xls - - - - - name = *.mp3 - any file with a .mp3 extension. - - - - - *.mp3 - (same as above) any file with a .mp3 extension. - - - - - attributes = A - all files whose attributes include the Archive bit. - - - - - attributes != H - all files whose attributes do not include the Hidden bit. - - - - - mtime > 2009-01-01 - all files with a last modified time after January 1st, 2009. - - - - - size > 2gb - all files whose uncompressed size is greater than 2gb. - - - - - type = D - all directories in the filesystem. - - - - - - You can combine criteria with the conjunctions AND or OR. Using a string - like "name = *.txt AND size >= 100k" for the selectionCriteria retrieves - entries whose names end in .txt, and whose uncompressed size is greater than - or equal to 100 kilobytes. - - - - For more complex combinations of criteria, you can use parenthesis to group - clauses in the boolean logic. Without parenthesis, the precedence of the - criterion atoms is determined by order of appearance. Unlike the C# - language, the AND conjunction does not take precendence over the logical OR. - This is important only in strings that contain 3 or more criterion atoms. - In other words, "name = *.txt and size > 1000 or attributes = H" implies - "((name = *.txt AND size > 1000) OR attributes = H)" while "attributes = - H OR name = *.txt and size > 1000" evaluates to "((attributes = H OR name - = *.txt) AND size > 1000)". When in doubt, use parenthesis. - - - - Using time properties requires some extra care. If you want to retrieve all - entries that were last updated on 2009 February 14, specify a time range - like so:"mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this to - say: all files updated after 12:00am on February 14th, until 12:00am on - February 15th. You can use the same bracketing approach to specify any time - period - a year, a month, a week, and so on. - - - - The syntax allows one special case: if you provide a string with no spaces, it is - treated as a pattern to match for the filename. Therefore a string like "*.xls" - will be equivalent to specifying "name = *.xls". - - - - There is no logic in this method that insures that the file inclusion - criteria are internally consistent. For example, it's possible to specify - criteria that says the file must have a size of less than 100 bytes, as well - as a size that is greater than 1000 bytes. Obviously no file will ever - satisfy such criteria, but this method does not detect such logical - inconsistencies. The caller is responsible for insuring the criteria are - sensible. - - - - Using this method, the file selection does not recurse into - subdirectories, and the full path of the selected files is included in the - entries added into the zip archive. If you don't like these behaviors, - see the other overloads of this method. - - - - - This example zips up all *.csv files in the current working directory. - - using (ZipFile zip = new ZipFile()) - { - // To just match on filename wildcards, - // use the shorthand form of the selectionCriteria string. - zip.AddSelectedFiles("*.csv"); - zip.Save(PathToZipArchive); - } - - - Using zip As ZipFile = New ZipFile() - zip.AddSelectedFiles("*.csv") - zip.Save(PathToZipArchive) - End Using - - - - The criteria for file selection - - - - Adds to the ZipFile a set of files from the disk that conform to the - specified criteria, optionally recursing into subdirectories. - - - - - This method selects files from the the current working directory matching - the specified criteria, and adds them to the ZipFile. If - recurseDirectories is true, files are also selected from - subdirectories, and the directory structure in the filesystem is - reproduced in the zip archive, rooted at the current working directory. - - - - Using this method, the full path of the selected files is included in the - entries added into the zip archive. If you don't want this behavior, use - one of the overloads of this method that allows the specification of a - directoryInArchive. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - - - - This example zips up all *.xml files in the current working directory, or any - subdirectory, that are larger than 1mb. - - - using (ZipFile zip = new ZipFile()) - { - // Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.xml and size > 1024kb", true); - zip.Save(PathToZipArchive); - } - - - Using zip As ZipFile = New ZipFile() - ' Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.xml and size > 1024kb", true) - zip.Save(PathToZipArchive) - End Using - - - - The criteria for file selection - - - If true, the file selection will recurse into subdirectories. - - - - - Adds to the ZipFile a set of files from a specified directory in the - filesystem, that conform to the specified criteria. - - - - - This method selects files that conform to the specified criteria, from the - the specified directory on disk, and adds them to the ZipFile. The search - does not recurse into subdirectores. - - - - Using this method, the full filesystem path of the files on disk is - reproduced on the entries added to the zip file. If you don't want this - behavior, use one of the other overloads of this method. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - - - - This example zips up all *.xml files larger than 1mb in the directory - given by "d:\rawdata". - - - using (ZipFile zip = new ZipFile()) - { - // Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\\rawdata"); - zip.Save(PathToZipArchive); - } - - - - Using zip As ZipFile = New ZipFile() - ' Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\rawdata) - zip.Save(PathToZipArchive) - End Using - - - - The criteria for file selection - - - The name of the directory on the disk from which to select files. - - - - - Adds to the ZipFile a set of files from the specified directory on disk, - that conform to the specified criteria. - - - - - - This method selects files from the the specified disk directory matching - the specified selection criteria, and adds them to the ZipFile. If - recurseDirectories is true, files are also selected from - subdirectories. - - - - The full directory structure in the filesystem is reproduced on the - entries added to the zip archive. If you don't want this behavior, use - one of the overloads of this method that allows the specification of a - directoryInArchive. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - - - This example zips up all *.csv files in the "files" directory, or any - subdirectory, that have been saved since 2009 February 14th. - - - using (ZipFile zip = new ZipFile()) - { - // Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true); - zip.Save(PathToZipArchive); - } - - - Using zip As ZipFile = New ZipFile() - ' Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true) - zip.Save(PathToZipArchive) - End Using - - - - - This example zips up all files in the current working - directory, and all its child directories, except those in - the excludethis subdirectory. - - Using Zip As ZipFile = New ZipFile(zipfile) - Zip.AddSelectedFfiles("name != 'excludethis\*.*'", datapath, True) - Zip.Save() - End Using - - - - The criteria for file selection - - - The filesystem path from which to select files. - - - - If true, the file selection will recurse into subdirectories. - - - - - Adds to the ZipFile a selection of files from the specified directory on - disk, that conform to the specified criteria, and using a specified root - path for entries added to the zip archive. - - - - - This method selects files from the specified disk directory matching the - specified selection criteria, and adds those files to the ZipFile, using - the specified directory path in the archive. The search does not recurse - into subdirectories. For details on the syntax for the selectionCriteria - parameter, see . - - - - - - - This example zips up all *.psd files in the "photos" directory that have - been saved since 2009 February 14th, and puts them all in a zip file, - using the directory name of "content" in the zip archive itself. When the - zip archive is unzipped, the folder containing the .psd files will be - named "content". - - - using (ZipFile zip = new ZipFile()) - { - // Use a compound expression in the selectionCriteria string. - zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content"); - zip.Save(PathToZipArchive); - } - - - Using zip As ZipFile = New ZipFile - zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content") - zip.Save(PathToZipArchive) - End Using - - - - - The criteria for selection of files to add to the ZipFile. - - - - The path to the directory in the filesystem from which to select files. - - - - Specifies a directory path to use to in place of the - directoryOnDisk. This path may, or may not, correspond to a real - directory in the current filesystem. If the files within the zip are - later extracted, this is the path used for the extracted file. Passing - null (nothing in VB) will use the path on the file name, if any; in other - words it would use directoryOnDisk, plus any subdirectory. Passing - the empty string ("") will insert the item at the root path within the - archive. - - - - - Adds to the ZipFile a selection of files from the specified directory on - disk, that conform to the specified criteria, optionally recursing through - subdirectories, and using a specified root path for entries added to the - zip archive. - - - - This method selects files from the specified disk directory that match the - specified selection criteria, and adds those files to the ZipFile, using - the specified directory path in the archive. If recurseDirectories - is true, files are also selected from subdirectories, and the directory - structure in the filesystem is reproduced in the zip archive, rooted at - the directory specified by directoryOnDisk. For details on the - syntax for the selectionCriteria parameter, see . - - - - - This example zips up all files that are NOT *.pst files, in the current - working directory and any subdirectories. - - - using (ZipFile zip = new ZipFile()) - { - zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true); - zip.Save(PathToZipArchive); - } - - - Using zip As ZipFile = New ZipFile - zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true) - zip.Save(PathToZipArchive) - End Using - - - - - The criteria for selection of files to add to the ZipFile. - - - - The path to the directory in the filesystem from which to select files. - - - - Specifies a directory path to use to in place of the - directoryOnDisk. This path may, or may not, correspond to a real - directory in the current filesystem. If the files within the zip are - later extracted, this is the path used for the extracted file. Passing - null (nothing in VB) will use the path on the file name, if any; in other - words it would use directoryOnDisk, plus any subdirectory. Passing - the empty string ("") will insert the item at the root path within the - archive. - - - - If true, the method also scans subdirectories for files matching the - criteria. - - - - - Updates the ZipFile with a selection of files from the disk that conform - to the specified criteria. - - - - This method selects files from the specified disk directory that match the - specified selection criteria, and Updates the ZipFile with those - files, using the specified directory path in the archive. If - recurseDirectories is true, files are also selected from - subdirectories, and the directory structure in the filesystem is - reproduced in the zip archive, rooted at the directory specified by - directoryOnDisk. For details on the syntax for the - selectionCriteria parameter, see . - - - - The criteria for selection of files to add to the ZipFile. - - - - The path to the directory in the filesystem from which to select files. - - - - Specifies a directory path to use to in place of the - directoryOnDisk. This path may, or may not, correspond to a - real directory in the current filesystem. If the files within the zip - are later extracted, this is the path used for the extracted file. - Passing null (nothing in VB) will use the path on the file name, if - any; in other words it would use directoryOnDisk, plus any - subdirectory. Passing the empty string ("") will insert the item at - the root path within the archive. - - - - If true, the method also scans subdirectories for files matching the criteria. - - - - - - - Retrieve entries from the zipfile by specified criteria. - - - - - This method allows callers to retrieve the collection of entries from the zipfile - that fit the specified criteria. The criteria are described in a string format, and - can include patterns for the filename; constraints on the size of the entry; - constraints on the last modified, created, or last accessed time for the file - described by the entry; or the attributes of the entry. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - This method is intended for use with a ZipFile that has been read from storage. - When creating a new ZipFile, this method will work only after the ZipArchive has - been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip - archive from storage.) Calling SelectEntries on a ZipFile that has not yet been - saved will deliver undefined results. - - - - - Thrown if selectionCriteria has an invalid syntax. - - - - This example selects all the PhotoShop files from within an archive, and extracts them - to the current working directory. - - using (ZipFile zip1 = ZipFile.Read(ZipFileName)) - { - var PhotoShopFiles = zip1.SelectEntries("*.psd"); - foreach (ZipEntry psd in PhotoShopFiles) - { - psd.Extract(); - } - } - - - Using zip1 As ZipFile = ZipFile.Read(ZipFileName) - Dim PhotoShopFiles as ICollection(Of ZipEntry) - PhotoShopFiles = zip1.SelectEntries("*.psd") - Dim psd As ZipEntry - For Each psd In PhotoShopFiles - psd.Extract - Next - End Using - - - the string that specifies which entries to select - a collection of ZipEntry objects that conform to the inclusion spec - - - - Retrieve entries from the zipfile by specified criteria. - - - - - This method allows callers to retrieve the collection of entries from the zipfile - that fit the specified criteria. The criteria are described in a string format, and - can include patterns for the filename; constraints on the size of the entry; - constraints on the last modified, created, or last accessed time for the file - described by the entry; or the attributes of the entry. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - This method is intended for use with a ZipFile that has been read from storage. - When creating a new ZipFile, this method will work only after the ZipArchive has - been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip - archive from storage.) Calling SelectEntries on a ZipFile that has not yet been - saved will deliver undefined results. - - - - - Thrown if selectionCriteria has an invalid syntax. - - - - - using (ZipFile zip1 = ZipFile.Read(ZipFileName)) - { - var UpdatedPhotoShopFiles = zip1.SelectEntries("*.psd", "UpdatedFiles"); - foreach (ZipEntry e in UpdatedPhotoShopFiles) - { - // prompt for extract here - if (WantExtract(e.FileName)) - e.Extract(); - } - } - - - Using zip1 As ZipFile = ZipFile.Read(ZipFileName) - Dim UpdatedPhotoShopFiles As ICollection(Of ZipEntry) = zip1.SelectEntries("*.psd", "UpdatedFiles") - Dim e As ZipEntry - For Each e In UpdatedPhotoShopFiles - ' prompt for extract here - If Me.WantExtract(e.FileName) Then - e.Extract - End If - Next - End Using - - - the string that specifies which entries to select - - - the directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - - a collection of ZipEntry objects that conform to the inclusion spec - - - - Remove entries from the zipfile by specified criteria. - - - - - This method allows callers to remove the collection of entries from the zipfile - that fit the specified criteria. The criteria are described in a string format, and - can include patterns for the filename; constraints on the size of the entry; - constraints on the last modified, created, or last accessed time for the file - described by the entry; or the attributes of the entry. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - This method is intended for use with a ZipFile that has been read from storage. - When creating a new ZipFile, this method will work only after the ZipArchive has - been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip - archive from storage.) Calling SelectEntries on a ZipFile that has not yet been - saved will deliver undefined results. - - - - - Thrown if selectionCriteria has an invalid syntax. - - - - This example removes all entries in a zip file that were modified prior to January 1st, 2008. - - using (ZipFile zip1 = ZipFile.Read(ZipFileName)) - { - // remove all entries from prior to Jan 1, 2008 - zip1.RemoveEntries("mtime < 2008-01-01"); - // don't forget to save the archive! - zip1.Save(); - } - - - Using zip As ZipFile = ZipFile.Read(ZipFileName) - ' remove all entries from prior to Jan 1, 2008 - zip1.RemoveEntries("mtime < 2008-01-01") - ' do not forget to save the archive! - zip1.Save - End Using - - - the string that specifies which entries to select - the number of entries removed - - - - Remove entries from the zipfile by specified criteria, and within the specified - path in the archive. - - - - - This method allows callers to remove the collection of entries from the zipfile - that fit the specified criteria. The criteria are described in a string format, and - can include patterns for the filename; constraints on the size of the entry; - constraints on the last modified, created, or last accessed time for the file - described by the entry; or the attributes of the entry. - - - - For details on the syntax for the selectionCriteria parameter, see . - - - - This method is intended for use with a ZipFile that has been read from storage. - When creating a new ZipFile, this method will work only after the ZipArchive has - been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip - archive from storage.) Calling SelectEntries on a ZipFile that has not yet been - saved will deliver undefined results. - - - - - Thrown if selectionCriteria has an invalid syntax. - - - - - using (ZipFile zip1 = ZipFile.Read(ZipFileName)) - { - // remove all entries from prior to Jan 1, 2008 - zip1.RemoveEntries("mtime < 2008-01-01", "documents"); - // a call to ZipFile.Save will make the modifications permanent - zip1.Save(); - } - - - Using zip As ZipFile = ZipFile.Read(ZipFileName) - ' remove all entries from prior to Jan 1, 2008 - zip1.RemoveEntries("mtime < 2008-01-01", "documents") - ' a call to ZipFile.Save will make the modifications permanent - zip1.Save - End Using - - - - the string that specifies which entries to select - - the directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - the number of entries removed - - - - Selects and Extracts a set of Entries from the ZipFile. - - - - - The entries are extracted into the current working directory. - - - - If any of the files to be extracted already exist, then the action taken is as - specified in the property on the - corresponding ZipEntry instance. By default, the action taken in this case is to - throw an exception. - - - - For information on the syntax of the selectionCriteria string, - see . - - - - - This example shows how extract all XML files modified after 15 January 2009. - - using (ZipFile zip = ZipFile.Read(zipArchiveName)) - { - zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15"); - } - - - the selection criteria for entries to extract. - - - - - - Selects and Extracts a set of Entries from the ZipFile. - - - - - The entries are extracted into the current working directory. When extraction would would - overwrite an existing filesystem file, the action taken is as specified in the - parameter. - - - - For information on the syntax of the string describing the entry selection criteria, - see . - - - - - This example shows how extract all XML files modified after 15 January 2009, - overwriting any existing files. - - using (ZipFile zip = ZipFile.Read(zipArchiveName)) - { - zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15", - ExtractExistingFileAction.OverwriteSilently); - } - - - - the selection criteria for entries to extract. - - - The action to take if extraction would overwrite an existing file. - - - - - Selects and Extracts a set of Entries from the ZipFile. - - - - - The entries are selected from the specified directory within the archive, and then - extracted into the current working directory. - - - - If any of the files to be extracted already exist, then the action taken is as - specified in the property on the - corresponding ZipEntry instance. By default, the action taken in this case is to - throw an exception. - - - - For information on the syntax of the string describing the entry selection criteria, - see . - - - - - This example shows how extract all XML files modified after 15 January 2009, - and writes them to the "unpack" directory. - - using (ZipFile zip = ZipFile.Read(zipArchiveName)) - { - zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15","unpack"); - } - - - - the selection criteria for entries to extract. - - - the directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - - - - - - Selects and Extracts a set of Entries from the ZipFile. - - - - - The entries are extracted into the specified directory. If any of the files to be - extracted already exist, an exception will be thrown. - - - For information on the syntax of the string describing the entry selection criteria, - see . - - - - the selection criteria for entries to extract. - - - the directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - - - the directory on the disk into which to extract. It will be created - if it does not exist. - - - - - Selects and Extracts a set of Entries from the ZipFile. - - - - - The entries are extracted into the specified directory. When extraction would would - overwrite an existing filesystem file, the action taken is as specified in the - parameter. - - - - For information on the syntax of the string describing the entry selection criteria, - see . - - - - - This example shows how extract all files with an XML extension or with a size larger than 100,000 bytes, - and puts them in the unpack directory. For any files that already exist in - that destination directory, they will not be overwritten. - - using (ZipFile zip = ZipFile.Read(zipArchiveName)) - { - zip.ExtractSelectedEntries("name = *.xml or size > 100000", - null, - "unpack", - ExtractExistingFileAction.DontOverwrite); - } - - - - the selection criteria for entries to extract. - - - The directory on the disk into which to extract. It will be created if it does not exist. - - - - The directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - - - The action to take if extraction would overwrite an existing file. - - - - - - - - Static constructor for ZipFile - - - Code Pages 437 and 1252 for English are same - Code Page 1252 Windows Latin 1 (ANSI) - - Code Page 437 MS-DOS Latin US - - - - - - The default text encoding used in zip archives. It is numeric 437, also - known as IBM437. - - - - - - Generic IEnumerator support, for use of a ZipFile in an enumeration. - - - - You probably do not want to call GetEnumerator explicitly. Instead - it is implicitly called when you use a loop in C#, or a - For Each loop in VB.NET. - - - - This example reads a zipfile of a given name, then enumerates the - entries in that zip file, and displays the information about each - entry on the Console. - - using (ZipFile zip = ZipFile.Read(zipfile)) - { - bool header = true; - foreach (ZipEntry e in zip) - { - if (header) - { - System.Console.WriteLine("Zipfile: {0}", zip.Name); - System.Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded); - System.Console.WriteLine("BitField: 0x{0:X2}", e.BitField); - System.Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod); - System.Console.WriteLine("\n{1,-22} {2,-6} {3,4} {4,-8} {0}", - "Filename", "Modified", "Size", "Ratio", "Packed"); - System.Console.WriteLine(new System.String('-', 72)); - header = false; - } - - System.Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}", - e.FileName, - e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), - e.UncompressedSize, - e.CompressionRatio, - e.CompressedSize); - - e.Extract(); - } - } - - - - Dim ZipFileToExtract As String = "c:\foo.zip" - Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) - Dim header As Boolean = True - Dim e As ZipEntry - For Each e In zip - If header Then - Console.WriteLine("Zipfile: {0}", zip.Name) - Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded) - Console.WriteLine("BitField: 0x{0:X2}", e.BitField) - Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod) - Console.WriteLine(ChrW(10) & "{1,-22} {2,-6} {3,4} {4,-8} {0}", _ - "Filename", "Modified", "Size", "Ratio", "Packed" ) - Console.WriteLine(New String("-"c, 72)) - header = False - End If - Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}", _ - e.FileName, _ - e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), _ - e.UncompressedSize, _ - e.CompressionRatio, _ - e.CompressedSize ) - e.Extract - Next - End Using - - - - A generic enumerator suitable for use within a foreach loop. - - - - An IEnumerator, for use of a ZipFile in a foreach construct. - - - - This method is included for COM support. An application generally does not call - this method directly. It is called implicitly by COM clients when enumerating - the entries in the ZipFile instance. In VBScript, this is done with a For Each - statement. In Javascript, this is done with new Enumerator(zipfile). - - - - The IEnumerator over the entries in the ZipFile. - - - - - Options for using ZIP64 extensions when saving zip archives. - - - - - - Designed many years ago, the original zip - specification from PKWARE allowed for 32-bit quantities for the - compressed and uncompressed sizes of zip entries, as well as a 32-bit quantity - for specifying the length of the zip archive itself, and a maximum of 65535 - entries. These limits are now regularly exceeded in many backup and archival - scenarios. Recently, PKWare added extensions to the original zip spec, called - "ZIP64 extensions", to raise those limitations. This property governs whether - DotNetZip will use those extensions when writing zip archives. The use of - these extensions is optional and explicit in DotNetZip because, despite the - status of ZIP64 as a bona fide standard, many other zip tools and libraries do - not support ZIP64, and therefore a zip file with ZIP64 extensions may be - unreadable by some of those other tools. - - - - Set this property to to always use ZIP64 - extensions when saving, regardless of whether your zip archive needs it. - Suppose you add 5 files, each under 100k, to a ZipFile. If you specify Always - for this flag, you will get a ZIP64 archive, though the archive does not need - to use ZIP64 because none of the original zip limits had been exceeded. - - - - Set this property to to tell the DotNetZip - library to never use ZIP64 extensions. This is useful for maximum - compatibility and interoperability, at the expense of the capability of - handling large files or large archives. NB: Windows Explorer in Windows XP - and Windows Vista cannot currently extract files from a zip64 archive, so if - you want to guarantee that a zip archive produced by this library will work in - Windows Explorer, use Never. If you set this property to , and your application creates a zip that would - exceed one of the Zip limits, the library will throw an exception while saving - the zip file. - - - - Set this property to to tell the - DotNetZip library to use the ZIP64 extensions when required by the - entry. After the file is compressed, the original and compressed sizes are - checked, and if they exceed the limits described above, then zip64 can be - used. That is the general idea, but there is an additional wrinkle when saving - to a non-seekable device, like the ASP.NET Response.OutputStream, or - Console.Out. When using non-seekable streams for output, the entry - header - which indicates whether zip64 is in use - is emitted before it is - known if zip64 is necessary. It is only after all entries have been saved - that it can be known if ZIP64 will be required. On seekable output streams, - after saving all entries, the library can seek backward and re-emit the zip - file header to be consistent with the actual ZIP64 requirement. But using a - non-seekable output stream, the library cannot seek backward, so the header - can never be changed. In other words, the archive's use of ZIP64 extensions is - not alterable after the header is emitted. Therefore, when saving to - non-seekable streams, using is the same - as using : it will always produce a zip - archive that uses ZIP64 extensions. - - - - - - - The default behavior, which is "Never". - (For COM clients, this is a 0 (zero).) - - - - - Do not use ZIP64 extensions when writing zip archives. - (For COM clients, this is a 0 (zero).) - - - - - Use ZIP64 extensions when writing zip archives, as necessary. - For example, when a single entry exceeds 0xFFFFFFFF in size, or when the archive as a whole - exceeds 0xFFFFFFFF in size, or when there are more than 65535 entries in an archive. - (For COM clients, this is a 1.) - - - - - Always use ZIP64 extensions when writing zip archives, even when unnecessary. - (For COM clients, this is a 2.) - - - - - An enum representing the values on a three-way toggle switch - for various options in the library. This might be used to - specify whether to employ a particular text encoding, or to use - ZIP64 extensions, or some other option. - - - - - The default behavior. This is the same as "Never". - (For COM clients, this is a 0 (zero).) - - - - - Never use the associated option. - (For COM clients, this is a 0 (zero).) - - - - - Use the associated behavior "as necessary." - (For COM clients, this is a 1.) - - - - - Use the associated behavior Always, whether necessary or not. - (For COM clients, this is a 2.) - - - - - A class for collecting the various options that can be used when - Reading zip files for extraction or update. - - - - - When reading a zip file, there are several options an - application can set, to modify how the file is read, or what - the library does while reading. This class collects those - options into one container. - - - - Pass an instance of the ReadOptions class into the - ZipFile.Read() method. - - - . - . - - - - - An event handler for Read operations. When opening large zip - archives, you may want to display a progress bar or other - indicator of status progress while reading. This parameter - allows you to specify a ReadProgress Event Handler directly. - When you call Read(), the progress event is invoked as - necessary. - - - - - The System.IO.TextWriter to use for writing verbose status messages - during operations on the zip archive. A console application may wish to - pass System.Console.Out to get messages on the Console. A graphical - or headless application may wish to capture the messages in a different - TextWriter, such as a System.IO.StringWriter. - - - - - The System.Text.Encoding to use when reading in the zip archive. Be - careful specifying the encoding. If the value you use here is not the same - as the Encoding used when the zip archive was created (possibly by a - different archiver) you will get unexpected results and possibly exceptions. - - - - - - - - Provides a stream metaphor for reading zip files. - - - - - This class provides an alternative programming model for reading zip files to - the one enabled by the class. Use this when reading zip - files, as an alternative to the class, when you would - like to use a Stream class to read the file. - - - - Some application designs require a readable stream for input. This stream can - be used to read a zip file, and extract entries. - - - - Both the ZipInputStream class and the ZipFile class can be used - to read and extract zip files. Both of them support many of the common zip - features, including Unicode, different compression levels, and ZIP64. The - programming models differ. For example, when extracting entries via calls to - the GetNextEntry() and Read() methods on the - ZipInputStream class, the caller is responsible for creating the file, - writing the bytes into the file, setting the attributes on the file, and - setting the created, last modified, and last accessed timestamps on the - file. All of these things are done automatically by a call to ZipEntry.Extract(). For this reason, the - ZipInputStream is generally recommended for when your application wants - to extract the data, without storing that data into a file. - - - - Aside from the obvious differences in programming model, there are some - differences in capability between the ZipFile class and the - ZipInputStream class. - - - - - ZipFile can be used to create or update zip files, or read and - extract zip files. ZipInputStream can be used only to read and - extract zip files. If you want to use a stream to create zip files, check - out the . - - - - ZipInputStream cannot read segmented or spanned - zip files. - - - - ZipInputStream will not read Zip file comments. - - - - When reading larger files, ZipInputStream will always underperform - ZipFile. This is because the ZipInputStream does a full scan on the - zip file, while the ZipFile class reads the central directory of the - zip file. - - - - - - - - - Create a ZipInputStream, wrapping it around an existing stream. - - - - - - While the class is generally easier - to use, this class provides an alternative to those - applications that want to read from a zipfile directly, - using a . - - - - Both the ZipInputStream class and the ZipFile class can be used - to read and extract zip files. Both of them support many of the common zip - features, including Unicode, different compression levels, and ZIP64. The - programming models differ. For example, when extracting entries via calls to - the GetNextEntry() and Read() methods on the - ZipInputStream class, the caller is responsible for creating the file, - writing the bytes into the file, setting the attributes on the file, and - setting the created, last modified, and last accessed timestamps on the - file. All of these things are done automatically by a call to ZipEntry.Extract(). For this reason, the - ZipInputStream is generally recommended for when your application wants - to extract the data, without storing that data into a file. - - - - Aside from the obvious differences in programming model, there are some - differences in capability between the ZipFile class and the - ZipInputStream class. - - - - - ZipFile can be used to create or update zip files, or read and extract - zip files. ZipInputStream can be used only to read and extract zip - files. If you want to use a stream to create zip files, check out the . - - - - ZipInputStream cannot read segmented or spanned - zip files. - - - - ZipInputStream will not read Zip file comments. - - - - When reading larger files, ZipInputStream will always underperform - ZipFile. This is because the ZipInputStream does a full scan on the - zip file, while the ZipFile class reads the central directory of the - zip file. - - - - - - - - The stream to read. It must be readable. This stream will be closed at - the time the ZipInputStream is closed. - - - - - This example shows how to read a zip file, and extract entries, using the - ZipInputStream class. - - - private void Unzip() - { - byte[] buffer= new byte[2048]; - int n; - using (var raw = File.Open(inputFileName, FileMode.Open, FileAccess.Read)) - { - using (var input= new ZipInputStream(raw)) - { - ZipEntry e; - while (( e = input.GetNextEntry()) != null) - { - if (e.IsDirectory) continue; - string outputPath = Path.Combine(extractDir, e.FileName); - using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) - { - while ((n= input.Read(buffer, 0, buffer.Length)) > 0) - { - output.Write(buffer,0,n); - } - } - } - } - } - } - - - - Private Sub UnZip() - Dim inputFileName As String = "MyArchive.zip" - Dim extractDir As String = "extract" - Dim buffer As Byte() = New Byte(2048) {} - Using raw As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read) - Using input As ZipInputStream = New ZipInputStream(raw) - Dim e As ZipEntry - Do While (Not e = input.GetNextEntry Is Nothing) - If Not e.IsDirectory Then - Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _ - FileMode.Create, FileAccess.ReadWrite) - Dim n As Integer - Do While (n = input.Read(buffer, 0, buffer.Length) > 0) - output.Write(buffer, 0, n) - Loop - End Using - End If - Loop - End Using - End Using - End Sub - - - - - - Create a ZipInputStream, given the name of an existing zip file. - - - - - - This constructor opens a FileStream for the given zipfile, and - wraps a ZipInputStream around that. See the documentation for the - constructor for full details. - - - - While the class is generally easier - to use, this class provides an alternative to those - applications that want to read from a zipfile directly, - using a . - - - - - - The name of the filesystem file to read. - - - - - This example shows how to read a zip file, and extract entries, using the - ZipInputStream class. - - - private void Unzip() - { - byte[] buffer= new byte[2048]; - int n; - using (var input= new ZipInputStream(inputFileName)) - { - ZipEntry e; - while (( e = input.GetNextEntry()) != null) - { - if (e.IsDirectory) continue; - string outputPath = Path.Combine(extractDir, e.FileName); - using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) - { - while ((n= input.Read(buffer, 0, buffer.Length)) > 0) - { - output.Write(buffer,0,n); - } - } - } - } - } - - - - Private Sub UnZip() - Dim inputFileName As String = "MyArchive.zip" - Dim extractDir As String = "extract" - Dim buffer As Byte() = New Byte(2048) {} - Using input As ZipInputStream = New ZipInputStream(inputFileName) - Dim e As ZipEntry - Do While (Not e = input.GetNextEntry Is Nothing) - If Not e.IsDirectory Then - Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _ - FileMode.Create, FileAccess.ReadWrite) - Dim n As Integer - Do While (n = input.Read(buffer, 0, buffer.Length) > 0) - output.Write(buffer, 0, n) - Loop - End Using - End If - Loop - End Using - End Sub - - - - - - Create a ZipInputStream, explicitly specifying whether to - keep the underlying stream open. - - - - See the documentation for the ZipInputStream(Stream) - constructor for a discussion of the class, and an example of how to use the class. - - - - The stream to read from. It must be readable. - - - - true if the application would like the stream - to remain open after the ZipInputStream has been closed. - - - - Provides a string representation of the instance. - - - This can be useful for debugging purposes. - - - a string representation of the instance. - - - - The text encoding to use when reading entries into the zip archive, for - those entries whose filenames or comments cannot be encoded with the - default (IBM437) encoding. - - - - - In its - zip specification, PKWare describes two options for encoding - filenames and comments: using IBM437 or UTF-8. But, some archiving tools - or libraries do not follow the specification, and instead encode - characters using the system default code page. For example, WinRAR when - run on a machine in Shanghai may encode filenames with the Big-5 Chinese - (950) code page. This behavior is contrary to the Zip specification, but - it occurs anyway. - - - - When using DotNetZip to read zip archives that use something other than - UTF-8 or IBM437, set this property to specify the code page to use when - reading encoded filenames and comments for each ZipEntry in the zip - file. - - - - This property is "provisional". When the entry in the zip archive is not - explicitly marked as using UTF-8, then IBM437 is used to decode filenames - and comments. If a loss of data would result from using IBM436 - - specifically when encoding and decoding is not reflexive - the codepage - specified here is used. It is possible, therefore, to have a given entry - with a Comment encoded in IBM437 and a FileName encoded with - the specified "provisional" codepage. - - - - When a zip file uses an arbitrary, non-UTF8 code page for encoding, there - is no standard way for the reader application - whether DotNetZip, WinZip, - WinRar, or something else - to know which codepage has been used for the - entries. Readers of zip files are not able to inspect the zip file and - determine the codepage that was used for the entries contained within it. - It is left to the application or user to determine the necessary codepage - when reading zip files encoded this way. If you use an incorrect codepage - when reading a zipfile, you will get entries with filenames that are - incorrect, and the incorrect filenames may even contain characters that - are not legal for use within filenames in Windows. Extracting entries with - illegal characters in the filenames will lead to exceptions. It's too bad, - but this is just the way things are with code pages in zip files. Caveat - Emptor. - - - - - - - Size of the work buffer to use for the ZLIB codec during decompression. - - - - Setting this affects the performance and memory efficiency of compression - and decompression. For larger files, setting this to a larger size may - improve performance, but the exact numbers vary depending on available - memory, and a bunch of other variables. I don't have good firm - recommendations on how to set it. You'll have to test it yourself. Or - just leave it alone and accept the default. - - - - - Sets the password to be used on the ZipInputStream instance. - - - - - - When reading a zip archive, this password is used to read and decrypt the - entries that are encrypted within the zip file. When entries within a zip - file use different passwords, set the appropriate password for the entry - before the first call to Read() for each entry. - - - - When reading an entry that is not encrypted, the value of this property is - ignored. - - - - - - - This example uses the ZipInputStream to read and extract entries from a - zip file, using a potentially different password for each entry. - - - byte[] buffer= new byte[2048]; - int n; - using (var raw = File.Open(_inputFileName, FileMode.Open, FileAccess.Read )) - { - using (var input= new ZipInputStream(raw)) - { - ZipEntry e; - while (( e = input.GetNextEntry()) != null) - { - input.Password = PasswordForEntry(e.FileName); - if (e.IsDirectory) continue; - string outputPath = Path.Combine(_extractDir, e.FileName); - using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) - { - while ((n= input.Read(buffer,0,buffer.Length)) > 0) - { - output.Write(buffer,0,n); - } - } - } - } - } - - - - - - - Read the data from the stream into the buffer. - - - - - The data for the zipentry will be decrypted and uncompressed, as - necessary, before being copied into the buffer. - - - - You must set the property before calling - Read() the first time for an encrypted entry. To determine if an - entry is encrypted and requires a password, check the ZipEntry.Encryption property. - - - - The buffer to hold the data read from the stream. - the offset within the buffer to copy the first byte read. - the number of bytes to read. - the number of bytes read, after decryption and decompression. - - - - Read the next entry from the zip file. - - - - - Call this method just before calling , - to position the pointer in the zip file to the next entry that can be - read. Subsequent calls to Read(), will decrypt and decompress the - data in the zip file, until Read() returns 0. - - - - Each time you call GetNextEntry(), the pointer in the wrapped - stream is moved to the next entry in the zip file. If you call , and thus re-position the pointer within - the file, you will need to call GetNextEntry() again, to insure - that the file pointer is positioned at the beginning of a zip entry. - - - - This method returns the ZipEntry. Using a stream approach, you will - read the raw bytes for an entry in a zip file via calls to Read(). - Alternatively, you can extract an entry into a file, or a stream, by - calling , or one of its siblings. - - - - - - The ZipEntry read. Returns null (or Nothing in VB) if there are no more - entries in the zip file. - - - - - - Dispose the stream. - - - - - This method disposes the ZipInputStream. It may also close the - underlying stream, depending on which constructor was used. - - - - Typically the application will call Dispose() implicitly, via - a using statement in C#, or a Using statement in VB. - - - - Application code won't call this code directly. This method may - be invoked in two distinct scenarios. If disposing == true, the - method has been called directly or indirectly by a user's code, - for example via the public Dispose() method. In this case, both - managed and unmanaged resources can be referenced and disposed. - If disposing == false, the method has been called by the runtime - from inside the object finalizer and this method should not - reference other objects; in that case only unmanaged resources - must be referenced or disposed. - - - - - true if the Dispose method was invoked by user code. - - - - - Always returns true. - - - - - Returns the value of CanSeek for the underlying (wrapped) stream. - - - - - Always returns false. - - - - - Returns the length of the underlying stream. - - - - - Gets or sets the position of the underlying stream. - - - Setting the position is equivalent to calling Seek(value, SeekOrigin.Begin). - - - - - This is a no-op. - - - - - This method always throws a NotSupportedException. - - ignored - ignored - ignored - - - - This method seeks in the underlying stream. - - - - - Call this method if you want to seek around within the zip file for random access. - - - - Applications can intermix calls to Seek() with calls to . After a call to Seek(), - GetNextEntry() will get the next ZipEntry that falls after - the current position in the input stream. You're on your own for finding - out just where to seek in the stream, to get to the various entries. - - - - - the offset point to seek to - the reference point from which to seek - The new position - - - - This method always throws a NotSupportedException. - - ignored - - - - Provides a stream metaphor for generating zip files. - - - - - This class writes zip files, as defined in the specification - for zip files described by PKWare. The compression for this - implementation is provided by a managed-code version of Zlib, included with - DotNetZip in the classes in the Ionic.Zlib namespace. - - - - This class provides an alternative programming model to the one enabled by the - class. Use this when creating zip files, as an - alternative to the class, when you would like to use a - Stream type to write the zip file. - - - - Both the ZipOutputStream class and the ZipFile class can be used - to create zip files. Both of them support many of the common zip features, - including Unicode, different compression levels, and ZIP64. They provide - very similar performance when creating zip files. - - - - The ZipFile class is generally easier to use than - ZipOutputStream and should be considered a higher-level interface. For - example, when creating a zip file via calls to the PutNextEntry() and - Write() methods on the ZipOutputStream class, the caller is - responsible for opening the file, reading the bytes from the file, writing - those bytes into the ZipOutputStream, setting the attributes on the - ZipEntry, and setting the created, last modified, and last accessed - timestamps on the zip entry. All of these things are done automatically by a - call to ZipFile.AddFile(). - For this reason, the ZipOutputStream is generally recommended for use - only when your application emits arbitrary data, not necessarily data from a - filesystem file, directly into a zip file, and does so using a Stream - metaphor. - - - - Aside from the differences in programming model, there are other - differences in capability between the two classes. - - - - - ZipFile can be used to read and extract zip files, in addition to - creating zip files. ZipOutputStream cannot read zip files. If you want - to use a stream to read zip files, check out the class. - - - - ZipOutputStream does not support the creation of segmented or spanned - zip files. - - - - ZipOutputStream cannot produce a self-extracting archive. - - - - - Be aware that the ZipOutputStream class implements the interface. In order for - ZipOutputStream to produce a valid zip file, you use use it within - a using clause (Using in VB), or call the Dispose() method - explicitly. See the examples for how to employ a using clause. - - - - Also, a note regarding compression performance: On the desktop .NET - Framework, DotNetZip can use a multi-threaded compression implementation - that provides significant speed increases on large files, over 300k or so, - at the cost of increased memory use at runtime. (The output of the - compression is almost exactly the same size). But, the multi-threaded - approach incurs a performance hit on smaller files. There's no way for the - ZipOutputStream to know whether parallel compression will be beneficial, - because the ZipOutputStream does not know how much data you will write - through the stream. You may wish to set the property to zero, if you are compressing - large files through ZipOutputStream. This will cause parallel - compression to be used, always. - - - - - - Create a ZipOutputStream, wrapping an existing stream. - - - - - The class is generally easier to use when creating - zip files. The ZipOutputStream offers a different metaphor for creating a - zip file, based on the class. - - - - - - The stream to wrap. It must be writable. This stream will be closed at - the time the ZipOutputStream is closed. - - - - - This example shows how to create a zip file, using the - ZipOutputStream class. - - - private void Zipup() - { - if (filesToZip.Count == 0) - { - System.Console.WriteLine("Nothing to do."); - return; - } - - using (var raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite )) - { - using (var output= new ZipOutputStream(raw)) - { - output.Password = "VerySecret!"; - output.Encryption = EncryptionAlgorithm.WinZipAes256; - - foreach (string inputFileName in filesToZip) - { - System.Console.WriteLine("file: {0}", inputFileName); - - output.PutNextEntry(inputFileName); - using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Write )) - { - byte[] buffer= new byte[2048]; - int n; - while ((n= input.Read(buffer,0,buffer.Length)) > 0) - { - output.Write(buffer,0,n); - } - } - } - } - } - } - - - - Private Sub Zipup() - Dim outputFileName As String = "XmlData.zip" - Dim filesToZip As String() = Directory.GetFiles(".", "*.xml") - If (filesToZip.Length = 0) Then - Console.WriteLine("Nothing to do.") - Else - Using raw As FileStream = File.Open(outputFileName, FileMode.Create, FileAccess.ReadWrite) - Using output As ZipOutputStream = New ZipOutputStream(raw) - output.Password = "VerySecret!" - output.Encryption = EncryptionAlgorithm.WinZipAes256 - Dim inputFileName As String - For Each inputFileName In filesToZip - Console.WriteLine("file: {0}", inputFileName) - output.PutNextEntry(inputFileName) - Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - Dim n As Integer - Dim buffer As Byte() = New Byte(2048) {} - Do While (n = input.Read(buffer, 0, buffer.Length) > 0) - output.Write(buffer, 0, n) - Loop - End Using - Next - End Using - End Using - End If - End Sub - - - - - - Create a ZipOutputStream that writes to a filesystem file. - - - - The class is generally easier to use when creating - zip files. The ZipOutputStream offers a different metaphor for creating a - zip file, based on the class. - - - - The name of the zip file to create. - - - - - This example shows how to create a zip file, using the - ZipOutputStream class. - - - private void Zipup() - { - if (filesToZip.Count == 0) - { - System.Console.WriteLine("Nothing to do."); - return; - } - - using (var output= new ZipOutputStream(outputFileName)) - { - output.Password = "VerySecret!"; - output.Encryption = EncryptionAlgorithm.WinZipAes256; - - foreach (string inputFileName in filesToZip) - { - System.Console.WriteLine("file: {0}", inputFileName); - - output.PutNextEntry(inputFileName); - using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, - FileShare.Read | FileShare.Write )) - { - byte[] buffer= new byte[2048]; - int n; - while ((n= input.Read(buffer,0,buffer.Length)) > 0) - { - output.Write(buffer,0,n); - } - } - } - } - } - - - - Private Sub Zipup() - Dim outputFileName As String = "XmlData.zip" - Dim filesToZip As String() = Directory.GetFiles(".", "*.xml") - If (filesToZip.Length = 0) Then - Console.WriteLine("Nothing to do.") - Else - Using output As ZipOutputStream = New ZipOutputStream(outputFileName) - output.Password = "VerySecret!" - output.Encryption = EncryptionAlgorithm.WinZipAes256 - Dim inputFileName As String - For Each inputFileName In filesToZip - Console.WriteLine("file: {0}", inputFileName) - output.PutNextEntry(inputFileName) - Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - Dim n As Integer - Dim buffer As Byte() = New Byte(2048) {} - Do While (n = input.Read(buffer, 0, buffer.Length) > 0) - output.Write(buffer, 0, n) - Loop - End Using - Next - End Using - End If - End Sub - - - - - - Create a ZipOutputStream. - - - - See the documentation for the ZipOutputStream(Stream) - constructor for an example. - - - - The stream to wrap. It must be writable. - - - - true if the application would like the stream - to remain open after the ZipOutputStream has been closed. - - - - Provides a string representation of the instance. - - - This can be useful for debugging purposes. - - - a string representation of the instance. - - - - Sets the password to be used on the ZipOutputStream instance. - - - - - - When writing a zip archive, this password is applied to the entries, not - to the zip archive itself. It applies to any ZipEntry subsequently - written to the ZipOutputStream. - - - - Using a password does not encrypt or protect the "directory" of the - archive - the list of entries contained in the archive. If you set the - Password property, the password actually applies to individual - entries that are added to the archive, subsequent to the setting of this - property. The list of filenames in the archive that is eventually created - will appear in clear text, but the contents of the individual files are - encrypted. This is how Zip encryption works. - - - - If you set this property, and then add a set of entries to the archive via - calls to PutNextEntry, then each entry is encrypted with that - password. You may also want to change the password between adding - different entries. If you set the password, add an entry, then set the - password to null (Nothing in VB), and add another entry, the - first entry is encrypted and the second is not. - - - - When setting the Password, you may also want to explicitly set the property, to specify how to encrypt the entries added - to the ZipFile. If you set the Password to a non-null value and do not - set , then PKZip 2.0 ("Weak") encryption is used. - This encryption is relatively weak but is very interoperable. If - you set the password to a null value (Nothing in VB), - Encryption is reset to None. - - - - Special case: if you wrap a ZipOutputStream around a non-seekable stream, - and use encryption, and emit an entry of zero bytes, the Close() or - PutNextEntry() following the entry will throw an exception. - - - - - - - The Encryption to use for entries added to the ZipOutputStream. - - - - - The specified Encryption is applied to the entries subsequently - written to the ZipOutputStream instance. - - - - If you set this to something other than - EncryptionAlgorithm.None, you will also need to set the - to a non-null, non-empty value in - order to actually get encryption on the entry. - - - - - ZipOutputStream.Password - ZipEntry.Encryption - - - - Size of the work buffer to use for the ZLIB codec during compression. - - - - Setting this may affect performance. For larger files, setting this to a - larger size may improve performance, but I'm not sure. Sorry, I don't - currently have good recommendations on how to set it. You can test it if - you like. - - - - - The compression strategy to use for all entries. - - - - Set the Strategy used by the ZLIB-compatible compressor, when compressing - data for the entries in the zip archive. Different compression strategies - work better on different sorts of data. The strategy parameter can affect - the compression ratio and the speed of compression but not the correctness - of the compresssion. For more information see . - - - - - The type of timestamp attached to the ZipEntry. - - - - Set this in order to specify the kind of timestamp that should be emitted - into the zip file for each entry. - - - - - Sets the compression level to be used for entries subsequently added to - the zip archive. - - - - - Varying the compression level used on entries can affect the - size-vs-speed tradeoff when compression and decompressing data streams - or files. - - - - As with some other properties on the ZipOutputStream class, like , and , - setting this property on a ZipOutputStream - instance will cause the specified CompressionLevel to be used on all - items that are subsequently added to the - ZipOutputStream instance. - - - - If you do not set this property, the default compression level is used, - which normally gives a good balance of compression efficiency and - compression speed. In some tests, using BestCompression can - double the time it takes to compress, while delivering just a small - increase in compression efficiency. This behavior will vary with the - type of data you compress. If you are in doubt, just leave this setting - alone, and accept the default. - - - - - - The compression method used on each entry added to the ZipOutputStream. - - - - - A comment attached to the zip archive. - - - - - - The application sets this property to specify a comment to be embedded - into the generated zip archive. - - - - According to PKWARE's - zip specification, the comment is not encrypted, even if there is a - password set on the zip file. - - - - The specification does not describe how to indicate the encoding used - on a comment string. Many "compliant" zip tools and libraries use - IBM437 as the code page for comments; DotNetZip, too, follows that - practice. On the other hand, there are situations where you want a - Comment to be encoded with something else, for example using code page - 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the - comment following the same procedure it follows for encoding - filenames: (a) if is - Never, it uses the default encoding (IBM437). (b) if is Always, it always uses the - alternate encoding (). (c) if is AsNecessary, it uses the - alternate encoding only if the default encoding is not sufficient for - encoding the comment - in other words if decoding the result does not - produce the original string. This decision is taken at the time of - the call to ZipFile.Save(). - - - - - - - Specify whether to use ZIP64 extensions when saving a zip archive. - - - - - The default value for the property is . is - safest, in the sense that you will not get an Exception if a - pre-ZIP64 limit is exceeded. - - - - You must set this property before calling Write(). - - - - - - - Indicates whether ZIP64 extensions were used when saving the zip archive. - - - - The value is defined only after the ZipOutputStream has been closed. - - - - - Whether the ZipOutputStream should use case-insensitive comparisons when - checking for uniqueness of zip entries. - - - - - Though the zip specification doesn't prohibit zipfiles with duplicate - entries, Sane zip files have no duplicates, and the DotNetZip library - cannot create zip files with duplicate entries. If an application attempts - to call with a name that duplicates one - already used within the archive, the library will throw an Exception. - - - This property allows the application to specify whether the - ZipOutputStream instance considers ordinal case when checking for - uniqueness of zip entries. - - - - - - Indicates whether to encode entry filenames and entry comments using - Unicode (UTF-8). - - - - - The - PKWare zip specification provides for encoding file names and file - comments in either the IBM437 code page, or in UTF-8. This flag selects - the encoding according to that specification. By default, this flag is - false, and filenames and comments are encoded into the zip file in the - IBM437 codepage. Setting this flag to true will specify that filenames - and comments that cannot be encoded with IBM437 will be encoded with - UTF-8. - - - - Zip files created with strict adherence to the PKWare specification with - respect to UTF-8 encoding can contain entries with filenames containing - any combination of Unicode characters, including the full range of - characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other - alphabets. However, because at this time, the UTF-8 portion of the PKWare - specification is not broadly supported by other zip libraries and - utilities, such zip files may not be readable by your favorite zip tool or - archiver. In other words, interoperability will decrease if you set this - flag to true. - - - - In particular, Zip files created with strict adherence to the PKWare - specification with respect to UTF-8 encoding will not work well with - Explorer in Windows XP or Windows Vista, because Windows compressed - folders, as far as I know, do not support UTF-8 in zip files. Vista can - read the zip files, but shows the filenames incorrectly. Unpacking from - Windows Vista Explorer will result in filenames that have rubbish - characters in place of the high-order UTF-8 bytes. - - - - Also, zip files that use UTF-8 encoding will not work well with Java - applications that use the java.util.zip classes, as of v5.0 of the Java - runtime. The Java runtime does not correctly implement the PKWare - specification in this regard. - - - - As a result, we have the unfortunate situation that "correct" behavior by - the DotNetZip library with regard to Unicode encoding of filenames during - zip creation will result in zip files that are readable by strictly - compliant and current tools (for example the most recent release of the - commercial WinZip tool); but these zip files will not be readable by - various other tools or libraries, including Windows Explorer. - - - - The DotNetZip library can read and write zip files with UTF8-encoded - entries, according to the PKware spec. If you use DotNetZip for both - creating and reading the zip file, and you use UTF-8, there will be no - loss of information in the filenames. For example, using a self-extractor - created by this library will allow you to unpack files correctly with no - loss of information in the filenames. - - - - If you do not set this flag, it will remain false. If this flag is false, - the ZipOutputStream will encode all filenames and comments using - the IBM437 codepage. This can cause "loss of information" on some - filenames, but the resulting zipfile will be more interoperable with other - utilities. As an example of the loss of information, diacritics can be - lost. The o-tilde character will be down-coded to plain o. The c with a - cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c. - Likewise, the O-stroke character (Unicode 248), used in Danish and - Norwegian, will be down-coded to plain o. Chinese characters cannot be - represented in codepage IBM437; when using the default encoding, Chinese - characters in filenames will be represented as ?. These are all examples - of "information loss". - - - - The loss of information associated to the use of the IBM437 encoding is - inconvenient, and can also lead to runtime errors. For example, using - IBM437, any sequence of 4 Chinese characters will be encoded as ????. If - your application creates a ZipOutputStream, does not set the - encoding, then adds two files, each with names of four Chinese characters - each, this will result in a duplicate filename exception. In the case - where you add a single file with a name containing four Chinese - characters, the zipfile will save properly, but extracting that file - later, with any zip tool, will result in an error, because the question - mark is not legal for use within filenames on Windows. These are just a - few examples of the problems associated to loss of information. - - - - This flag is independent of the encoding of the content within the entries - in the zip file. Think of the zip file as a container - it supports an - encoding. Within the container are other "containers" - the file entries - themselves. The encoding within those entries is independent of the - encoding of the zip archive container for those entries. - - - - Rather than specify the encoding in a binary fashion using this flag, an - application can specify an arbitrary encoding via the property. Setting the encoding - explicitly when creating zip archives will result in non-compliant zip - files that, curiously, are fairly interoperable. The challenge is, the - PKWare specification does not provide for a way to specify that an entry - in a zip archive uses a code page that is neither IBM437 nor UTF-8. - Therefore if you set the encoding explicitly when creating a zip archive, - you must take care upon reading the zip archive to use the same code page. - If you get it wrong, the behavior is undefined and may result in incorrect - filenames, exceptions, stomach upset, hair loss, and acne. - - - - - - - The text encoding to use when emitting entries into the zip archive, for - those entries whose filenames or comments cannot be encoded with the - default (IBM437) encoding. - - - - - In its - zip specification, PKWare describes two options for encoding - filenames and comments: using IBM437 or UTF-8. But, some archiving tools - or libraries do not follow the specification, and instead encode - characters using the system default code page. For example, WinRAR when - run on a machine in Shanghai may encode filenames with the Big-5 Chinese - (950) code page. This behavior is contrary to the Zip specification, but - it occurs anyway. - - - - When using DotNetZip to write zip archives that will be read by one of - these other archivers, set this property to specify the code page to use - when encoding the and for each ZipEntry in the zip file, for - values that cannot be encoded with the default codepage for zip files, - IBM437. This is why this property is "provisional". In all cases, IBM437 - is used where possible, in other words, where no loss of data would - result. It is possible, therefore, to have a given entry with a - Comment encoded in IBM437 and a FileName encoded with the - specified "provisional" codepage. - - - - Be aware that a zip file created after you've explicitly set the - ProvisionalAlternateEncoding property to a value other than - IBM437 may not be compliant to the PKWare specification, and may not be - readable by compliant archivers. On the other hand, many (most?) - archivers are non-compliant and can read zip files created in arbitrary - code pages. The trick is to use or specify the proper codepage when - reading the zip. - - - - When creating a zip archive using this library, it is possible to change - the value of ProvisionalAlternateEncoding between each entry you - add, and between adding entries and the call to Close(). Don't do - this. It will likely result in a zipfile that is not readable. For best - interoperability, either leave ProvisionalAlternateEncoding - alone, or specify it only once, before adding any entries to the - ZipOutputStream instance. There is one exception to this - recommendation, described later. - - - - When using an arbitrary, non-UTF8 code page for encoding, there is no - standard way for the creator application - whether DotNetZip, WinZip, - WinRar, or something else - to formally specify in the zip file which - codepage has been used for the entries. As a result, readers of zip files - are not able to inspect the zip file and determine the codepage that was - used for the entries contained within it. It is left to the application - or user to determine the necessary codepage when reading zip files encoded - this way. If you use an incorrect codepage when reading a zipfile, you - will get entries with filenames that are incorrect, and the incorrect - filenames may even contain characters that are not legal for use within - filenames in Windows. Extracting entries with illegal characters in the - filenames will lead to exceptions. It's too bad, but this is just the way - things are with code pages in zip files. Caveat Emptor. - - - - One possible approach for specifying the code page for a given zip file is - to describe the code page in a human-readable form in the Zip comment. For - example, the comment may read "Entries in this archive are encoded in the - Big5 code page". For maximum interoperability, the zip comment in this - case should be encoded in the default, IBM437 code page. In this case, - the zip comment is encoded using a different page than the filenames. To - do this, Specify ProvisionalAlternateEncoding to your desired - region-specific code page, once before adding any entries, and then set - the property and reset - ProvisionalAlternateEncoding to IBM437 before calling Close(). - - - - - - A Text Encoding to use when encoding the filenames and comments for - all the ZipEntry items, during a ZipFile.Save() operation. - - - - Whether the encoding specified here is used during the save depends - on . - - - - - - A flag that tells if and when this instance should apply - AlternateEncoding to encode the filenames and comments associated to - of ZipEntry objects contained within this instance. - - - - - The default text encoding used in zip archives. It is numeric 437, also - known as IBM437. - - - - - - The size threshold for an entry, above which a parallel deflate is used. - - - - - - DotNetZip will use multiple threads to compress any ZipEntry, when - the CompressionMethod is Deflate, and if the entry is - larger than the given size. Zero means "always use parallel - deflate", while -1 means "never use parallel deflate". - - - - If the entry size cannot be known before compression, as with any entry - added via a ZipOutputStream, then Parallel deflate will never be - performed, unless the value of this property is zero. - - - - A parallel deflate operations will speed up the compression of - large files, on computers with multiple CPUs or multiple CPU - cores. For files above 1mb, on a dual core or dual-cpu (2p) - machine, the time required to compress the file can be 70% of the - single-threaded deflate. For very large files on 4p machines the - compression can be done in 30% of the normal time. The downside - is that parallel deflate consumes extra memory during the deflate, - and the deflation is slightly less effective. - - - - Parallel deflate tends to not be as effective as single-threaded deflate - because the original data stream is split into multiple independent - buffers, each of which is compressed in parallel. But because they are - treated independently, there is no opportunity to share compression - dictionaries, and additional framing bytes must be added to the output - stream. For that reason, a deflated stream may be slightly larger when - compressed using parallel deflate, as compared to a traditional - single-threaded deflate. For files of about 512k, the increase over the - normal deflate is as much as 5% of the total compressed size. For larger - files, the difference can be as small as 0.1%. - - - - Multi-threaded compression does not give as much an advantage when using - Encryption. This is primarily because encryption tends to slow down - the entire pipeline. Also, multi-threaded compression gives less of an - advantage when using lower compression levels, for example . You may have to perform - some tests to determine the best approach for your situation. - - - - The default value for this property is -1, which means parallel - compression will not be performed unless you set it to zero. - - - - - - - The maximum number of buffer pairs to use when performing - parallel compression. - - - - - This property sets an upper limit on the number of memory - buffer pairs to create when performing parallel - compression. The implementation of the parallel - compression stream allocates multiple buffers to - facilitate parallel compression. As each buffer fills up, - the stream uses - ThreadPool.QueueUserWorkItem() to compress those - buffers in a background threadpool thread. After a buffer - is compressed, it is re-ordered and written to the output - stream. - - - - A higher number of buffer pairs enables a higher degree of - parallelism, which tends to increase the speed of compression on - multi-cpu computers. On the other hand, a higher number of buffer - pairs also implies a larger memory consumption, more active worker - threads, and a higher cpu utilization for any compression. This - property enables the application to limit its memory consumption and - CPU utilization behavior depending on requirements. - - - - For each compression "task" that occurs in parallel, there are 2 - buffers allocated: one for input and one for output. This property - sets a limit for the number of pairs. The total amount of storage - space allocated for buffering will then be (N*S*2), where N is the - number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer - pairs per CPU core, so if your machine has 4 cores, and you retain - the default buffer size of 128k, then the - ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer - memory in total, or 4mb, in blocks of 128kb. If you then set this - property to 8, then the number will be 8 * 2 * 128kb of buffer - memory, or 2mb. - - - - CPU utilization will also go up with additional buffers, because a - larger number of buffer pairs allows a larger number of background - threads to compress in parallel. If you find that parallel - compression is consuming too much memory or CPU, you can adjust this - value downward. - - - - The default value is 16. Different values may deliver better or - worse results, depending on your priorities and the dynamic - performance characteristics of your storage and compute resources. - - - - This property is not the number of buffer pairs to use; it is an - upper limit. An illustration: Suppose you have an application that - uses the default value of this property (which is 16), and it runs - on a machine with 2 CPU cores. In that case, DotNetZip will allocate - 4 buffer pairs per CPU core, for a total of 8 pairs. The upper - limit specified by this property has no effect. - - - - The application can set this value at any time, but it is - effective only if set before calling - ZipOutputStream.Write() for the first time. - - - - - - - - - Returns true if an entry by the given name has already been written - to the ZipOutputStream. - - - - The name of the entry to scan for. - - - - true if an entry by the given name has already been written. - - - - - Write the data from the buffer to the stream. - - - - As the application writes data into this stream, the data may be - compressed and encrypted before being written out to the underlying - stream, depending on the settings of the - and the properties. - - - The buffer holding data to write to the stream. - the offset within that data array to find the first byte to write. - the number of bytes to write. - - - - Specify the name of the next entry that will be written to the zip file. - - - - - Call this method just before calling , to - specify the name of the entry that the next set of bytes written to - the ZipOutputStream belongs to. All subsequent calls to Write, - until the next call to PutNextEntry, - will be inserted into the named entry in the zip file. - - - - If the used in PutNextEntry() ends in - a slash, then the entry added is marked as a directory. Because directory - entries do not contain data, a call to Write(), before an - intervening additional call to PutNextEntry(), will throw an - exception. - - - - If you don't call Write() between two calls to - PutNextEntry(), the first entry is inserted into the zip file as a - file of zero size. This may be what you want. - - - - Because PutNextEntry() closes out the prior entry, if any, this - method may throw if there is a problem with the prior entry. - - - - This method returns the ZipEntry. You can modify public properties - on the ZipEntry, such as , , and so on, until the first call to - ZipOutputStream.Write(), or until the next call to - PutNextEntry(). If you modify the ZipEntry after - having called Write(), you may get a runtime exception, or you may - silently get an invalid zip archive. - - - - - - - This example shows how to create a zip file, using the - ZipOutputStream class. - - - private void Zipup() - { - using (FileStream fs raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite )) - { - using (var output= new ZipOutputStream(fs)) - { - output.Password = "VerySecret!"; - output.Encryption = EncryptionAlgorithm.WinZipAes256; - output.PutNextEntry("entry1.txt"); - byte[] buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #1."); - output.Write(buffer,0,buffer.Length); - output.PutNextEntry("entry2.txt"); // this will be zero length - output.PutNextEntry("entry3.txt"); - buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #3."); - output.Write(buffer,0,buffer.Length); - } - } - } - - - - - The name of the entry to be added, including any path to be used - within the zip file. - - - - The ZipEntry created. - - - - - - Dispose the stream - - - - - This method writes the Zip Central directory, then closes the stream. The - application must call Dispose() (or Close) in order to produce a valid zip file. - - - - Typically the application will call Dispose() implicitly, via a using - statement in C#, or a Using statement in VB. - - - - - set this to true, always. - - - - Always returns false. - - - - - Always returns false. - - - - - Always returns true. - - - - - Always returns a NotSupportedException. - - - - - Setting this property always returns a NotSupportedException. Getting it - returns the value of the Position on the underlying stream. - - - - - This is a no-op. - - - - - This method always throws a NotSupportedException. - - ignored - ignored - ignored - nothing - - - - This method always throws a NotSupportedException. - - ignored - ignored - nothing - - - - This method always throws a NotSupportedException. - - ignored - - - - Sort-of like a factory method, ForUpdate is used only when - the application needs to update the zip entry metadata for - a segmented zip file, when the starting segment is earlier - than the ending segment, for a particular entry. - - - - The update is always contiguous, never rolls over. As a - result, this method doesn't need to return a ZSS; it can - simply return a FileStream. That's why it's "sort of" - like a Factory method. - - - Caller must Close/Dispose the stream object returned by - this method. - - - - - - Name of the filesystem file corresponding to the current segment. - - - - The name is not always the name currently being used in the - filesystem. When rwMode is RwMode.Write, the filesystem file has a - temporary name until the stream is closed or until the next segment is - started. - - - - - - Read from the stream - - the buffer to read - the offset at which to start - the number of bytes to read - the number of bytes actually read - - - - Write to the stream. - - the buffer from which to write - the offset at which to start writing - the number of bytes to write - - - - Enumerates the options for a logical conjunction. This enum is intended for use - internally by the FileSelector class. - - - - - FileSelector encapsulates logic that selects files from a source - a zip file - or the filesystem - based on a set of criteria. This class is used internally - by the DotNetZip library, in particular for the AddSelectedFiles() methods. - This class can also be used independently of the zip capability in DotNetZip. - - - - - - The FileSelector class is used internally by the ZipFile class for selecting - files for inclusion into the ZipFile, when the method, or one of - its overloads, is called. It's also used for the methods. Typically, an - application that creates or manipulates Zip archives will not directly - interact with the FileSelector class. - - - - Some applications may wish to use the FileSelector class directly, to - select files from disk volumes based on a set of criteria, without creating or - querying Zip archives. The file selection criteria include: a pattern to - match the filename; the last modified, created, or last accessed time of the - file; the size of the file; and the attributes of the file. - - - - Consult the documentation for - for more information on specifying the selection criteria. - - - - - - - Constructor that allows the caller to specify file selection criteria. - - - - - This constructor allows the caller to specify a set of criteria for - selection of files. - - - - See for a description of - the syntax of the selectionCriteria string. - - - - By default the FileSelector will traverse NTFS Reparse Points. To - change this, use FileSelector(String, bool). - - - - The criteria for file selection. - - - - Constructor that allows the caller to specify file selection criteria. - - - - - This constructor allows the caller to specify a set of criteria for - selection of files. - - - - See for a description of - the syntax of the selectionCriteria string. - - - - The criteria for file selection. - - whether to traverse NTFS reparse points (junctions). - - - - - The string specifying which files to include when retrieving. - - - - - Specify the criteria in statements of 3 elements: a noun, an operator, - and a value. Consider the string "name != *.doc" . The noun is - "name". The operator is "!=", implying "Not Equal". The value is - "*.doc". That criterion, in English, says "all files with a name that - does not end in the .doc extension." - - - - Supported nouns include "name" (or "filename") for the filename; - "atime", "mtime", and "ctime" for last access time, last modfied time, - and created time of the file, respectively; "attributes" (or "attrs") - for the file attributes; "size" (or "length") for the file length - (uncompressed); and "type" for the type of object, either a file or a - directory. The "attributes", "type", and "name" nouns all support = - and != as operators. The "size", "atime", "mtime", and "ctime" nouns - support = and !=, and >, >=, <, <= as well. The times are - taken to be expressed in local time. - - - - Specify values for the file attributes as a string with one or more of - the characters H,R,S,A,I,L in any order, implying file attributes of - Hidden, ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint - (symbolic link) respectively. - - - - To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as - the format. If you omit the HH:mm:ss portion, it is assumed to be - 00:00:00 (midnight). - - - - The value for a size criterion is expressed in integer quantities of - bytes, kilobytes (use k or kb after the number), megabytes (m or mb), - or gigabytes (g or gb). - - - - The value for a name is a pattern to match against the filename, - potentially including wildcards. The pattern follows CMD.exe glob - rules: * implies one or more of any character, while ? implies one - character. If the name pattern contains any slashes, it is matched to - the entire filename, including the path; otherwise, it is matched - against only the filename without the path. This means a pattern of - "*\*.*" matches all files one directory level deep, while a pattern of - "*.*" matches all files in all directories. - - - - To specify a name pattern that includes spaces, use single quotes - around the pattern. A pattern of "'* *.*'" will match all files that - have spaces in the filename. The full criteria string for that would - be "name = '* *.*'" . - - - - The value for a type criterion is either F (implying a file) or D - (implying a directory). - - - - Some examples: - - - - - criteria - Files retrieved - - - - name != *.xls - any file with an extension that is not .xls - - - - - name = *.mp3 - any file with a .mp3 extension. - - - - - *.mp3 - (same as above) any file with a .mp3 extension. - - - - - attributes = A - all files whose attributes include the Archive bit. - - - - - attributes != H - all files whose attributes do not include the Hidden bit. - - - - - mtime > 2009-01-01 - all files with a last modified time after January 1st, 2009. - - - - - ctime > 2009/01/01-03:00:00 - all files with a created time after 3am (local time), - on January 1st, 2009. - - - - - size > 2gb - all files whose uncompressed size is greater than 2gb. - - - - - type = D - all directories in the filesystem. - - - - - - You can combine criteria with the conjunctions AND, OR, and XOR. Using - a string like "name = *.txt AND size >= 100k" for the - selectionCriteria retrieves entries whose names end in .txt, and whose - uncompressed size is greater than or equal to 100 kilobytes. - - - - For more complex combinations of criteria, you can use parenthesis to - group clauses in the boolean logic. Absent parenthesis, the - precedence of the criterion atoms is determined by order of - appearance. Unlike the C# language, the AND conjunction does not take - precendence over the logical OR. This is important only in strings - that contain 3 or more criterion atoms. In other words, "name = *.txt - and size > 1000 or attributes = H" implies "((name = *.txt AND size - > 1000) OR attributes = H)" while "attributes = H OR name = *.txt - and size > 1000" evaluates to "((attributes = H OR name = *.txt) - AND size > 1000)". When in doubt, use parenthesis. - - - - Using time properties requires some extra care. If you want to - retrieve all entries that were last updated on 2009 February 14, - specify "mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this - to say: all files updated after 12:00am on February 14th, until - 12:00am on February 15th. You can use the same bracketing approach to - specify any time period - a year, a month, a week, and so on. - - - - The syntax allows one special case: if you provide a string with no - spaces, it is treated as a pattern to match for the filename. - Therefore a string like "*.xls" will be equivalent to specifying "name - = *.xls". This "shorthand" notation does not work with compound - criteria. - - - - There is no logic in this class that insures that the inclusion - criteria are internally consistent. For example, it's possible to - specify criteria that says the file must have a size of less than 100 - bytes, as well as a size that is greater than 1000 bytes. Obviously - no file will ever satisfy such criteria, but this class does not check - for or detect such inconsistencies. - - - - - - Thrown in the setter if the value has an invalid syntax. - - - - - Indicates whether searches will traverse NTFS reparse points, like Junctions. - - - - - Returns a string representation of the FileSelector object. - - The string representation of the boolean logic statement of the file - selection criteria for this instance. - - - - Returns the names of the files in the specified directory - that fit the selection criteria specified in the FileSelector. - - - - This is equivalent to calling - with recurseDirectories = false. - - - - The name of the directory over which to apply the FileSelector - criteria. - - - - A collection of strings containing fully-qualified pathnames of files - that match the criteria specified in the FileSelector instance. - - - - - Returns the names of the files in the specified directory that fit the - selection criteria specified in the FileSelector, optionally recursing - through subdirectories. - - - - This method applies the file selection criteria contained in the - FileSelector to the files contained in the given directory, and - returns the names of files that conform to the criteria. - - - - The name of the directory over which to apply the FileSelector - criteria. - - - - Whether to recurse through subdirectories when applying the file - selection criteria. - - - - A collection of strings containing fully-qualified pathnames of files - that match the criteria specified in the FileSelector instance. - - - - - Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria. - - - - - This method applies the criteria set in the FileSelector instance (as described in - the ) to the specified ZipFile. Using this - method, for example, you can retrieve all entries from the given ZipFile that - have filenames ending in .txt. - - - - Normally, applications would not call this method directly. This method is used - by the ZipFile class. - - - - Using the appropriate SelectionCriteria, you can retrieve entries based on size, - time, and attributes. See for a - description of the syntax of the SelectionCriteria string. - - - - - The ZipFile from which to retrieve entries. - - a collection of ZipEntry objects that conform to the criteria. - - - - Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria. - - - - - This method applies the criteria set in the FileSelector instance (as described in - the ) to the specified ZipFile. Using this - method, for example, you can retrieve all entries from the given ZipFile that - have filenames ending in .txt. - - - - Normally, applications would not call this method directly. This method is used - by the ZipFile class. - - - - This overload allows the selection of ZipEntry instances from the ZipFile to be restricted - to entries contained within a particular directory in the ZipFile. - - - - Using the appropriate SelectionCriteria, you can retrieve entries based on size, - time, and attributes. See for a - description of the syntax of the SelectionCriteria string. - - - - - The ZipFile from which to retrieve entries. - - - the directory in the archive from which to select entries. If null, then - all directories in the archive are used. - - - a collection of ZipEntry objects that conform to the criteria. - - - - Summary description for EnumUtil. - - - - - Returns the value of the DescriptionAttribute if the specified Enum - value has one. If not, returns the ToString() representation of the - Enum value. - - The Enum to get the description for - - - - - Converts the string representation of the name or numeric value of one - or more enumerated constants to an equivalent enumerated object. - Note: use the DescriptionAttribute on enum values to enable this. - - The System.Type of the enumeration. - - A string containing the name or value to convert. - - - - - - Converts the string representation of the name or numeric value of one - or more enumerated constants to an equivalent enumerated object. A - parameter specified whether the operation is case-sensitive. Note: - use the DescriptionAttribute on enum values to enable this. - - The System.Type of the enumeration. - - A string containing the name or value to convert. - - - Whether the operation is case-sensitive or not. - - -
-