| 614 | } |
| 615 | |
| 616 | BOOL OpenMPQ(const char *pszArchive, DWORD dwChar) |
| 617 | { |
| 618 | DWORD dwFlagsAndAttributes; |
| 619 | DWORD key; |
| 620 | _FILEHEADER fhdr; |
| 621 | |
| 622 | InitHash(); |
| 623 | |
| 624 | if (!cur_archive.Open(pszArchive)) { |
| 625 | return FALSE; |
| 626 | } |
| 627 | if (cur_archive.sgpBlockTbl == NULL || cur_archive.sgpHashTbl == NULL) { |
| 628 | if (!cur_archive.exists) { |
| 629 | InitDefaultMpqHeader(&cur_archive, &fhdr); |
| 630 | } else if (!ReadMPQHeader(&cur_archive, &fhdr)) { |
| 631 | goto on_error; |
| 632 | } |
| 633 | cur_archive.sgpBlockTbl = new _BLOCKENTRY[kBlockEntrySize / sizeof(_BLOCKENTRY)]; |
| 634 | std::memset(cur_archive.sgpBlockTbl, 0, kBlockEntrySize); |
| 635 | if (fhdr.blockcount) { |
| 636 | if (!cur_archive.stream.read(reinterpret_cast<char *>(cur_archive.sgpBlockTbl), kBlockEntrySize)) |
| 637 | goto on_error; |
| 638 | key = Hash("(block table)", 3); |
| 639 | Decrypt(cur_archive.sgpBlockTbl, kBlockEntrySize, key); |
| 640 | } |
| 641 | cur_archive.sgpHashTbl = new _HASHENTRY[kHashEntrySize / sizeof(_HASHENTRY)]; |
| 642 | std::memset(cur_archive.sgpHashTbl, 255, kHashEntrySize); |
| 643 | if (fhdr.hashcount) { |
| 644 | if (!cur_archive.stream.read(reinterpret_cast<char *>(cur_archive.sgpHashTbl), kHashEntrySize)) |
| 645 | goto on_error; |
| 646 | key = Hash("(hash table)", 3); |
| 647 | Decrypt(cur_archive.sgpHashTbl, kHashEntrySize, key); |
| 648 | } |
| 649 | |
| 650 | #ifndef CAN_SEEKP_BEYOND_EOF |
| 651 | if (!cur_archive.stream.seekp(0, std::ios::beg)) |
| 652 | goto on_error; |
| 653 | |
| 654 | // Memorize stream begin, we'll need it for calculations later. |
| 655 | if (!cur_archive.stream.tellp(&cur_archive.stream_begin)) |
| 656 | goto on_error; |
| 657 | |
| 658 | // Write garbage header and tables because some platforms cannot `seekp` beyond EOF. |
| 659 | // The data is incorrect at this point, it will be overwritten on Close. |
| 660 | if (!cur_archive.exists) |
| 661 | cur_archive.WriteHeaderAndTables(); |
| 662 | #endif |
| 663 | } |
| 664 | return TRUE; |
| 665 | on_error: |
| 666 | cur_archive.Close(/*clear_tables=*/true); |
| 667 | return FALSE; |
| 668 | } |
| 669 | |
| 670 | BOOL mpqapi_flush_and_close(const char *pszArchive, BOOL bFree, DWORD dwChar) |
| 671 | { |
no test coverage detected