Libgourou

Libgourou Commit Details

Date:2022-08-29 12:18:29 (1 year 25 days ago)
Author:Grégory Soutadé
Branch:master
Commit:e28dc39a68ae73a3bc4aec0dc74722c71d0f791c
Parents: 7b8c7acbadf5dbdbba534899ea0ab55db1102a64
Message:Make DRMProcessorClient API more consistent

Changes:
Minclude/drmprocessorclient.h (9 diffs)
Minclude/libgourou_common.h (1 diff)
Msrc/libgourou.cpp (6 diffs)
Mutils/drmprocessorclientimpl.cpp (6 diffs)
Mutils/drmprocessorclientimpl.h (2 diffs)

File differences

include/drmprocessorclient.h
4747
4848
4949
50
51
5250
53
51
5452
5553
5654
5755
5856
5957
60
61
6258
63
59
6460
6561
6662
......
6965
7066
7167
72
73
7468
75
69
7670
7771
7872
......
239233
240234
241235
242
236
243237
244238
245239
......
256250
257251
258252
259
253
260254
261255
262256
......
269263
270264
271265
272
266
273267
274268
275269
276
270
277271
278272
279273
280274
281275
282276
283
277
284278
285279
286280
......
296290
297291
298292
299
293
300294
301295
302296
......
313307
314308
315309
316
310
317311
318312
319313
......
326320
327321
328322
329
323
330324
331325
332326
......
336330
337331
338332
339
333
340334
341335
342336
* @param handler Digest handler
* @param data Data to digest
* @param length Length of data
*
* @return OK/KO
*/
virtual int digestUpdate(void* handler, unsigned char* data, unsigned int length) = 0;
virtual void digestUpdate(void* handler, unsigned char* data, unsigned int length) = 0;
/**
* @brief Finalize digest with remained buffered data and destroy handler
*
* @param handler Digest handler
* @param digestOut Digest result (buffer must be pre allocated with right size)
*
* @return OK/KO
*/
virtual int digestFinalize(void* handler, unsigned char* digestOut) = 0;
virtual void digestFinalize(void* handler, unsigned char* digestOut) = 0;
/**
* @brief Global digest function
* @param data Data to digest
* @param length Length of data
* @param digestOut Digest result (buffer must be pre allocated with right size)
*
* @return OK/KO
*/
virtual int digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut) = 0;
virtual void digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut) = 0;
};
class RandomInterface
* @param dataOut Encrypted data
* @param dataOutLength Length of encrypted data
*/
virtual void Encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
virtual void encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv, unsigned int ivLength,
const unsigned char* dataIn, unsigned int dataInLength,
*
* @return AES handler
*/
virtual void* EncryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
virtual void* encryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
* @param dataOut Encrypted data
* @param dataOutLength Length of encrypted data
*/
virtual void EncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
virtual void encryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
/**
* @brief Finalizeencryption (pad and encrypt last block if needed)
* @brief Finalize encryption (pad and encrypt last block if needed)
* Destroy handler at the end
*
* @param handler Crypto handler
* @param dataOut Last block of encrypted data
* @param dataOutLength Length of encrypted data
*/
virtual void EncryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
virtual void encryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
/**
* @brief Do decryption. If length of data is not multiple of block size, PKCS#5 padding is done
* @param dataOut Encrypted data
* @param dataOutLength Length of encrypted data
*/
virtual void Decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
virtual void decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv, unsigned int ivLength,
const unsigned char* dataIn, unsigned int dataInLength,
*
* @return AES handler
*/
virtual void* DecryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
virtual void* decryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
* @param dataOut Decrypted data
* @param dataOutLength Length of decrypted data
*/
virtual void DecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
virtual void decryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
/**
* @brief Finalize decryption (decrypt last block and remove padding if it is set).
* @param dataOut Last block decrypted data
* @param dataOutLength Length of decrypted data
*/
virtual void DecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
virtual void decryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
};
include/libgourou_common.h
117117
118118
119119
120
121
120122
121123
122124
CLIENT_INVALID_PKCS8,
CLIENT_FILE_ERROR,
CLIENT_OSSL_ERROR,
CLIENT_CRYPT_ERROR,
CLIENT_DIGEST_ERROR,
};
enum DRM_REMOVAL_ERROR {
src/libgourou.cpp
869869
870870
871871
872
872
873873
874874
875875
......
888888
889889
890890
891
891
892892
893893
894894
......
10091009
10101010
10111011
1012
1012
10131013
10141014
10151015
......
11091109
11101110
11111111
1112
1112
11131113
11141114
11151115
......
13131313
13141314
13151315
1316
1316
13171317
13181318
13191319
......
13461346
13471347
13481348
1349
1349
13501350
13511351
13521352
// Generate IV in front
client->randBytes(encrypted_data, 16);
client->Encrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
client->encrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
deviceKey, 16, encrypted_data, 16,
data, len,
encrypted_data+16, &outLen);
const unsigned char* deviceKey = device->getDeviceKey();
unsigned char* decrypted_data = new unsigned char[len-16];
client->Decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
client->decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
deviceKey, 16, data, 16,
data+16, len-16,
decrypted_data, &outLen);
unsigned char* clearRSAKey = new unsigned char[arrayEncryptedKey.size()];
client->Decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
client->decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
(const unsigned char*)key, (unsigned int)sizeof(key),
(const unsigned char*)iv, (unsigned int)sizeof(iv),
(const unsigned char*)arrayEncryptedKey.data(), arrayEncryptedKey.size(),
gourou::ByteArray inflateData(true);
unsigned int dataOutLength;
client->Decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
client->decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
decryptedKey+sizeof(decryptedKey)-16, 16, /* Key */
_data, 16, /* IV */
&_data[16], zipData.length()-16,
GOUROU_LOG(DEBUG, "Decrypt string " << dictIt->first << " " << dataLength);
client->Decrypt(CryptoInterface::ALGO_RC4, CryptoInterface::CHAIN_ECB,
client->decrypt(CryptoInterface::ALGO_RC4, CryptoInterface::CHAIN_ECB,
tmpKey, 16, /* Key */
NULL, 0, /* IV */
encryptedData, dataLength,
GOUROU_LOG(DEBUG, "Decrypt stream id " << object->objectId() << ", size " << stream->dataLength());
client->Decrypt(CryptoInterface::ALGO_RC4, CryptoInterface::CHAIN_ECB,
client->decrypt(CryptoInterface::ALGO_RC4, CryptoInterface::CHAIN_ECB,
tmpKey, 16, /* Key */
NULL, 0, /* IV */
encryptedData, dataLength,
utils/drmprocessorclientimpl.cpp
8282
8383
8484
85
85
8686
8787
8888
8989
9090
91
91
9292
93
93
94
9495
9596
96
97
9798
9899
99100
100
101
102
103
101104
102105
103
106
104107
105108
106
107
108
109
110
109
110
111111
112112
113113
......
506506
507507
508508
509
509
510510
511511
512512
513513
514514
515
516
517
515
516
517
518518
519519
520
520
521521
522522
523523
524524
525
526
525
526
527
528
529
527530
528531
529532
......
531534
532535
533536
534
537
535538
536539
537
540
538541
539542
540543
......
544547
545548
546549
550
547551
548
552
549553
550554
551555
552556
553557
554558
555
559
560
561
556562
563
564
565
566
567
568
569
557570
558571
559572
560
573
561574
562575
563576
564577
565
566
578
579
580
581
582
567583
568584
569585
......
571587
572588
573589
574
590
575591
576592
577
593
578594
579595
580596
......
584600
585601
586602
603
587604
588
605
589606
590607
591608
592609
593610
594611
595
612
613
614
596615
597616
617
618
619
620
621
622
598623
599624
600625
601
626
602627
603628
604
629
630
631
632
605633
606634
607
635
608636
609637
610
611
638
639
640
612641
613642
643
644
645
614646
615647
616
648
617649
618650
619651
620652
621653
622
623
624
654
655
656
625657
626658
627
659
628660
629661
630
662
663
664
665
631666
632667
633
668
634669
635
636
670
671
672
637673
638674
675
676
677
639678
640679
641680
if (EVP_DigestInit(md_ctx, md) != 1)
{
EVP_MD_CTX_free(md_ctx);
return 0;
EXCEPTION(gourou::CLIENT_DIGEST_ERROR, ERR_error_string(ERR_get_error(), NULL));
}
return md_ctx;
}
int DRMProcessorClientImpl::digestUpdate(void* handler, unsigned char* data, unsigned int length)
void DRMProcessorClientImpl::digestUpdate(void* handler, unsigned char* data, unsigned int length)
{
return (EVP_DigestUpdate((EVP_MD_CTX *)handler, data, length)) ? 0 : -1;
if (EVP_DigestUpdate((EVP_MD_CTX *)handler, data, length) != 1)
EXCEPTION(gourou::CLIENT_DIGEST_ERROR, ERR_error_string(ERR_get_error(), NULL));
}
int DRMProcessorClientImpl::digestFinalize(void* handler, unsigned char* digestOut)
void DRMProcessorClientImpl::digestFinalize(void* handler, unsigned char* digestOut)
{
int res = EVP_DigestFinal((EVP_MD_CTX *)handler, digestOut, NULL);
EVP_MD_CTX_free((EVP_MD_CTX *)handler);
return (res == 1) ? 0 : -1;
if (res <= 0)
EXCEPTION(gourou::CLIENT_DIGEST_ERROR, ERR_error_string(ERR_get_error(), NULL));
}
int DRMProcessorClientImpl::digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut)
void DRMProcessorClientImpl::digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut)
{
void* handler = createDigest(digestName);
if (!handler)
return -1;
if (digestUpdate(handler, data, length))
return -1;
return digestFinalize(handler, digestOut);
digestUpdate(handler, data, length);
digestFinalize(handler, digestOut);
}
/* Random interface */
}
/* Crypto interface */
void DRMProcessorClientImpl::Encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
void DRMProcessorClientImpl::encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv, unsigned int ivLength,
const unsigned char* dataIn, unsigned int dataInLength,
unsigned char* dataOut, unsigned int* dataOutLength)
{
void* handler = EncryptInit(algo, chaining, key, keyLength, iv, ivLength);
EncryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
EncryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
void* handler = encryptInit(algo, chaining, key, keyLength, iv, ivLength);
encryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
encryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
}
void* DRMProcessorClientImpl::EncryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
void* DRMProcessorClientImpl::encryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv, unsigned int ivLength)
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (algo == ALGO_AES)
int ret = 0;
switch (algo)
{
case ALGO_AES:
{
switch(keyLength)
{
switch(chaining)
{
case CHAIN_ECB:
EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, iv);
ret = EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, iv);
break;
case CHAIN_CBC:
EVP_EncryptInit(ctx, EVP_aes_128_cbc(), key, iv);
ret = EVP_EncryptInit(ctx, EVP_aes_128_cbc(), key, iv);
break;
default:
EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining);
EVP_CIPHER_CTX_free(ctx);
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
}
break;
}
else if (algo == ALGO_RC4)
case ALGO_RC4:
{
if (keyLength != 16)
{
EVP_CIPHER_CTX_free(ctx);
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
}
EVP_DecryptInit(ctx, EVP_rc4(), key, iv);
ret = EVP_DecryptInit(ctx, EVP_rc4(), key, iv);
break;
}
}
if (ret <= 0)
{
EVP_CIPHER_CTX_free(ctx);
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
}
return ctx;
}
void* DRMProcessorClientImpl::DecryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
void* DRMProcessorClientImpl::decryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv, unsigned int ivLength)
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (algo == ALGO_AES)
int ret = 0;
switch(algo)
{
case ALGO_AES:
{
switch(keyLength)
{
switch(chaining)
{
case CHAIN_ECB:
EVP_DecryptInit(ctx, EVP_aes_128_ecb(), key, iv);
ret = EVP_DecryptInit(ctx, EVP_aes_128_ecb(), key, iv);
break;
case CHAIN_CBC:
EVP_DecryptInit(ctx, EVP_aes_128_cbc(), key, iv);
ret = EVP_DecryptInit(ctx, EVP_aes_128_cbc(), key, iv);
break;
default:
EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining);
EVP_CIPHER_CTX_free(ctx);
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
}
break;
}
else if (algo == ALGO_RC4)
case ALGO_RC4:
{
if (keyLength != 16)
{
EVP_CIPHER_CTX_free(ctx);
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
}
EVP_DecryptInit(ctx, EVP_rc4(), key, iv);
ret = EVP_DecryptInit(ctx, EVP_rc4(), key, iv);
break;
}
}
if (ret <= 0)
{
EVP_CIPHER_CTX_free(ctx);
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
}
return ctx;
}
void DRMProcessorClientImpl::EncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
void DRMProcessorClientImpl::encryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
unsigned char* dataOut, unsigned int* dataOutLength)
{
EVP_EncryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
int ret = EVP_EncryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
if (ret <= 0)
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
}
void DRMProcessorClientImpl::EncryptFinalize(void* handler,
void DRMProcessorClientImpl::encryptFinalize(void* handler,
unsigned char* dataOut, unsigned int* dataOutLength)
{
int len;
EVP_EncryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
int len, ret;
ret = EVP_EncryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
*dataOutLength += len;
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler);
if (ret <= 0)
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
}
void DRMProcessorClientImpl::Decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
void DRMProcessorClientImpl::decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv, unsigned int ivLength,
const unsigned char* dataIn, unsigned int dataInLength,
unsigned char* dataOut, unsigned int* dataOutLength)
{
void* handler = DecryptInit(algo, chaining, key, keyLength, iv, ivLength);
DecryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
DecryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
void* handler = decryptInit(algo, chaining, key, keyLength, iv, ivLength);
decryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
decryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
}
void DRMProcessorClientImpl::DecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
void DRMProcessorClientImpl::decryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
unsigned char* dataOut, unsigned int* dataOutLength)
{
EVP_DecryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
int ret = EVP_DecryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
if (ret <= 0)
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
}
void DRMProcessorClientImpl::DecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength)
void DRMProcessorClientImpl::decryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength)
{
int len;
EVP_DecryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
int len, ret;
ret = EVP_DecryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
*dataOutLength += len;
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler);
if (ret <= 0)
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
}
void* DRMProcessorClientImpl::zipOpen(const std::string& path)
utils/drmprocessorclientimpl.h
4545
4646
4747
48
49
50
48
49
50
5151
5252
5353
......
8080
8181
8282
83
83
8484
8585
8686
8787
8888
89
89
9090
9191
9292
9393
94
94
9595
96
96
9797
98
98
9999
100100
101101
102102
103103
104
104
105105
106106
107107
108
108
109109
110
110
111111
112112
113113
/* Digest interface */
virtual void* createDigest(const std::string& digestName);
virtual int digestUpdate(void* handler, unsigned char* data, unsigned int length);
virtual int digestFinalize(void* handler,unsigned char* digestOut);
virtual int digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut);
virtual void digestUpdate(void* handler, unsigned char* data, unsigned int length);
virtual void digestFinalize(void* handler,unsigned char* digestOut);
virtual void digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut);
/* Random interface */
virtual void randBytes(unsigned char* bytesOut, unsigned int length);
unsigned char** certOut, unsigned int* certOutLength);
/* Crypto interface */
virtual void Encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
virtual void encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv, unsigned int ivLength,
const unsigned char* dataIn, unsigned int dataInLength,
unsigned char* dataOut, unsigned int* dataOutLength);
virtual void* EncryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
virtual void* encryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv=0, unsigned int ivLength=0);
virtual void EncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
virtual void encryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
unsigned char* dataOut, unsigned int* dataOutLength);
virtual void EncryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
virtual void encryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
virtual void Decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
virtual void decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv, unsigned int ivLength,
const unsigned char* dataIn, unsigned int dataInLength,
unsigned char* dataOut, unsigned int* dataOutLength);
virtual void* DecryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
virtual void* decryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
const unsigned char* key, unsigned int keyLength,
const unsigned char* iv=0, unsigned int ivLength=0);
virtual void DecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
virtual void decryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
unsigned char* dataOut, unsigned int* dataOutLength);
virtual void DecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
virtual void decryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
/* ZIP Interface */
virtual void* zipOpen(const std::string& path);

Archive Download the corresponding diff file