#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
