#include <inttypes.h>
#include <curl/curl.h>
#include <stdbool.h>

#pragma pack(push, 1)

typedef struct EndOfCD {
	uint32_t signature;
	uint16_t diskNo;
	uint16_t CDDiskNo;
	uint16_t CDDiskEntries;
	uint16_t CDEntries;
	uint32_t CDSize;
	uint32_t CDOffset;
	uint16_t lenComment;
}  EndOfCD;

typedef struct CDFile {
	uint32_t signature;
	uint16_t version;
	uint16_t versionExtract;
	uint16_t flags;
	uint16_t method;
	uint16_t modTime;
	uint16_t modDate;
	uint32_t crc32;
	uint32_t compressedSize;
	uint32_t size;
	uint16_t lenFileName;
	uint16_t lenExtra;
	uint16_t lenComment;
	uint16_t diskStart;
	uint16_t internalAttr;
	uint32_t externalAttr;
	uint32_t offset;
}  CDFile;

typedef struct LocalFile {
	uint32_t signature;
	uint16_t versionExtract;
	uint16_t flags;
	uint16_t method;
	uint16_t modTime;
	uint16_t modDate;
	uint32_t crc32;
	uint32_t compressedSize;
	uint32_t size;
	uint16_t lenFileName;
	uint16_t lenExtra;
}  LocalFile;
#pragma pack(pop)

typedef struct ZipInfo ZipInfo;

typedef size_t (WINAPI*PartialZipGetFileCallback)(ZipInfo* info, CDFile* file, unsigned char *buffer, size_t size, void *userInfo);

struct ZipInfo {
	char* url;
	uint64_t length;
	CURL* hCurl;
	char* centralDirectory;
	size_t centralDirectoryRecvd;
	EndOfCD* centralDirectoryDesc;
	char centralDirectoryEnd[0xffff + sizeof(EndOfCD)];
	size_t centralDirectoryEndRecvd;
};

#ifdef __cplusplus
extern "C" {
#endif

	ZipInfo* PartialZipInit(const char* url);

	CDFile* PartialZipFindFile(ZipInfo* info, const char* fileName);
	unsigned char* PartialZipCopyFileName(ZipInfo* info, CDFile* file);

	CDFile* PartialZipListFiles(ZipInfo* info);

	bool PartialZipGetFile(ZipInfo* info, CDFile* file, PartialZipGetFileCallback callback, void *userInfo);
	bool PartialZipGetFiles(ZipInfo* info, CDFile* files[], size_t count, PartialZipGetFileCallback callback, void *userInfo);

	void PartialZipRelease(ZipInfo* info);
	
#ifdef __cplusplus
}
#endif

