/***************************************************************************
 * Copyright (C) 2011
 * by Dimok
 * Modifications by xFede
 * Wiiflowized and heavily improved by Miigotu
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any
 * damages arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any
 * purpose, including commercial applications, and to alter it and
 * redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you
 * must not claim that you wrote the original software. If you use
 * this software in a product, an acknowledgment in the product
 * documentation would be appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and
 * must not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 * distribution.
 ***************************************************************************/

#include <gctypes.h>
#include <malloc.h>
#include <cstdio>
#include <cstring>

#include "cios.hpp"
#include "utils.h"
#include "mem2.hpp"
#include "fs.h"

#define ARRAY_SIZE(a)		(sizeof a / sizeof a[0])

static u32 allowedBases[] = { 37, 38, 53, 55, 56, 57, 58 }; 
static u32 boot2version = 0;

bool cIOSInfo::neek2o(void)
{
	if(!boot2version)
		ES_GetBoot2Version(&boot2version);
	
	return boot2version > 4 ? true : false;
}

/* Check if the cIOS is a D2X. */
bool cIOSInfo::D2X(u8 ios, u8 *base)
{
	if(neek2o())
	{
		*base = (u8)IOS_GetVersion();
		return true;
	}		

	iosinfo_t *info = GetInfo(ios);
	if(!info)
		return false;
	*base = (u8)info->baseios;
	MEM2_free(info);
	return true;
}

/*
 * Reads the ios info struct from the .app file.
 * @return pointer to iosinfo_t on success else NULL. The user is responsible for freeing the buffer.
 */

iosinfo_t *cIOSInfo::GetInfo(u8 ios)
{
	u32 TMD_Length;
	if (ES_GetStoredTMDSize(TITLE_ID(1, ios), &TMD_Length) < 0) return NULL;

	signed_blob *TMD = (signed_blob*)MEM2_alloc(ALIGN32(TMD_Length));
	if (TMD == NULL)
		return NULL;

	if (ES_GetStoredTMD(TITLE_ID(1, ios), TMD, TMD_Length) < 0)
	{
		MEM2_free(TMD);
		return NULL;
	}

	char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
	sprintf(filepath, "/title/00000001/%08x/content/%08x.app", ios, *(u8 *)((u32)TMD+0x1E7));

	MEM2_free(TMD);

	u32 size = 0;
	u8 *buffer = ISFS_GetFile((u8 *)filepath, &size, sizeof(iosinfo_t));
	if(buffer == NULL || size == 0)
		return NULL;

	iosinfo_t *iosinfo = (iosinfo_t *)buffer;

	bool baseMatch = false;
	for(u8 i = 0; i < ARRAY_SIZE(allowedBases); i++)
		if(iosinfo->baseios == allowedBases[i])
		{
			baseMatch = true;
			break;
		}

	if(iosinfo->magicword != 0x1ee7c105					/* Magic Word */
		|| iosinfo->magicversion != 1					/* Magic Version */
		|| iosinfo->version < 6							/* Version */
		|| !baseMatch									/* Base */
		|| strncasecmp(iosinfo->name, "d2x", 3) != 0)	/* Name */
	{
		MEM2_free(buffer);
		return NULL;
	}

	return iosinfo;
}