You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

74 lines
2.2 KiB

/**
* @file mpq/mpq_writer.hpp
*
* Interface of functions for creating and editing MPQ files.
*/
#pragma once
#include <cstddef>
#include <cstdint>
#include "mpq/mpq_common.hpp"
#include "utils/logged_fstream.hpp"
namespace devilution {
class MpqWriter {
public:
explicit MpqWriter(const char *path);
explicit MpqWriter(const std::string &path)
: MpqWriter(path.c_str())
{
}
MpqWriter(MpqWriter &&other) = default;
MpqWriter &operator=(MpqWriter &&other) = default;
~MpqWriter();
bool HasFile(const char *name) const;
void RemoveHashEntry(const char *filename);
void RemoveHashEntries(bool (*fnGetName)(uint8_t, char *));
bool WriteFile(const char *filename, const std::byte *data, size_t size);
void RenameFile(const char *name, const char *newName);
private:
bool IsValidMpqHeader(MpqFileHeader *hdr) const;
uint32_t GetHashIndex(uint32_t index, uint32_t hashA, uint32_t hashB) const;
uint32_t FetchHandle(const char *filename) const;
bool ReadMPQHeader(MpqFileHeader *hdr);
MpqBlockEntry *AddFile(const char *filename, MpqBlockEntry *block, uint32_t blockIndex);
bool WriteFileContents(const char *filename, const std::byte *fileData, size_t fileSize, MpqBlockEntry *block);
// Returns an unused entry in the block entry table.
MpqBlockEntry *NewBlock(uint32_t *blockIndex = nullptr);
// Marks space at `blockOffset` of size `blockSize` as free (unused) space.
void AllocBlock(uint32_t blockOffset, uint32_t blockSize);
// Returns the file offset that is followed by empty space of at least the given size.
uint32_t FindFreeBlock(uint32_t size);
bool WriteHeaderAndTables();
bool WriteHeader();
bool WriteBlockTable();
bool WriteHashTable();
void InitDefaultMpqHeader(MpqFileHeader *hdr);
LoggedFStream stream_;
std::string name_;
std::uintmax_t size_ {};
std::unique_ptr<MpqHashEntry[]> hashTable_;
std::unique_ptr<MpqBlockEntry[]> blockTable_;
// Amiga cannot Seekp beyond EOF.
// See https://github.com/bebbo/libnix/issues/30
#ifndef __AMIGA__
#define CAN_SEEKP_BEYOND_EOF
#endif
#ifndef CAN_SEEKP_BEYOND_EOF
long streamBegin_;
#endif
};
} // namespace devilution