#pragma once

#include "common.h"
#include "ticket.h"
#include "tmd.h"

#define CIA_HEADER_SIZE     sizeof(CiaHeader)
#define CIA_CERT_SIZE       0xA00
#define CIA_META_SIZE       sizeof(CiaMeta)

// see: https://www.3dbrew.org/wiki/CIA#Meta
typedef struct {
    u8  dependencies[0x180]; // from ExtHeader
    u8  reserved0[0x180];
    u32 core_version; // 2 normally
    u8  reserved1[0xFC];
    u8  smdh[0x36C0]; // from ExeFS
} PACKED_STRUCT CiaMeta;

typedef struct {
    u32 size_header;
    u16 type;
    u16 version;
    u32 size_cert;
    u32 size_ticket;
    u32 size_tmd;
    u32 size_meta;
    u64 size_content;
    u8  content_index[0x2000];
} PACKED_STRUCT CiaHeader;

typedef struct {
    CiaHeader header;
    u8 header_padding[0x40 - (CIA_HEADER_SIZE % 0x40)];
    u8 cert[CIA_CERT_SIZE];
    // cert is aligned and needs no padding
    TicketCommon ticket;
    u8 ticket_padding[0x40 - (TICKET_COMMON_SIZE % 0x40)];
    TitleMetaData tmd;
    TmdContentChunk content_list[TMD_MAX_CONTENTS];
} PACKED_ALIGN(16) CiaStub;

typedef struct { // first 0x20 bytes are identical with CIA header
    u32 size_header;
    u16 type;
    u16 version;
    u32 size_cert;
    u32 size_ticket;
    u32 size_tmd;
    u32 size_meta;
    u64 size_content;
    u32 size_content_list;
    u64 size_cia;
    u32 offset_cert;
    u32 offset_ticket;
    u32 offset_tmd;
    u32 offset_content;
    u32 offset_meta;
    u32 offset_content_list;
    u32 max_contents;
} PACKED_STRUCT CiaInfo;

u32 ValidateCiaHeader(CiaHeader* header);
u32 GetCiaInfo(CiaInfo* info, CiaHeader* header);
u32 FixCiaHeaderForTmd(CiaHeader* header, TitleMetaData* tmd);

u32 BuildCiaCert(u8* ciacert);
u32 BuildCiaMeta(CiaMeta* meta, void* exthdr, void* smdh);
u32 BuildCiaHeader(CiaHeader* header, u32 ticket_size);

u32 DecryptCiaContentSequential(void* data, u32 size, u8* ctr, const u8* titlekey);
u32 EncryptCiaContentSequential(void* data, u32 size, u8* ctr, const u8* titlekey);
