dosbox-x/include/zipfile.h
2021-08-22 15:47:10 +09:00

137 lines
6.2 KiB
C++

#ifndef ZIPFILE_H
#define ZIPFILE_H
#include <stdint.h>
extern "C" {
#include "zipcrc.h"
}
#include <map>
#pragma pack(push,1)
struct ZIPLocalFileHeader { /* ZIP File Format Specification v6.3.4 sec 4.3.7 Local file header */
uint32_t local_file_header_signature; /* +0x00 0x04034b50 */
uint16_t version_needed_to_extract; /* +0x04 */
uint16_t general_purpose_bit_flag; /* +0x06 */
uint16_t compression_method; /* +0x08 */
uint16_t last_mod_file_time; /* +0x0A */
uint16_t last_mod_file_date; /* +0x0C */
uint32_t crc_32; /* +0x0E */
uint32_t compressed_size; /* +0x12 */
uint32_t uncompressed_size; /* +0x16 */
uint16_t file_name_length; /* +0x1A */
uint16_t extra_field_length; /* +0x1C */
}; /* =0x1E */
#pragma pack(pop)
#pragma pack(push,1)
# define PKZIP_CENTRAL_DIRECTORY_HEADER_SIG (0x02014B50UL)
struct pkzip_central_directory_header_main { /* PKZIP APPNOTE 2.0: General Format of a ZIP file section C */
uint32_t sig; /* 4 bytes +0x00 0x02014B50 = 'PK\x01\x02' */
uint16_t version_made_by; /* 2 bytes +0x04 version made by */
uint16_t version_needed_to_extract; /* 2 bytes +0x06 version needed to extract */
uint16_t general_purpose_bit_flag; /* 2 bytes +0x08 general purpose bit flag */
uint16_t compression_method; /* 2 bytes +0x0A compression method */
uint16_t last_mod_file_time; /* 2 bytes +0x0C */
uint16_t last_mod_file_date; /* 2 bytes +0x0E */
uint32_t crc32; /* 4 bytes +0x10 */
uint32_t compressed_size; /* 4 bytes +0x14 */
uint32_t uncompressed_size; /* 4 bytes +0x18 */
uint16_t filename_length; /* 2 bytes +0x1C */
uint16_t extra_field_length; /* 2 bytes +0x1E */
uint16_t file_comment_length; /* 2 bytes +0x20 */
uint16_t disk_number_start; /* 2 bytes +0x22 */
uint16_t internal_file_attributes; /* 2 bytes +0x24 */
uint32_t external_file_attributes; /* 4 bytes +0x26 */
uint32_t relative_offset_of_local_header;/* 4 bytes +0x2A */
}; /* =0x2E */
/* filename and extra field follow, then file data */
#pragma pack(pop)
#pragma pack(push,1)
# define PKZIP_CENTRAL_DIRECTORY_END_SIG (0x06054B50UL)
struct pkzip_central_directory_header_end { /* PKZIP APPNOTE 2.0: General Format of a ZIP file section C */
uint32_t sig; /* 4 bytes +0x00 0x06054B50 = 'PK\x05\x06' */
uint16_t number_of_this_disk; /* 2 bytes +0x04 */
uint16_t number_of_disk_with_start_of_central_directory;
/* 2 bytes +0x06 */
uint16_t total_number_of_entries_of_central_dir_on_this_disk;
/* 2 bytes +0x08 */
uint16_t total_number_of_entries_of_central_dir;
/* 2 bytes +0x0A */
uint32_t size_of_central_directory; /* 4 bytes +0x0C */
uint32_t offset_of_central_directory_from_start_disk;
/* 4 bytes +0x10 */
uint16_t zipfile_comment_length; /* 2 bytes +0x14 */
}; /* =0x16 */
/* filename and extra field follow, then file data */
#pragma pack(pop)
class ZIPFile;
class ZIPFileEntry {
public:
bool can_write = false;
off_t file_length = 0;
off_t file_offset = 0;
off_t file_header_offset = 0;
off_t position = 0;
std::string name;
ZIPFile* file = NULL;
zipcrc_t write_crc = 0;
public:
bool rewind(void);
int read(void *buffer,size_t count);
int write(const void *buffer,size_t count);
private: /* encourage code that uses this C++ class to stream-read so that
this code can add deflate compression support later without pain and hacks */
off_t seek_file(off_t pos);
};
class ZIPFile {
public:
int file_fd = -1;
std::string filename;
std::map<std::string,ZIPFileEntry> entries;
off_t write_pos = 0;
bool can_write = false;
bool wrote_trailer = false;
std::string current_entry; /* currently writing entry */
public:
ZIPFile();
~ZIPFile();
public:
void close(void);
ZIPFileEntry *get_entry(const char *name);
ZIPFileEntry *new_entry(const char *name);
off_t end_of_file(void);
void close_current(void);
int open(const char *path,int mode);
off_t seek_file(off_t pos);
int read(void *buffer,size_t count);
int write(const void *buffer,size_t count);
void writeZIPFooter(void);
};
class zip_nv_pair_map : public std::map<std::string, std::string> {
public:
zip_nv_pair_map();
zip_nv_pair_map(ZIPFileEntry &ent);
public:
std::string &get(const char *name);
bool get_bool(const char *name);
long get_long(const char *name);
unsigned long get_ulong(const char *name);
void process_line(char *line/*will modify, assume caller has put NUL at the end*/);
void read_nv_pairs(ZIPFileEntry &ent);
};
void zip_nv_write(ZIPFileEntry &ent,const char *name,bool val);
void zip_nv_write(ZIPFileEntry &ent,const char *name,long val);
void zip_nv_write_hex(ZIPFileEntry &ent,const char *name,unsigned long val);
#endif //ZIPFILE_H