00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "multifile.h"
00016
00017 #include "config_express.h"
00018 #include "streamWriter.h"
00019 #include "streamReader.h"
00020 #include "datagram.h"
00021 #include "zStream.h"
00022 #include "encryptStream.h"
00023 #include "virtualFileSystem.h"
00024 #include "virtualFile.h"
00025
00026 #include <algorithm>
00027 #include <iterator>
00028 #include <time.h>
00029
00030
00031
00032 const char Multifile::_header[] = "pmf\0\n\r";
00033 const size_t Multifile::_header_size = 6;
00034
00035
00036
00037
00038 const int Multifile::_current_major_ver = 1;
00039
00040 const int Multifile::_current_minor_ver = 1;
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 const char Multifile::_encrypt_header[] = "crypty";
00051 const size_t Multifile::_encrypt_header_size = 6;
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 Multifile::
00106 Multifile() :
00107 _read_filew(_read_file),
00108 _read_write_filew(_read_write_file)
00109 {
00110 ConfigVariableInt multifile_encryption_iteration_count
00111 ("multifile-encryption-iteration-count", 0,
00112 PRC_DESC("This is a special value of encryption-iteration-count used to encrypt "
00113 "subfiles within a multifile. It has a default value of 0 (just one "
00114 "application), on the assumption that the files from a multifile must "
00115 "be loaded quickly, without paying the cost of an expensive hash on "
00116 "each subfile in order to decrypt it."));
00117
00118 _read = (IStreamWrapper *)NULL;
00119 _write = (ostream *)NULL;
00120 _offset = 0;
00121 _owns_stream = false;
00122 _next_index = 0;
00123 _last_index = 0;
00124 _last_data_byte = 0;
00125 _needs_repack = false;
00126 _timestamp = 0;
00127 _timestamp_dirty = false;
00128 _record_timestamp = true;
00129 _scale_factor = 1;
00130 _new_scale_factor = 1;
00131 _encryption_flag = false;
00132 _encryption_iteration_count = multifile_encryption_iteration_count;
00133 _file_major_ver = 0;
00134 _file_minor_ver = 0;
00135
00136 #ifdef HAVE_OPENSSL
00137
00138 EncryptStreamBuf tbuf;
00139 _encryption_algorithm = tbuf.get_algorithm();
00140 _encryption_key_length = tbuf.get_key_length();
00141 #endif
00142 }
00143
00144
00145
00146
00147
00148
00149 Multifile::
00150 ~Multifile() {
00151 close();
00152 }
00153
00154
00155
00156
00157
00158
00159 Multifile::
00160 Multifile(const Multifile ©) :
00161 _read_filew(_read_file),
00162 _read_write_filew(_read_write_file)
00163 {
00164 nassertv(false);
00165 }
00166
00167
00168
00169
00170
00171
00172 void Multifile::
00173 operator = (const Multifile ©) {
00174 nassertv(false);
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 bool Multifile::
00190 open_read(const Filename &multifile_name, const streampos &offset) {
00191 close();
00192 Filename fname = multifile_name;
00193 fname.set_binary();
00194
00195 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00196 PT(VirtualFile) vfile = vfs->get_file(fname);
00197 if (vfile == NULL) {
00198 return false;
00199 }
00200 istream *multifile_stream = vfile->open_read_file(false);
00201 if (multifile_stream == NULL) {
00202 return false;
00203 }
00204
00205 _timestamp = vfile->get_timestamp();
00206 _timestamp_dirty = true;
00207 _read = new IStreamWrapper(multifile_stream, true);
00208 _owns_stream = true;
00209 _multifile_name = multifile_name;
00210 _offset = offset;
00211 return read_index();
00212 }
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 bool Multifile::
00227 open_read(IStreamWrapper *multifile_stream, bool owns_pointer,
00228 const streampos &offset) {
00229 close();
00230 _timestamp = time(NULL);
00231 _timestamp_dirty = true;
00232 _read = multifile_stream;
00233 _owns_stream = owns_pointer;
00234 _offset = offset;
00235 return read_index();
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 bool Multifile::
00252 open_write(const Filename &multifile_name) {
00253 close();
00254 Filename fname = multifile_name;
00255 fname.set_binary();
00256 if (!fname.open_write(_write_file, true)) {
00257 return false;
00258 }
00259 _timestamp = time(NULL);
00260 _timestamp_dirty = true;
00261 _write = &_write_file;
00262 _multifile_name = multifile_name;
00263 return true;
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 bool Multifile::
00279 open_write(ostream *multifile_stream, bool owns_pointer) {
00280 close();
00281 _timestamp = time(NULL);
00282 _timestamp_dirty = true;
00283 _write = multifile_stream;
00284 _owns_stream = owns_pointer;
00285 _write->seekp(0, ios::beg);
00286 return true;
00287 }
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 bool Multifile::
00303 open_read_write(const Filename &multifile_name) {
00304 close();
00305 Filename fname = multifile_name;
00306 fname.set_binary();
00307 bool exists = fname.exists();
00308 if (!fname.open_read_write(_read_write_file)) {
00309 return false;
00310 }
00311 if (exists) {
00312 _timestamp = fname.get_timestamp();
00313 } else {
00314 _timestamp = time(NULL);
00315 }
00316 _timestamp_dirty = true;
00317 _read = &_read_write_filew;
00318 _write = &_read_write_file;
00319 _multifile_name = multifile_name;
00320
00321 if (exists) {
00322 return read_index();
00323 } else {
00324 return true;
00325 }
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 bool Multifile::
00342 open_read_write(iostream *multifile_stream, bool owns_pointer) {
00343 close();
00344 _timestamp = time(NULL);
00345 _timestamp_dirty = true;
00346
00347
00348
00349
00350
00351 _read = new StreamWrapper(multifile_stream, owns_pointer);
00352 _write = multifile_stream;
00353 _owns_stream = true;
00354 _write->seekp(0, ios::beg);
00355
00356
00357 multifile_stream->seekg(0, ios::end);
00358 if (multifile_stream->tellg() == (streampos)0) {
00359
00360 return true;
00361 }
00362
00363
00364
00365 return read_index();
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375 void Multifile::
00376 close() {
00377 if (_new_scale_factor != _scale_factor) {
00378
00379
00380 repack();
00381 } else {
00382 flush();
00383 }
00384
00385 if (_owns_stream) {
00386
00387
00388 if (_read != (IStreamWrapper *)NULL) {
00389 delete _read;
00390 } else if (_write != (ostream *)NULL) {
00391 delete _write;
00392 }
00393 }
00394
00395 _read = (IStreamWrapper *)NULL;
00396 _write = (ostream *)NULL;
00397 _offset = 0;
00398 _owns_stream = false;
00399 _next_index = 0;
00400 _last_index = 0;
00401 _needs_repack = false;
00402 _timestamp = 0;
00403 _timestamp_dirty = false;
00404 _scale_factor = 1;
00405 _new_scale_factor = 1;
00406 _encryption_flag = false;
00407 _file_major_ver = 0;
00408 _file_minor_ver = 0;
00409
00410 _read_file.close();
00411 _write_file.close();
00412 _read_write_file.close();
00413 _multifile_name = Filename();
00414
00415 clear_subfiles();
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 void Multifile::
00442 set_scale_factor(size_t scale_factor) {
00443 nassertv(is_write_valid());
00444 nassertv(scale_factor != (size_t)0);
00445
00446 if (_next_index == (streampos)0) {
00447
00448
00449 _scale_factor = scale_factor;
00450 } else {
00451
00452
00453 nassertv(is_read_valid());
00454 }
00455
00456
00457
00458 _new_scale_factor = scale_factor;
00459 }
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 string Multifile::
00480 add_subfile(const string &subfile_name, const Filename &filename,
00481 int compression_level) {
00482 nassertr(is_write_valid(), string());
00483
00484 Filename fname = filename;
00485 if (multifile_always_binary) {
00486 fname.set_binary();
00487 }
00488
00489 nassertr(fname.is_binary_or_text(), string());
00490
00491 if (!fname.exists()) {
00492 return string();
00493 }
00494 string name = standardize_subfile_name(subfile_name);
00495 if (!name.empty()) {
00496 Subfile *subfile = new Subfile;
00497 subfile->_name = name;
00498 subfile->_source_filename = fname;
00499 if (fname.is_text()) {
00500 subfile->_flags |= SF_text;
00501 }
00502
00503 add_new_subfile(subfile, compression_level);
00504 }
00505
00506 _timestamp = time(NULL);
00507 _timestamp_dirty = true;
00508
00509 return name;
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533 string Multifile::
00534 add_subfile(const string &subfile_name, istream *subfile_data,
00535 int compression_level) {
00536 nassertr(is_write_valid(), string());
00537
00538 string name = standardize_subfile_name(subfile_name);
00539 if (!name.empty()) {
00540 Subfile *subfile = new Subfile;
00541 subfile->_name = name;
00542 subfile->_source = subfile_data;
00543 add_new_subfile(subfile, compression_level);
00544 }
00545
00546 return name;
00547 }
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563 string Multifile::
00564 update_subfile(const string &subfile_name, const Filename &filename,
00565 int compression_level) {
00566 nassertr(is_write_valid(), string());
00567
00568 Filename fname = filename;
00569 if (multifile_always_binary) {
00570 fname.set_binary();
00571 }
00572
00573 nassertr(fname.is_binary_or_text(), string());
00574
00575 if (!fname.exists()) {
00576 return string();
00577 }
00578 string name = standardize_subfile_name(subfile_name);
00579 if (!name.empty()) {
00580 int index = find_subfile(name);
00581 if (index >= 0) {
00582
00583 if (compare_subfile(index, fname)) {
00584
00585 return name;
00586 }
00587 }
00588
00589
00590
00591 Subfile *subfile = new Subfile;
00592 subfile->_name = name;
00593 subfile->_source_filename = fname;
00594 if (fname.is_text()) {
00595 subfile->_flags |= SF_text;
00596 }
00597
00598 add_new_subfile(subfile, compression_level);
00599 }
00600
00601 _timestamp = time(NULL);
00602 _timestamp_dirty = true;
00603
00604 return name;
00605 }
00606
00607 #ifdef HAVE_OPENSSL
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641 bool Multifile::
00642 add_signature(const Filename &certificate, const Filename &chain,
00643 const Filename &pkey, const string &password) {
00644 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00645
00646 if (chain.empty() && pkey.empty()) {
00647
00648
00649
00650 return add_signature(certificate, password);
00651 }
00652
00653 CertChain cert_chain;
00654
00655
00656
00657 string certificate_data;
00658 if (!vfs->read_file(certificate, certificate_data, true)) {
00659 express_cat.info()
00660 << "Could not read " << certificate << ".\n";
00661 return false;
00662 }
00663
00664
00665 BIO *certificate_mbio = BIO_new_mem_buf((void *)certificate_data.data(), certificate_data.size());
00666 X509 *x509 = PEM_read_bio_X509(certificate_mbio, NULL, NULL, (void *)"");
00667 BIO_free(certificate_mbio);
00668 if (x509 == NULL) {
00669 express_cat.info()
00670 << "Could not read certificate in " << certificate << ".\n";
00671 return false;
00672 }
00673
00674
00675
00676 cert_chain.push_back(CertRecord(x509));
00677
00678
00679 if (!chain.empty()) {
00680 string chain_data;
00681 if (!vfs->read_file(chain, chain_data, true)) {
00682 express_cat.info()
00683 << "Could not read " << chain << ".\n";
00684 return false;
00685 }
00686
00687 BIO *chain_mbio = BIO_new_mem_buf((void *)chain_data.data(), chain_data.size());
00688 X509 *c = PEM_read_bio_X509(chain_mbio, NULL, NULL, (void *)"");
00689 while (c != NULL) {
00690 cert_chain.push_back(c);
00691 c = PEM_read_bio_X509(chain_mbio, NULL, NULL, (void *)"");
00692 }
00693 BIO_free(chain_mbio);
00694
00695 if (cert_chain.size() == 1) {
00696 express_cat.info()
00697 << "Could not read certificate chain in " << chain << ".\n";
00698 return false;
00699 }
00700 }
00701
00702
00703
00704 string pkey_data;
00705 if (!vfs->read_file(pkey, pkey_data, true)) {
00706 express_cat.info()
00707 << "Could not read " << pkey << ".\n";
00708 return false;
00709 }
00710
00711 BIO *pkey_mbio = BIO_new_mem_buf((void *)pkey_data.data(), pkey_data.size());
00712 EVP_PKEY *evp_pkey = PEM_read_bio_PrivateKey(pkey_mbio, NULL, NULL,
00713 (void *)password.c_str());
00714 BIO_free(pkey_mbio);
00715 if (evp_pkey == NULL) {
00716 express_cat.info()
00717 << "Could not read private key in " << pkey << ".\n";
00718 return false;
00719 }
00720
00721 bool result = add_signature(cert_chain, evp_pkey);
00722
00723 EVP_PKEY_free(evp_pkey);
00724
00725 return result;
00726 }
00727 #endif // HAVE_OPENSSL
00728
00729 #ifdef HAVE_OPENSSL
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749 bool Multifile::
00750 add_signature(const Filename &composite, const string &password) {
00751 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00752
00753
00754 string composite_data;
00755 if (!vfs->read_file(composite, composite_data, true)) {
00756 express_cat.info()
00757 << "Could not read " << composite << ".\n";
00758 return false;
00759 }
00760
00761
00762 BIO *pkey_mbio = BIO_new_mem_buf((void *)composite_data.data(), composite_data.size());
00763 EVP_PKEY *evp_pkey = PEM_read_bio_PrivateKey(pkey_mbio, NULL, NULL,
00764 (void *)password.c_str());
00765 BIO_free(pkey_mbio);
00766 if (evp_pkey == NULL) {
00767 express_cat.info()
00768 << "Could not read private key in " << composite << ".\n";
00769 return false;
00770 }
00771
00772
00773 CertChain cert_chain;
00774
00775 BIO *chain_mbio = BIO_new_mem_buf((void *)composite_data.data(), composite_data.size());
00776 X509 *c = PEM_read_bio_X509(chain_mbio, NULL, NULL, (void *)"");
00777 while (c != NULL) {
00778 cert_chain.push_back(c);
00779 c = PEM_read_bio_X509(chain_mbio, NULL, NULL, (void *)"");
00780 }
00781 BIO_free(chain_mbio);
00782
00783 if (cert_chain.empty()) {
00784 express_cat.info()
00785 << "Could not read certificates in " << composite << ".\n";
00786 return false;
00787 }
00788
00789
00790
00791 size_t i;
00792 bool found_match = false;
00793 for (i = 0; i < cert_chain.size(); ++i) {
00794 X509 *c = cert_chain[i]._cert;
00795 if (X509_check_private_key(c, evp_pkey)) {
00796 found_match = true;
00797 if (i != 0) {
00798
00799 cert_chain.insert(cert_chain.begin(), cert_chain[i]);
00800 cert_chain.erase(cert_chain.begin() + i + 1);
00801 }
00802 break;
00803 }
00804 }
00805
00806 if (!found_match) {
00807 express_cat.info()
00808 << "No certificates in " << composite << " match key.\n";
00809 return false;
00810 }
00811
00812 bool result = add_signature(cert_chain, evp_pkey);
00813
00814 EVP_PKEY_free(evp_pkey);
00815
00816 return result;
00817 }
00818 #endif // HAVE_OPENSSL
00819
00820 #ifdef HAVE_OPENSSL
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847 bool Multifile::
00848 add_signature(X509 *certificate, STACK_OF(X509) *chain, EVP_PKEY *pkey) {
00849
00850
00851 CertChain cert_chain;
00852 cert_chain.push_back(CertRecord(certificate));
00853 if (chain != NULL) {
00854 int num = sk_X509_num(chain);
00855 for (int i = 0; i < num; ++i) {
00856 cert_chain.push_back(CertRecord((X509 *)sk_X509_value(chain, i)));
00857 }
00858 }
00859
00860 return add_signature(cert_chain, pkey);
00861 }
00862 #endif // HAVE_OPENSSL
00863
00864 #ifdef HAVE_OPENSSL
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892 bool Multifile::
00893 add_signature(const Multifile::CertChain &cert_chain, EVP_PKEY *pkey) {
00894 if (_needs_repack) {
00895 if (!repack()) {
00896 return false;
00897 }
00898 } else {
00899 if (!flush()) {
00900 return false;
00901 }
00902 }
00903
00904 if (cert_chain.empty()) {
00905 express_cat.info()
00906 << "No certificate given.\n";
00907 return false;
00908 }
00909
00910 if (pkey == NULL) {
00911 express_cat.info()
00912 << "No private key given.\n";
00913 return false;
00914 }
00915
00916 if (!X509_check_private_key(cert_chain[0]._cert, pkey)) {
00917 express_cat.info()
00918 << "Private key does not match certificate.\n";
00919 return false;
00920 }
00921
00922
00923 stringstream der_stream;
00924 StreamWriter der_writer(der_stream);
00925 der_writer.add_uint32(cert_chain.size());
00926
00927 CertChain::const_iterator ci;
00928 for (ci = cert_chain.begin(); ci != cert_chain.end(); ++ci) {
00929 X509 *cert = (*ci)._cert;
00930
00931 int der_len = i2d_X509(cert, NULL);
00932 unsigned char *der_buf = new unsigned char[der_len];
00933 unsigned char *p = der_buf;
00934 i2d_X509(cert, &p);
00935 der_writer.append_data(der_buf, der_len);
00936 delete[] der_buf;
00937 }
00938
00939
00940 der_stream.seekg(0);
00941 Subfile *subfile = new Subfile;
00942 subfile->_pkey = pkey;
00943 subfile->_flags |= SF_signature;
00944 subfile->_source = &der_stream;
00945
00946
00947
00948
00949 nassertr(_new_subfiles.empty(), false);
00950 _new_subfiles.push_back(subfile);
00951 bool result = flush();
00952
00953 delete subfile;
00954
00955 return result;
00956 }
00957 #endif // HAVE_OPENSSL
00958
00959 #ifdef HAVE_OPENSSL
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976 int Multifile::
00977 get_num_signatures() const {
00978 ((Multifile *)this)->check_signatures();
00979 return _signatures.size();
00980 }
00981 #endif // HAVE_OPENSSL
00982
00983 #ifdef HAVE_OPENSSL
00984
00985
00986
00987
00988
00989
00990 const Multifile::CertChain &Multifile::
00991 get_signature(int n) const {
00992 ((Multifile *)this)->check_signatures();
00993 static CertChain error_chain;
00994 nassertr(n >= 0 && n < (int)_signatures.size(), error_chain);
00995 return _signatures[n];
00996 }
00997 #endif // HAVE_OPENSSL
00998
00999 #ifdef HAVE_OPENSSL
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011 string Multifile::
01012 get_signature_subject_name(int n) const {
01013 const CertChain &cert_chain = get_signature(n);
01014 nassertr(!cert_chain.empty(), string());
01015
01016 X509_NAME *xname = X509_get_subject_name(cert_chain[0]._cert);
01017 if (xname != NULL) {
01018
01019
01020
01021 BIO *mbio = BIO_new(BIO_s_mem());
01022 X509_NAME_print_ex(mbio, xname, 0, XN_FLAG_RFC2253);
01023
01024 char *pp;
01025 long pp_size = BIO_get_mem_data(mbio, &pp);
01026 string name(pp, pp_size);
01027 BIO_free(mbio);
01028 return name;
01029 }
01030
01031 return string();
01032 }
01033 #endif // HAVE_OPENSSL
01034
01035 #ifdef HAVE_OPENSSL
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047 string Multifile::
01048 get_signature_friendly_name(int n) const {
01049 const CertChain &cert_chain = get_signature(n);
01050 nassertr(!cert_chain.empty(), string());
01051
01052 static const int nid_choices[] = {
01053 NID_pkcs9_emailAddress,
01054 NID_subject_alt_name,
01055 NID_commonName,
01056 -1,
01057 };
01058
01059
01060 for (int ni = 0; nid_choices[ni] != -1; ++ni) {
01061 int nid = nid_choices[ni];
01062
01063
01064 X509_NAME *xname = X509_get_subject_name(cert_chain[0]._cert);
01065 if (xname != NULL) {
01066 int pos = X509_NAME_get_index_by_NID(xname, nid, -1);
01067 if (pos != -1) {
01068
01069
01070 X509_NAME_ENTRY *xentry = X509_NAME_get_entry(xname, pos);
01071 if (xentry != NULL) {
01072 ASN1_STRING *data = X509_NAME_ENTRY_get_data(xentry);
01073 if (data != NULL) {
01074
01075
01076
01077 BIO *mbio = BIO_new(BIO_s_mem());
01078 ASN1_STRING_print_ex(mbio, data, ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB);
01079
01080 char *pp;
01081 long pp_size = BIO_get_mem_data(mbio, &pp);
01082 string name(pp, pp_size);
01083 BIO_free(mbio);
01084 return name;
01085 }
01086 }
01087 }
01088 }
01089 }
01090
01091 return string();
01092 }
01093 #endif // HAVE_OPENSSL
01094
01095 #ifdef HAVE_OPENSSL
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108 string Multifile::
01109 get_signature_public_key(int n) const {
01110 const CertChain &cert_chain = get_signature(n);
01111 nassertr(!cert_chain.empty(), string());
01112
01113 EVP_PKEY *pkey = X509_get_pubkey(cert_chain[0]._cert);
01114 if (pkey != NULL) {
01115 int key_len = i2d_PublicKey(pkey, NULL);
01116 unsigned char *key_buf = new unsigned char[key_len];
01117 unsigned char *p = key_buf;
01118 i2d_PublicKey(pkey, &p);
01119 string result;
01120 for (int i = 0; i < key_len; ++i) {
01121 result += tohex(key_buf[i] >> 4);
01122 result += tohex(key_buf[i]);
01123 }
01124 delete[] key_buf;
01125 return result;
01126 }
01127
01128 return string();
01129 }
01130 #endif // HAVE_OPENSSL
01131
01132 #ifdef HAVE_OPENSSL
01133
01134
01135
01136
01137
01138
01139
01140 void Multifile::
01141 print_signature_certificate(int n, ostream &out) const {
01142 const CertChain &cert_chain = get_signature(n);
01143 nassertv(!cert_chain.empty());
01144
01145 BIO *mbio = BIO_new(BIO_s_mem());
01146 X509_print(mbio, cert_chain[0]._cert);
01147
01148 char *pp;
01149 long pp_size = BIO_get_mem_data(mbio, &pp);
01150 out.write(pp, pp_size);
01151 BIO_free(mbio);
01152 }
01153 #endif // HAVE_OPENSSL
01154
01155 #ifdef HAVE_OPENSSL
01156
01157
01158
01159
01160
01161
01162
01163 void Multifile::
01164 write_signature_certificate(int n, ostream &out) const {
01165 const CertChain &cert_chain = get_signature(n);
01166 nassertv(!cert_chain.empty());
01167
01168 BIO *mbio = BIO_new(BIO_s_mem());
01169
01170 CertChain::const_iterator ci;
01171 for (ci = cert_chain.begin(); ci != cert_chain.end(); ++ci) {
01172 X509 *c = (*ci)._cert;
01173 X509_print(mbio, c);
01174 PEM_write_bio_X509(mbio, c);
01175 }
01176
01177 char *pp;
01178 long pp_size = BIO_get_mem_data(mbio, &pp);
01179 out.write(pp, pp_size);
01180 BIO_free(mbio);
01181 }
01182 #endif // HAVE_OPENSSL
01183
01184 #ifdef HAVE_OPENSSL
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195 int Multifile::
01196 validate_signature_certificate(int n) const {
01197 int verify_result = -1;
01198
01199 const CertChain &chain = get_signature(n);
01200 nassertr(!chain.empty(), false);
01201
01202 OpenSSLWrapper *sslw = OpenSSLWrapper::get_global_ptr();
01203
01204
01205
01206 X509 *x509 = chain[0]._cert;
01207 STACK_OF(X509) *stack = NULL;
01208 if (chain.size() > 1) {
01209 stack = sk_X509_new(NULL);
01210 for (size_t n = 1; n < chain.size(); ++n) {
01211 sk_X509_push(stack, chain[n]._cert);
01212 }
01213 }
01214
01215
01216 X509_STORE_CTX *ctx = X509_STORE_CTX_new();
01217 X509_STORE_CTX_init(ctx, sslw->get_x509_store(), x509, stack);
01218 X509_STORE_CTX_set_cert(ctx, x509);
01219
01220 if (X509_verify_cert(ctx)) {
01221 verify_result = 0;
01222 } else {
01223 verify_result = X509_STORE_CTX_get_error(ctx);
01224 }
01225
01226 if (express_cat.is_debug()) {
01227 express_cat.debug()
01228 << get_signature_subject_name(n) << ": validate " << verify_result
01229 << "\n";
01230 }
01231
01232 sk_X509_free(stack);
01233 X509_STORE_CTX_cleanup(ctx);
01234 X509_STORE_CTX_free(ctx);
01235
01236 return verify_result;
01237 }
01238 #endif // HAVE_OPENSSL
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261 bool Multifile::
01262 flush() {
01263 if (!is_write_valid()) {
01264 return false;
01265 }
01266
01267 bool new_file = (_next_index == (streampos)0);
01268 if (new_file) {
01269
01270
01271 if (!write_header()) {
01272 return false;
01273 }
01274
01275 } else {
01276 if (_file_minor_ver != _current_minor_ver) {
01277
01278
01279 return repack();
01280 }
01281 }
01282
01283 nassertr(_write != (ostream *)NULL, false);
01284
01285
01286 PendingSubfiles::iterator pi;
01287 for (pi = _removed_subfiles.begin(); pi != _removed_subfiles.end(); ++pi) {
01288 Subfile *subfile = (*pi);
01289 subfile->rewrite_index_flags(*_write);
01290 delete subfile;
01291 }
01292 _removed_subfiles.clear();
01293
01294 bool wrote_ok = true;
01295
01296 if (!_new_subfiles.empty() || new_file) {
01297
01298
01299 sort(_new_subfiles.begin(), _new_subfiles.end(), IndirectLess<Subfile>());
01300 if (_last_index != (streampos)0) {
01301 _write->seekp(0, ios::end);
01302 if (_write->fail()) {
01303 express_cat.info()
01304 << "Unable to seek Multifile " << _multifile_name << ".\n";
01305 return false;
01306 }
01307 _next_index = _write->tellp();
01308 _next_index = pad_to_streampos(_next_index);
01309
01310
01311
01312 _write->seekp(_last_index);
01313 StreamWriter writer(_write, false);
01314 writer.add_uint32(streampos_to_word(_next_index));
01315 }
01316
01317 _write->seekp(_next_index);
01318 nassertr(_next_index == _write->tellp(), false);
01319
01320
01321
01322 for (pi = _new_subfiles.begin(); pi != _new_subfiles.end(); ++pi) {
01323 Subfile *subfile = (*pi);
01324 _last_index = _next_index;
01325 _next_index = subfile->write_index(*_write, _next_index, this);
01326 nassertr(_next_index == _write->tellp(), false);
01327 _next_index = pad_to_streampos(_next_index);
01328 nassertr(_next_index == _write->tellp(), false);
01329 }
01330
01331
01332
01333 StreamWriter writer(_write, false);
01334 writer.add_uint32(0);
01335 _next_index += 4;
01336 nassertr(_next_index == _write->tellp(), false);
01337 _next_index = pad_to_streampos(_next_index);
01338
01339
01340 for (pi = _new_subfiles.begin(); pi != _new_subfiles.end(); ++pi) {
01341 Subfile *subfile = (*pi);
01342
01343 if (_read != (IStreamWrapper *)NULL) {
01344 _read->acquire();
01345 _next_index = subfile->write_data(*_write, _read->get_istream(),
01346 _next_index, this);
01347 _read->release();
01348
01349 } else {
01350 _next_index = subfile->write_data(*_write, NULL, _next_index, this);
01351 }
01352
01353 nassertr(_next_index == _write->tellp(), false);
01354 _next_index = pad_to_streampos(_next_index);
01355 if (subfile->is_data_invalid()) {
01356 wrote_ok = false;
01357 }
01358
01359 if (!subfile->is_cert_special()) {
01360 _last_data_byte = max(_last_data_byte, subfile->get_last_byte_pos());
01361 }
01362 nassertr(_next_index == _write->tellp(), false);
01363 }
01364
01365
01366
01367
01368
01369 for (pi = _new_subfiles.begin(); pi != _new_subfiles.end(); ++pi) {
01370 Subfile *subfile = (*pi);
01371 subfile->rewrite_index_data_start(*_write, this);
01372 }
01373
01374 _new_subfiles.clear();
01375 }
01376
01377
01378 if (_timestamp_dirty) {
01379 nassertr(!_write->fail(), false);
01380 static const size_t timestamp_pos = _header_prefix.size() + _header_size + 2 + 2 + 4;
01381 _write->seekp(timestamp_pos);
01382 nassertr(!_write->fail(), false);
01383
01384 StreamWriter writer(*_write);
01385 if (_record_timestamp) {
01386 writer.add_uint32(_timestamp);
01387 } else {
01388 writer.add_uint32(0);
01389 }
01390 _timestamp_dirty = false;
01391 }
01392
01393 _write->flush();
01394 if (!wrote_ok || _write->fail()) {
01395 express_cat.info()
01396 << "Unable to update Multifile " << _multifile_name << ".\n";
01397 close();
01398 return false;
01399 }
01400
01401 return true;
01402 }
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422 bool Multifile::
01423 repack() {
01424 if (_next_index == (streampos)0) {
01425
01426
01427 _needs_repack = false;
01428 return flush();
01429 }
01430
01431 nassertr(is_write_valid() && is_read_valid(), false);
01432 nassertr(!_multifile_name.empty(), false);
01433
01434
01435 Filename dirname = _multifile_name.get_dirname();
01436 if (dirname.empty()) {
01437 dirname = ".";
01438 }
01439 Filename temp_filename = Filename::temporary(dirname, "mftemp");
01440 temp_filename.set_binary();
01441 pofstream temp;
01442 if (!temp_filename.open_write(temp)) {
01443 express_cat.info()
01444 << "Unable to open temporary file " << temp_filename << "\n";
01445 return false;
01446 }
01447
01448
01449
01450 PendingSubfiles::iterator pi;
01451 for (pi = _removed_subfiles.begin(); pi != _removed_subfiles.end(); ++pi) {
01452 Subfile *subfile = (*pi);
01453 delete subfile;
01454 }
01455 _removed_subfiles.clear();
01456 _new_subfiles.clear();
01457 copy(_subfiles.begin(), _subfiles.end(), back_inserter(_new_subfiles));
01458 _next_index = 0;
01459 _last_index = 0;
01460 _last_data_byte = 0;
01461 _scale_factor = _new_scale_factor;
01462
01463
01464 _write = &temp;
01465 if (!flush()) {
01466 temp.close();
01467 temp_filename.unlink();
01468 return false;
01469 }
01470
01471
01472
01473 Filename orig_name = _multifile_name;
01474 temp.close();
01475 close();
01476 orig_name.unlink();
01477 if (!temp_filename.rename_to(orig_name)) {
01478 express_cat.info()
01479 << "Unable to rename temporary file " << temp_filename << " to "
01480 << orig_name << ".\n";
01481 return false;
01482 }
01483
01484 if (!open_read_write(orig_name)) {
01485 express_cat.info()
01486 << "Unable to read newly repacked " << _multifile_name
01487 << ".\n";
01488 return false;
01489 }
01490
01491 return true;
01492 }
01493
01494
01495
01496
01497
01498
01499
01500
01501 int Multifile::
01502 get_num_subfiles() const {
01503 return _subfiles.size();
01504 }
01505
01506
01507
01508
01509
01510
01511
01512
01513 int Multifile::
01514 find_subfile(const string &subfile_name) const {
01515 Subfile find_subfile;
01516 find_subfile._name = standardize_subfile_name(subfile_name);
01517 Subfiles::const_iterator fi;
01518 fi = _subfiles.find(&find_subfile);
01519 if (fi == _subfiles.end()) {
01520
01521 return -1;
01522 }
01523 return (fi - _subfiles.begin());
01524 }
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534 bool Multifile::
01535 has_directory(const string &subfile_name) const {
01536 string prefix = subfile_name;
01537 if (!prefix.empty()) {
01538 prefix += '/';
01539 }
01540 Subfile find_subfile;
01541 find_subfile._name = prefix;
01542 Subfiles::const_iterator fi;
01543 fi = _subfiles.upper_bound(&find_subfile);
01544 if (fi == _subfiles.end()) {
01545
01546 return false;
01547 }
01548
01549
01550
01551 Subfile *subfile = (*fi);
01552 return (subfile->_name.length() > prefix.length() &&
01553 subfile->_name.substr(0, prefix.length()) == prefix);
01554 }
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571 bool Multifile::
01572 scan_directory(vector_string &contents, const string &subfile_name) const {
01573 string prefix = subfile_name;
01574 if (!prefix.empty()) {
01575 prefix += '/';
01576 }
01577 Subfile find_subfile;
01578 find_subfile._name = prefix;
01579 Subfiles::const_iterator fi;
01580 fi = _subfiles.upper_bound(&find_subfile);
01581
01582 string previous = "";
01583 while (fi != _subfiles.end()) {
01584 Subfile *subfile = (*fi);
01585 if (!(subfile->_name.length() > prefix.length() &&
01586 subfile->_name.substr(0, prefix.length()) == prefix)) {
01587
01588
01589 return true;
01590 }
01591
01592 size_t slash = subfile->_name.find('/', prefix.length());
01593 string basename = subfile->_name.substr(prefix.length(), slash - prefix.length());
01594 if (basename != previous) {
01595 contents.push_back(basename);
01596 previous = basename;
01597 }
01598 ++fi;
01599 }
01600
01601 return true;
01602 }
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618 void Multifile::
01619 remove_subfile(int index) {
01620 nassertv(is_write_valid());
01621 nassertv(index >= 0 && index < (int)_subfiles.size());
01622 Subfile *subfile = _subfiles[index];
01623 subfile->_flags |= SF_deleted;
01624 _removed_subfiles.push_back(subfile);
01625 _subfiles.erase(_subfiles.begin() + index);
01626
01627 _timestamp = time(NULL);
01628 _timestamp_dirty = true;
01629
01630 _needs_repack = true;
01631 }
01632
01633
01634
01635
01636
01637
01638 const string &Multifile::
01639 get_subfile_name(int index) const {
01640 #ifndef NDEBUG
01641 static string empty_string;
01642 nassertr(index >= 0 && index < (int)_subfiles.size(), empty_string);
01643 #endif
01644 return _subfiles[index]->_name;
01645 }
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655 size_t Multifile::
01656 get_subfile_length(int index) const {
01657 nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
01658 return _subfiles[index]->_uncompressed_length;
01659 }
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671 time_t Multifile::
01672 get_subfile_timestamp(int index) const {
01673 nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
01674 if (!get_record_timestamp()) {
01675 return get_timestamp();
01676 } else {
01677 return _subfiles[index]->_timestamp;
01678 }
01679 }
01680
01681
01682
01683
01684
01685
01686
01687
01688 bool Multifile::
01689 is_subfile_compressed(int index) const {
01690 nassertr(index >= 0 && index < (int)_subfiles.size(), false);
01691 return (_subfiles[index]->_flags & SF_compressed) != 0;
01692 }
01693
01694
01695
01696
01697
01698
01699
01700
01701 bool Multifile::
01702 is_subfile_encrypted(int index) const {
01703 nassertr(index >= 0 && index < (int)_subfiles.size(), false);
01704 return (_subfiles[index]->_flags & SF_encrypted) != 0;
01705 }
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718 bool Multifile::
01719 is_subfile_text(int index) const {
01720 nassertr(index >= 0 && index < (int)_subfiles.size(), false);
01721 return (_subfiles[index]->_flags & SF_text) != 0;
01722 }
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737 streampos Multifile::
01738 get_index_end() const {
01739 return normalize_streampos(_next_index + (streampos)4);
01740 }
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753 streampos Multifile::
01754 get_subfile_internal_start(int index) const {
01755 nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
01756 return _subfiles[index]->_data_start;
01757 }
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770 size_t Multifile::
01771 get_subfile_internal_length(int index) const {
01772 nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
01773 return _subfiles[index]->_data_length;
01774 }
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799 istream *Multifile::
01800 open_read_subfile(int index) {
01801 nassertr(is_read_valid(), NULL);
01802 nassertr(index >= 0 && index < (int)_subfiles.size(), NULL);
01803 Subfile *subfile = _subfiles[index];
01804
01805 if (subfile->_source != (istream *)NULL ||
01806 !subfile->_source_filename.empty()) {
01807
01808
01809 flush();
01810
01811
01812
01813 nassertr(subfile == _subfiles[index], NULL);
01814 }
01815
01816 return open_read_subfile(subfile);
01817 }
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828 void Multifile::
01829 close_read_subfile(istream *stream) {
01830 if (stream != (istream *)NULL) {
01831
01832
01833
01834
01835 #if !defined(WIN32_VC) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW)
01836 stream->~istream();
01837 (*global_operator_delete)(stream);
01838 #else
01839 delete stream;
01840 #endif
01841 }
01842 }
01843
01844
01845
01846
01847
01848
01849
01850 bool Multifile::
01851 extract_subfile(int index, const Filename &filename) {
01852 nassertr(is_read_valid(), false);
01853 nassertr(index >= 0 && index < (int)_subfiles.size(), false);
01854
01855 Filename fname = filename;
01856 if (multifile_always_binary) {
01857 fname.set_binary();
01858 }
01859
01860 if (!fname.is_binary_or_text()) {
01861
01862
01863 if ((_subfiles[index]->_flags & SF_text) != 0) {
01864 fname.set_text();
01865 } else {
01866 fname.set_binary();
01867 }
01868 }
01869 fname.make_dir();
01870 pofstream out;
01871 if (!fname.open_write(out, true)) {
01872 express_cat.info()
01873 << "Unable to write to file " << filename << "\n";
01874 return false;
01875 }
01876
01877 return extract_subfile_to(index, out);
01878 }
01879
01880
01881
01882
01883
01884
01885 bool Multifile::
01886 extract_subfile_to(int index, ostream &out) {
01887 nassertr(is_read_valid(), false);
01888 nassertr(index >= 0 && index < (int)_subfiles.size(), false);
01889
01890 istream *in = open_read_subfile(index);
01891 if (in == (istream *)NULL) {
01892 return false;
01893 }
01894
01895 static const size_t buffer_size = 4096;
01896 char buffer[buffer_size];
01897
01898 in->read(buffer, buffer_size);
01899 size_t count = in->gcount();
01900 while (count != 0) {
01901 out.write(buffer, count);
01902 in->read(buffer, buffer_size);
01903 count = in->gcount();
01904 }
01905
01906 bool failed = (in->fail() && !in->eof());
01907 close_read_subfile(in);
01908 nassertr(!failed, false);
01909
01910 return (!out.fail());
01911 }
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928 bool Multifile::
01929 compare_subfile(int index, const Filename &filename) {
01930 nassertr(is_read_valid(), false);
01931 nassertr(index >= 0 && index < (int)_subfiles.size(), false);
01932
01933 if (!filename.exists()) {
01934 express_cat.info()
01935 << "File is missing: " << filename << "\n";
01936 return false;
01937 }
01938
01939 Filename fname = filename;
01940 if (fname.is_binary()) {
01941
01942
01943 if ((_subfiles[index]->_flags & SF_text) != 0) {
01944 if (express_cat.is_debug()) {
01945 express_cat.debug()
01946 << "File is not binary: " << filename << "\n";
01947 }
01948 return false;
01949 }
01950
01951 } else if (fname.is_text()) {
01952
01953
01954 if ((_subfiles[index]->_flags & SF_text) == 0) {
01955 if (express_cat.is_debug()) {
01956 express_cat.debug()
01957 << "File is not text: " << filename << "\n";
01958 }
01959 return false;
01960 }
01961
01962 } else {
01963
01964
01965 if ((_subfiles[index]->_flags & SF_text) != 0) {
01966 fname.set_text();
01967 } else {
01968 fname.set_binary();
01969 }
01970 }
01971
01972 istream *in1 = open_read_subfile(index);
01973 if (in1 == (istream *)NULL) {
01974 return false;
01975 }
01976
01977 pifstream in2;
01978
01979 if (!fname.open_read(in2)) {
01980 express_cat.info()
01981 << "Cannot read " << filename << "\n";
01982 return false;
01983 }
01984
01985 if (fname.is_binary()) {
01986
01987 in2.seekg(0, ios::end);
01988 streampos file_size = in2.tellg();
01989
01990 if (file_size != (streampos)get_subfile_length(index)) {
01991
01992 close_read_subfile(in1);
01993 return false;
01994 }
01995 }
01996
01997
01998 in2.seekg(0);
01999 int byte1 = in1->get();
02000 int byte2 = in2.get();
02001 while (!in1->fail() && !in1->eof() &&
02002 !in2.fail() && !in2.eof()) {
02003 if (byte1 != byte2) {
02004 close_read_subfile(in1);
02005 return false;
02006 }
02007 byte1 = in1->get();
02008 byte2 = in2.get();
02009 }
02010
02011 bool failed = (in1->fail() && !in1->eof()) || (in2.fail() && !in2.eof());
02012 close_read_subfile(in1);
02013
02014 nassertr(!failed, false);
02015
02016 return true;
02017 }
02018
02019
02020
02021
02022
02023
02024 void Multifile::
02025 output(ostream &out) const {
02026 out << "Multifile " << _multifile_name << ", " << get_num_subfiles()
02027 << " subfiles.\n";
02028 }
02029
02030
02031
02032
02033
02034
02035 void Multifile::
02036 ls(ostream &out) const {
02037 int num_subfiles = get_num_subfiles();
02038 for (int i = 0; i < num_subfiles; i++) {
02039 string subfile_name = get_subfile_name(i);
02040 out << subfile_name << "\n";
02041 }
02042 }
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056
02057
02058
02059
02060
02061
02062
02063 void Multifile::
02064 set_header_prefix(const string &header_prefix) {
02065 string new_header_prefix = header_prefix;
02066
02067 if (!new_header_prefix.empty()) {
02068
02069 if (new_header_prefix[0] != '#') {
02070 new_header_prefix = string("#") + new_header_prefix;
02071 }
02072
02073
02074 if (new_header_prefix[new_header_prefix.size() - 1] != '\n') {
02075 new_header_prefix += string("\n");
02076 }
02077
02078
02079 size_t newline = new_header_prefix.find('\n');
02080 while (newline < new_header_prefix.size() - 1) {
02081 if (new_header_prefix[newline + 1] != '#') {
02082 new_header_prefix = new_header_prefix.substr(0, newline + 1) + string("#") + new_header_prefix.substr(newline + 1);
02083 }
02084 newline = new_header_prefix.find('#', newline);
02085 }
02086 }
02087
02088 if (_header_prefix != new_header_prefix) {
02089 _header_prefix = new_header_prefix;
02090 _needs_repack = true;
02091 }
02092 }
02093
02094
02095
02096
02097
02098
02099
02100
02101 bool Multifile::
02102 read_subfile(int index, string &result) {
02103 result = string();
02104
02105
02106
02107
02108 pvector<unsigned char> pv;
02109 if (!read_subfile(index, pv)) {
02110 return false;
02111 }
02112
02113 if (!pv.empty()) {
02114 result.append((const char *)&pv[0], pv.size());
02115 }
02116
02117 return true;
02118 }
02119
02120
02121
02122
02123
02124
02125
02126 bool Multifile::
02127 read_subfile(int index, pvector<unsigned char> &result) {
02128 nassertr(is_read_valid(), false);
02129 nassertr(index >= 0 && index < (int)_subfiles.size(), false);
02130 result.clear();
02131
02132
02133 nassertr(is_read_valid(), NULL);
02134 nassertr(index >= 0 && index < (int)_subfiles.size(), NULL);
02135 Subfile *subfile = _subfiles[index];
02136
02137 if (subfile->_source != (istream *)NULL ||
02138 !subfile->_source_filename.empty()) {
02139
02140
02141 flush();
02142
02143
02144
02145 nassertr(subfile == _subfiles[index], NULL);
02146 }
02147
02148 result.reserve(subfile->_uncompressed_length);
02149
02150 bool success = true;
02151 if (subfile->_flags & (SF_encrypted | SF_compressed)) {
02152
02153
02154 istream *in = open_read_subfile(index);
02155 if (in == (istream *)NULL) {
02156 return false;
02157 }
02158
02159 success = VirtualFile::simple_read_file(in, result);
02160 close_read_subfile(in);
02161
02162 } else {
02163
02164
02165
02166 static const size_t buffer_size = 4096;
02167 char buffer[buffer_size];
02168
02169 streamsize pos = _offset + subfile->_data_start;
02170 size_t max_bytes = subfile->_data_length;
02171 streamsize count = 0;
02172 bool eof = true;
02173
02174 streamsize num_bytes = (streamsize)min(buffer_size, max_bytes);
02175 _read->seek_read(pos, buffer, num_bytes, count, eof);
02176 while (count != 0) {
02177 thread_consider_yield();
02178 nassertr(count <= (streamsize)max_bytes, false);
02179 result.insert(result.end(), buffer, buffer + (size_t)count);
02180 max_bytes -= (size_t)count;
02181 pos += count;
02182
02183 num_bytes = (streamsize)min(buffer_size, max_bytes);
02184 _read->seek_read(pos, buffer, num_bytes, count, eof);
02185 }
02186
02187 success = !eof;
02188 }
02189
02190 if (!success) {
02191 ostringstream message;
02192 message << "I/O error reading from " << get_multifile_name() << " at "
02193 << get_subfile_name(index);
02194 nassert_raise(message.str());
02195 return false;
02196 }
02197
02198 return true;
02199 }
02200
02201
02202
02203
02204
02205
02206
02207
02208
02209
02210 streampos Multifile::
02211 pad_to_streampos(streampos fpos) {
02212 nassertr(_write != (ostream *)NULL, fpos);
02213 nassertr(_write->tellp() == fpos, fpos);
02214 streampos new_fpos = normalize_streampos(fpos);
02215 while (fpos < new_fpos) {
02216 _write->put(0);
02217 fpos += 1;
02218 }
02219 nassertr(_write->tellp() == fpos, fpos);
02220 return fpos;
02221 }
02222
02223
02224
02225
02226
02227
02228
02229 void Multifile::
02230 add_new_subfile(Subfile *subfile, int compression_level) {
02231 if (compression_level != 0) {
02232 #ifndef HAVE_ZLIB
02233 express_cat.warning()
02234 << "zlib not compiled in; cannot generated compressed multifiles.\n";
02235 compression_level = 0;
02236 #else // HAVE_ZLIB
02237 subfile->_flags |= SF_compressed;
02238 subfile->_compression_level = compression_level;
02239 #endif // HAVE_ZLIB
02240 }
02241
02242 #ifdef HAVE_OPENSSL
02243 if (_encryption_flag) {
02244 subfile->_flags |= SF_encrypted;
02245 }
02246 #endif // HAVE_OPENSSL
02247
02248 if (_next_index != (streampos)0) {
02249
02250
02251 _needs_repack = true;
02252 }
02253
02254 pair<Subfiles::iterator, bool> insert_result = _subfiles.insert(subfile);
02255 if (!insert_result.second) {
02256
02257
02258 Subfile *old_subfile = (*insert_result.first);
02259 old_subfile->_flags |= SF_deleted;
02260
02261
02262 PendingSubfiles::iterator ni = find(_new_subfiles.begin(), _new_subfiles.end(), old_subfile);
02263 if (ni != _new_subfiles.end()) {
02264 _new_subfiles.erase(ni);
02265
02266 } else {
02267
02268 _removed_subfiles.push_back(old_subfile);
02269 }
02270
02271 (*insert_result.first) = subfile;
02272 }
02273
02274 _new_subfiles.push_back(subfile);
02275 }
02276
02277
02278
02279
02280
02281
02282
02283
02284
02285 istream *Multifile::
02286 open_read_subfile(Subfile *subfile) {
02287 nassertr(subfile->_source == (istream *)NULL &&
02288 subfile->_source_filename.empty(), NULL);
02289
02290
02291
02292 nassertr(subfile->_data_start != (streampos)0, NULL);
02293 istream *stream =
02294 new ISubStream(_read, _offset + subfile->_data_start,
02295 _offset + subfile->_data_start + (streampos)subfile->_data_length);
02296
02297 if ((subfile->_flags & SF_encrypted) != 0) {
02298 #ifndef HAVE_OPENSSL
02299 express_cat.error()
02300 << "OpenSSL not compiled in; cannot read encrypted multifiles.\n";
02301 delete stream;
02302 return NULL;
02303 #else // HAVE_OPENSSL
02304
02305
02306 IDecryptStream *wrapper =
02307 new IDecryptStream(stream, true, _encryption_password);
02308 stream = wrapper;
02309
02310
02311
02312 char this_header[_encrypt_header_size];
02313 stream->read(this_header, _encrypt_header_size);
02314 if (stream->fail() || stream->gcount() != (unsigned)_encrypt_header_size ||
02315 memcmp(this_header, _encrypt_header, _encrypt_header_size) != 0) {
02316 express_cat.error()
02317 << "Unable to decrypt subfile " << subfile->_name << ".\n";
02318 delete stream;
02319 return NULL;
02320 }
02321 #endif // HAVE_OPENSSL
02322 }
02323
02324 if ((subfile->_flags & SF_compressed) != 0) {
02325 #ifndef HAVE_ZLIB
02326 express_cat.error()
02327 << "zlib not compiled in; cannot read compressed multifiles.\n";
02328 delete stream;
02329 return NULL;
02330 #else // HAVE_ZLIB
02331
02332
02333 IDecompressStream *wrapper = new IDecompressStream(stream, true);
02334 stream = wrapper;
02335 #endif // HAVE_ZLIB
02336 }
02337
02338 if (stream->fail()) {
02339
02340 delete stream;
02341 return NULL;
02342 }
02343
02344 return stream;
02345 }
02346
02347
02348
02349
02350
02351
02352 string Multifile::
02353 standardize_subfile_name(const string &subfile_name) const {
02354 Filename name = subfile_name;
02355 name.standardize();
02356 if (name.empty() || name == "/") {
02357
02358 return string();
02359 }
02360
02361 if (name[0] == '/') {
02362 return name.get_fullpath().substr(1);
02363 } else if (name.length() > 2 && name[0] == '.' && name[1] == '/') {
02364 return name.get_fullpath().substr(2);
02365 } else {
02366 return name.get_fullpath();
02367 }
02368 }
02369
02370
02371
02372
02373
02374
02375
02376 void Multifile::
02377 clear_subfiles() {
02378 PendingSubfiles::iterator pi;
02379 for (pi = _removed_subfiles.begin(); pi != _removed_subfiles.end(); ++pi) {
02380 Subfile *subfile = (*pi);
02381 subfile->rewrite_index_flags(*_write);
02382 delete subfile;
02383 }
02384 _removed_subfiles.clear();
02385
02386
02387
02388 _new_subfiles.clear();
02389
02390 #ifdef HAVE_OPENSSL
02391 for (pi = _cert_special.begin(); pi != _cert_special.end(); ++pi) {
02392 Subfile *subfile = (*pi);
02393 delete subfile;
02394 }
02395 _cert_special.clear();
02396
02397 _signatures.clear();
02398 #endif // HAVE_OPENSSL
02399
02400 Subfiles::iterator fi;
02401 for (fi = _subfiles.begin(); fi != _subfiles.end(); ++fi) {
02402 Subfile *subfile = (*fi);
02403 delete subfile;
02404 }
02405 _subfiles.clear();
02406 }
02407
02408
02409
02410
02411
02412
02413
02414 bool Multifile::
02415 read_index() {
02416 nassertr(_read != (IStreamWrapper *)NULL, false);
02417
02418
02419
02420 _read->acquire();
02421 istream *read = _read->get_istream();
02422
02423 char this_header[_header_size];
02424 read->seekg(_offset);
02425
02426
02427
02428
02429
02430
02431
02432 _header_prefix = string();
02433 int ch = read->get();
02434
02435 if (ch == '#') {
02436 while (ch != EOF && ch == '#') {
02437
02438 while (ch != EOF && ch != '\n') {
02439 _header_prefix += ch;
02440 ch = read->get();
02441 }
02442
02443 while (ch != EOF && (isspace(ch) || ch == '\r')) {
02444 _header_prefix += ch;
02445 ch = read->get();
02446 }
02447 }
02448 }
02449
02450
02451 this_header[0] = ch;
02452 read->read(this_header + 1, _header_size - 1);
02453 if (read->fail() || read->gcount() != (unsigned)(_header_size - 1)) {
02454 express_cat.info()
02455 << "Unable to read Multifile header " << _multifile_name << ".\n";
02456 _read->release();
02457 close();
02458 return false;
02459 }
02460
02461 if (memcmp(this_header, _header, _header_size) != 0) {
02462 express_cat.info()
02463 << _multifile_name << " is not a Multifile.\n";
02464 _read->release();
02465 close();
02466 return false;
02467 }
02468
02469
02470 StreamReader reader(read, false);
02471 _file_major_ver = reader.get_int16();
02472 _file_minor_ver = reader.get_int16();
02473 _scale_factor = reader.get_uint32();
02474 _new_scale_factor = _scale_factor;
02475
02476 if (read->eof() || read->fail()) {
02477 express_cat.info()
02478 << _multifile_name << " header is truncated.\n";
02479 _read->release();
02480 close();
02481 return false;
02482 }
02483
02484 if (_file_major_ver != _current_major_ver ||
02485 (_file_major_ver == _current_major_ver &&
02486 _file_minor_ver > _current_minor_ver)) {
02487 express_cat.info()
02488 << _multifile_name << " has version " << _file_major_ver << "."
02489 << _file_minor_ver << ", expecting version "
02490 << _current_major_ver << "." << _current_minor_ver << ".\n";
02491 _read->release();
02492 close();
02493 return false;
02494 }
02495
02496 _record_timestamp = true;
02497 if (_file_minor_ver >= 1) {
02498 time_t read_timestamp = reader.get_uint32();
02499 if (read_timestamp == 0) {
02500
02501
02502 _record_timestamp = false;
02503 } else {
02504 _timestamp = read_timestamp;
02505 }
02506 _timestamp_dirty = false;
02507 }
02508
02509
02510 _next_index = read->tellg() - _offset;
02511 _next_index = normalize_streampos(_next_index);
02512 read->seekg(_next_index + _offset);
02513 _last_index = 0;
02514 _last_data_byte = 0;
02515 streampos index_forward;
02516 streamoff bytes_skipped = 0;
02517 bool read_cert_special = false;
02518
02519 Subfile *subfile = new Subfile;
02520 index_forward = subfile->read_index(*read, _next_index, this);
02521 while (index_forward != (streampos)0) {
02522 _last_index = _next_index;
02523 if (subfile->is_deleted()) {
02524
02525 _needs_repack = true;
02526 delete subfile;
02527 } else if (subfile->is_cert_special()) {
02528
02529
02530 _cert_special.push_back(subfile);
02531 read_cert_special = true;
02532 } else {
02533 _subfiles.push_back(subfile);
02534 }
02535 if (!subfile->is_cert_special()) {
02536 if (bytes_skipped != 0) {
02537
02538
02539
02540 _needs_repack = true;
02541 }
02542 if (read_cert_special) {
02543
02544
02545
02546 _needs_repack = true;
02547 }
02548 _last_data_byte = max(_last_data_byte, subfile->get_last_byte_pos());
02549 }
02550 streampos curr_pos = normalize_streampos(read->tellg() - _offset);
02551 bytes_skipped = index_forward - curr_pos;
02552 read->seekg(index_forward + _offset);
02553 _next_index = index_forward;
02554 subfile = new Subfile;
02555 index_forward = subfile->read_index(*read, _next_index, this);
02556 }
02557 if (subfile->is_index_invalid()) {
02558 express_cat.info()
02559 << "Error reading index for " << _multifile_name << ".\n";
02560 _read->release();
02561 close();
02562 delete subfile;
02563 return false;
02564 }
02565
02566
02567
02568 for (size_t si = 1; si < _subfiles.size() && !_needs_repack; ++si) {
02569 if (*_subfiles[si] < *_subfiles[si - 1]) {
02570 _needs_repack = true;
02571 }
02572 }
02573
02574 if (_needs_repack) {
02575
02576 size_t before_size = _subfiles.size();
02577 _subfiles.sort();
02578 size_t after_size = _subfiles.size();
02579
02580
02581
02582 nassertr(before_size == after_size, true);
02583 }
02584
02585 delete subfile;
02586 _read->release();
02587 return true;
02588 }
02589
02590
02591
02592
02593
02594
02595
02596 bool Multifile::
02597 write_header() {
02598 _file_major_ver = _current_major_ver;
02599 _file_minor_ver = _current_minor_ver;
02600
02601 nassertr(_write != (ostream *)NULL, false);
02602 nassertr(_write->tellp() == (streampos)0, false);
02603 _write->write(_header_prefix.data(), _header_prefix.size());
02604 _write->write(_header, _header_size);
02605 StreamWriter writer(_write, false);
02606 writer.add_int16(_current_major_ver);
02607 writer.add_int16(_current_minor_ver);
02608 writer.add_uint32(_scale_factor);
02609
02610 if (_record_timestamp) {
02611 writer.add_uint32(_timestamp);
02612 } else {
02613 writer.add_uint32(0);
02614 _timestamp_dirty = false;
02615 }
02616
02617 _next_index = _write->tellp();
02618 _next_index = pad_to_streampos(_next_index);
02619 _last_index = 0;
02620
02621 if (_write->fail()) {
02622 express_cat.info()
02623 << "Unable to write header for " << _multifile_name << ".\n";
02624 close();
02625 return false;
02626 }
02627
02628 return true;
02629 }
02630
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641
02642
02643 void Multifile::
02644 check_signatures() {
02645 #ifdef HAVE_OPENSSL
02646 PendingSubfiles::iterator pi;
02647
02648 for (pi = _cert_special.begin(); pi != _cert_special.end(); ++pi) {
02649 Subfile *subfile = (*pi);
02650 nassertv((subfile->_flags & SF_signature) != 0);
02651
02652
02653 istream *stream = open_read_subfile(subfile);
02654 nassertv(stream != NULL);
02655 StreamReader reader(*stream);
02656 size_t sig_size = reader.get_uint32();
02657 string sig_string = reader.extract_bytes(sig_size);
02658
02659 size_t num_certs = reader.get_uint32();
02660
02661
02662 pvector<unsigned char> buffer;
02663 bool success = VirtualFile::simple_read_file(stream, buffer);
02664 nassertv(success);
02665 close_read_subfile(stream);
02666
02667
02668
02669 CertChain chain;
02670 EVP_PKEY *pkey = NULL;
02671 if (!buffer.empty()) {
02672 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
02673
02674 const unsigned char *bp, *bp_end;
02675 #else
02676
02677 unsigned char *bp, *bp_end;
02678 #endif
02679 bp = (unsigned char *)&buffer[0];
02680 bp_end = bp + buffer.size();
02681 X509 *x509 = d2i_X509(NULL, &bp, bp_end - bp);
02682 while (num_certs > 0 && x509 != NULL) {
02683 chain.push_back(CertRecord(x509));
02684 --num_certs;
02685 x509 = d2i_X509(NULL, &bp, bp_end - bp);
02686 }
02687 if (num_certs != 0 || x509 != NULL) {
02688 express_cat.warning()
02689 << "Extra data in signature record.\n";
02690 }
02691 }
02692
02693 if (!chain.empty()) {
02694 pkey = X509_get_pubkey(chain[0]._cert);
02695 }
02696
02697 if (pkey != NULL) {
02698 EVP_MD_CTX *md_ctx;
02699 #ifdef SSL_097
02700 md_ctx = EVP_MD_CTX_create();
02701 #else
02702 md_ctx = new EVP_MD_CTX;
02703 #endif
02704 EVP_VerifyInit(md_ctx, EVP_sha1());
02705
02706 nassertv(_read != NULL);
02707 _read->acquire();
02708 istream *read = _read->get_istream();
02709
02710
02711
02712 read->seekg(_offset);
02713 streampos bytes_remaining = _last_data_byte;
02714 static const size_t buffer_size = 4096;
02715 char buffer[buffer_size];
02716 read->read(buffer, min((streampos)buffer_size, bytes_remaining));
02717 size_t count = read->gcount();
02718 while (count != 0) {
02719 nassertv(count <= buffer_size);
02720 EVP_VerifyUpdate(md_ctx, buffer, count);
02721 bytes_remaining -= count;
02722 read->read(buffer, min((streampos)buffer_size, bytes_remaining));
02723 count = read->gcount();
02724 }
02725 nassertv(bytes_remaining == (streampos)0);
02726 _read->release();
02727
02728
02729 int verify_result =
02730 EVP_VerifyFinal(md_ctx,
02731 (unsigned char *)sig_string.data(),
02732 sig_string.size(), pkey);
02733 if (verify_result == 1) {
02734
02735 _signatures.push_back(chain);
02736 } else {
02737
02738 _needs_repack = true;
02739 }
02740 }
02741 }
02742 #endif // HAVE_OPENSSL
02743
02744 _cert_special.clear();
02745 }
02746
02747
02748
02749
02750
02751
02752
02753
02754
02755
02756 streampos Multifile::Subfile::
02757 read_index(istream &read, streampos fpos, Multifile *multifile) {
02758 nassertr(read.tellg() - multifile->_offset == fpos, fpos);
02759
02760
02761
02762 StreamReader reader(read);
02763
02764 streampos next_index = multifile->word_to_streampos(reader.get_uint32());
02765 if (read.eof() || read.fail()) {
02766 _flags |= SF_index_invalid;
02767 return 0;
02768 }
02769
02770 if (next_index == (streampos)0) {
02771 return 0;
02772 }
02773
02774
02775
02776 _index_start = fpos;
02777 _index_length = 0;
02778
02779 _data_start = multifile->word_to_streampos(reader.get_uint32());
02780 _data_length = reader.get_uint32();
02781 _flags = reader.get_uint16();
02782 if ((_flags & (SF_compressed | SF_encrypted)) != 0) {
02783 _uncompressed_length = reader.get_uint32();
02784 } else {
02785 _uncompressed_length = _data_length;
02786 }
02787 if (multifile->_file_minor_ver < 1) {
02788 _timestamp = multifile->get_timestamp();
02789 } else {
02790 _timestamp = reader.get_uint32();
02791 if (_timestamp == 0) {
02792 _timestamp = multifile->get_timestamp();
02793 }
02794 }
02795
02796 size_t name_length = reader.get_uint16();
02797 if (read.eof() || read.fail()) {
02798 _flags |= SF_index_invalid;
02799 return 0;
02800 }
02801
02802
02803 char *name_buffer = (char *)PANDA_MALLOC_ARRAY(name_length);
02804 nassertr(name_buffer != (char *)NULL, next_index);
02805 for (size_t ni = 0; ni < name_length; ni++) {
02806 name_buffer[ni] = read.get() ^ 0xff;
02807 }
02808 _name = string(name_buffer, name_length);
02809 PANDA_FREE_ARRAY(name_buffer);
02810
02811 if (read.eof() || read.fail()) {
02812 _flags |= SF_index_invalid;
02813 return 0;
02814 }
02815
02816 _index_length = read.tellg() - fpos - multifile->_offset;
02817 return next_index;
02818 }
02819
02820
02821
02822
02823
02824
02825
02826
02827
02828
02829
02830
02831
02832 streampos Multifile::Subfile::
02833 write_index(ostream &write, streampos fpos, Multifile *multifile) {
02834 nassertr(write.tellp() - multifile->_offset == fpos, fpos);
02835
02836 _index_start = fpos;
02837 _index_length = 0;
02838
02839
02840
02841 Datagram dg;
02842 dg.add_uint32(multifile->streampos_to_word(_data_start));
02843 dg.add_uint32(_data_length);
02844 dg.add_uint16(_flags);
02845 if ((_flags & (SF_compressed | SF_encrypted)) != 0) {
02846 dg.add_uint32(_uncompressed_length);
02847 }
02848 dg.add_uint32(_timestamp);
02849 dg.add_uint16(_name.length());
02850
02851
02852
02853
02854
02855
02856 string::iterator ni;
02857 for (ni = _name.begin(); ni != _name.end(); ++ni) {
02858 dg.add_int8((*ni) ^ 0xff);
02859 }
02860
02861 size_t this_index_size = 4 + dg.get_length();
02862
02863
02864 streampos next_index = fpos + (streampos)this_index_size;
02865
02866 Datagram idg;
02867 idg.add_uint32(multifile->streampos_to_word(next_index));
02868
02869 write.write((const char *)idg.get_data(), idg.get_length());
02870 write.write((const char *)dg.get_data(), dg.get_length());
02871
02872 _index_length = write.tellp() - fpos - multifile->_offset;
02873 return next_index;
02874 }
02875
02876
02877
02878
02879
02880
02881
02882
02883
02884
02885
02886
02887
02888
02889
02890
02891
02892
02893
02894
02895
02896 streampos Multifile::Subfile::
02897 write_data(ostream &write, istream *read, streampos fpos,
02898 Multifile *multifile) {
02899 nassertr(write.tellp() - multifile->_offset == fpos, fpos);
02900
02901 istream *source = _source;
02902 pifstream source_file;
02903 if (source == (istream *)NULL && !_source_filename.empty()) {
02904
02905 if (!_source_filename.open_read(source_file)) {
02906
02907 express_cat.info()
02908 << "Unable to read " << _source_filename << ".\n";
02909 _flags |= SF_data_invalid;
02910 _data_length = 0;
02911 _uncompressed_length = 0;
02912 } else {
02913 source = &source_file;
02914 }
02915 }
02916
02917 if (source == (istream *)NULL) {
02918
02919
02920 if (read == (istream *)NULL) {
02921
02922 express_cat.info()
02923 << "No source for subfile " << _name << ".\n";
02924 _flags |= SF_data_invalid;
02925 } else {
02926
02927 read->seekg(_data_start + multifile->_offset);
02928 for (size_t p = 0; p < _data_length; p++) {
02929 int byte = read->get();
02930 if (read->eof() || read->fail()) {
02931
02932 express_cat.info()
02933 << "Unexpected EOF for subfile " << _name << ".\n";
02934 _flags |= SF_data_invalid;
02935 break;
02936 }
02937 write.put(byte);
02938 }
02939 }
02940 } else {
02941
02942
02943 ostream *putter = &write;
02944 bool delete_putter = false;
02945
02946 #ifndef HAVE_OPENSSL
02947
02948
02949 nassertr((_flags & SF_encrypted) == 0, fpos);
02950
02951 #else // HAVE_OPENSSL
02952 if ((_flags & SF_encrypted) != 0) {
02953
02954 OEncryptStream *encrypt = new OEncryptStream;
02955 encrypt->set_iteration_count(multifile->_encryption_iteration_count);
02956 encrypt->open(putter, delete_putter, multifile->_encryption_password);
02957
02958 putter = encrypt;
02959 delete_putter = true;
02960
02961
02962
02963
02964 putter->write(_encrypt_header, _encrypt_header_size);
02965 }
02966 #endif // HAVE_OPENSSL
02967
02968 #ifndef HAVE_ZLIB
02969
02970
02971 nassertr((_flags & SF_compressed) == 0, fpos);
02972 #else // HAVE_ZLIB
02973 if ((_flags & SF_compressed) != 0) {
02974
02975 putter = new OCompressStream(putter, delete_putter, _compression_level);
02976 delete_putter = true;
02977 }
02978 #endif // HAVE_ZLIB
02979
02980 streampos write_start = fpos;
02981 _uncompressed_length = 0;
02982
02983 #ifndef HAVE_OPENSSL
02984
02985 nassertr((_flags & SF_signature) == 0, fpos);
02986
02987 #else // HAVE_OPENSSL
02988 if ((_flags & SF_signature) != 0) {
02989
02990
02991
02992
02993
02994
02995 nassertr(read != NULL, fpos);
02996
02997
02998 nassertr(_pkey != NULL, fpos);
02999
03000 EVP_MD_CTX *md_ctx;
03001 #ifdef SSL_097
03002 md_ctx = EVP_MD_CTX_create();
03003 #else
03004 md_ctx = new EVP_MD_CTX;
03005 #endif
03006 EVP_SignInit(md_ctx, EVP_sha1());
03007
03008
03009
03010 nassertr(multifile->_last_data_byte < fpos, fpos);
03011 read->seekg(multifile->_offset);
03012 streampos bytes_remaining = multifile->_last_data_byte;
03013 static const size_t buffer_size = 4096;
03014 char buffer[buffer_size];
03015 read->read(buffer, min((streampos)buffer_size, bytes_remaining));
03016 size_t count = read->gcount();
03017 while (count != 0) {
03018 nassertr(count <= buffer_size, fpos);
03019 EVP_SignUpdate(md_ctx, buffer, count);
03020 bytes_remaining -= count;
03021 read->read(buffer, min((streampos)buffer_size, bytes_remaining));
03022 count = read->gcount();
03023 }
03024 nassertr(bytes_remaining == (streampos)0, fpos);
03025
03026
03027 unsigned int max_size = EVP_PKEY_size(_pkey);
03028 unsigned char *sig_data = new unsigned char[max_size];
03029 unsigned int sig_size;
03030 if (!EVP_SignFinal(md_ctx, sig_data, &sig_size, _pkey)) {
03031 OpenSSLWrapper *sslw = OpenSSLWrapper::get_global_ptr();
03032 sslw->notify_ssl_errors();
03033 }
03034 nassertr(sig_size <= max_size, fpos);
03035
03036 StreamWriter writer(*putter);
03037 writer.add_uint32(sig_size);
03038 putter->write((char *)sig_data, sig_size);
03039 _uncompressed_length += 4 + sig_size;
03040
03041 delete[] sig_data;
03042
03043 #ifdef SSL_097
03044 EVP_MD_CTX_destroy(md_ctx);
03045 #else
03046 delete md_ctx;
03047 #endif
03048 }
03049 #endif // HAVE_OPENSSL
03050
03051
03052 static const size_t buffer_size = 4096;
03053 char buffer[buffer_size];
03054
03055 source->read(buffer, buffer_size);
03056 size_t count = source->gcount();
03057 while (count != 0) {
03058 _uncompressed_length += count;
03059 putter->write(buffer, count);
03060 source->read(buffer, buffer_size);
03061 count = source->gcount();
03062 }
03063
03064 if (delete_putter) {
03065 delete putter;
03066 }
03067
03068 streampos write_end = write.tellp() - multifile->_offset;
03069 _data_length = (size_t)(write_end - write_start);
03070 }
03071
03072
03073
03074 _data_start = fpos;
03075
03076
03077
03078
03079 if (!_source_filename.empty()) {
03080 _timestamp = _source_filename.get_timestamp();
03081 }
03082 if (_timestamp == 0) {
03083 _timestamp = time(NULL);
03084 }
03085
03086 _source = (istream *)NULL;
03087 _source_filename = Filename();
03088 source_file.close();
03089
03090 return fpos + (streampos)_data_length;
03091 }
03092
03093
03094
03095
03096
03097
03098
03099
03100 void Multifile::Subfile::
03101 rewrite_index_data_start(ostream &write, Multifile *multifile) {
03102 nassertv(_index_start != (streampos)0);
03103
03104 static const size_t data_start_offset = 4;
03105 size_t data_start_pos = _index_start + (streampos)data_start_offset;
03106 write.seekp(data_start_pos + multifile->_offset);
03107 nassertv(!write.fail());
03108
03109 StreamWriter writer(write);
03110 writer.add_uint32(multifile->streampos_to_word(_data_start));
03111 writer.add_uint32(_data_length);
03112 writer.add_uint16(_flags);
03113 if ((_flags & (SF_compressed | SF_encrypted)) != 0) {
03114 writer.add_uint32(_uncompressed_length);
03115 }
03116 if (multifile->_record_timestamp) {
03117 writer.add_uint32(_timestamp);
03118 } else {
03119 writer.add_uint32(0);
03120 }
03121 }
03122
03123
03124
03125
03126
03127
03128
03129
03130 void Multifile::Subfile::
03131 rewrite_index_flags(ostream &write) {
03132
03133
03134 if (_index_start != (streampos)0) {
03135 static const size_t flags_offset = 4 + 4 + 4;
03136 size_t flags_pos = _index_start + (streampos)flags_offset;
03137 write.seekp(flags_pos);
03138 nassertv(!write.fail());
03139
03140 StreamWriter writer(write);
03141 writer.add_uint16(_flags);
03142 }
03143 }