#ifndef MINIVHD_INTERNAL_H
#define MINIVHD_INTERNAL_H
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "minivhd.h" /* Pull in the MVHDMeta typedef */

#define MVHD_FOOTER_SIZE 512
#define MVHD_SPARSE_SIZE 1024

#define MVHD_SECTOR_SIZE 512
#define MVHD_BAT_ENT_PER_SECT 128

#define MVHD_MAX_SIZE_IN_BYTES 0x1fe00000000

#define MVHD_SPARSE_BLK 0xffffffff
/* For simplicity, we don't handle paths longer than this 
 * Note, this is the max path in characters, as that is what
 * Windows uses
 */
#define MVHD_MAX_PATH_CHARS 260
#define MVHD_MAX_PATH_BYTES 1040

#define MVHD_DIF_LOC_W2RU 0x57327275
#define MVHD_DIF_LOC_W2KU 0x57326B75

typedef struct MVHDSectorBitmap {
	uint8_t *curr_bitmap;
	int sector_count;
	int curr_block;
} MVHDSectorBitmap;

typedef struct MVHDFooter {
	uint8_t cookie[8];
	uint32_t features;
	uint32_t fi_fmt_vers;
	uint64_t data_offset;
	uint32_t timestamp;
	uint8_t cr_app[4];
	uint32_t cr_vers;
	uint8_t cr_host_os[4];
	uint64_t orig_sz;
	uint64_t curr_sz;
	struct {
		uint16_t cyl;
		uint8_t heads;
		uint8_t spt;
	} geom;
	uint32_t disk_type;
	uint32_t checksum;
	uint8_t uuid[16];
	uint8_t saved_st;
	uint8_t reserved[427];
} MVHDFooter;

typedef struct MVHDSparseHeader {
	uint8_t cookie[8];
	uint64_t data_offset;
	uint64_t bat_offset;
	uint32_t head_vers;
	uint32_t max_bat_ent;
	uint32_t block_sz;
	uint32_t checksum;
	uint8_t par_uuid[16];
	uint32_t par_timestamp;
	uint32_t reserved_1;
	uint8_t par_utf16_name[512];
	struct {
		uint32_t plat_code;
		uint32_t plat_data_space;
		uint32_t plat_data_len;
		uint32_t reserved;
		uint64_t plat_data_offset;
	} par_loc_entry[8];
	uint8_t reserved_2[256];
} MVHDSparseHeader;

struct MVHDMeta {
	FILE *f;
	bool readonly;
	char filename[MVHD_MAX_PATH_BYTES];
	struct MVHDMeta *parent;
	MVHDFooter footer;
	MVHDSparseHeader sparse;
	uint32_t *block_offset;
	int sect_per_block;
	MVHDSectorBitmap bitmap;
	int (*read_sectors)(MVHDMeta *, uint32_t, int, void *);
	int (*write_sectors)(MVHDMeta *, uint32_t, int, void *);
	struct {
		uint8_t *zero_data;
		int sector_count;
	} format_buffer;
};

#endif
