/*
	Ninja Library
	
	COPYRIGHT (C) SEGA ENTERPRISES,LTD.
*/

#include <njCommon.h>
#include <nuBinary.h>
#include <sg_gd.h>
#include <njDef.h>

/*******************************************************************/
/*                                                                 */
/*  Function Name   : nuOpenBinary 				                   */
/*                                                                 */
/*  Function        : Read File from GD & Create Work Buff.        */
/*                                                                 */
/*	Parameters      : const char *fname: binary file name		   */
/*                                                                 */
/*  Return Value    : Sint8* work: buffer address                  */
/*                                                                 */
/*  Explanation     :                                              */
/*                                                                 */
/*  Note                                                           */
/*                                                                 */
/*******************************************************************/
Sint8 *nuOpenBinary(const char *fname)
{
    GDFS fid;
    Sint32 sn;
    Sint8 *wbuff;
    
    
    /* ファイルのオープン失敗 */
    if((fid = gdFsOpen(fname, NULL)) == NULL){
    	return NULL;
    }
    
    /* ファイルのサイズを求める */
    if(gdFsGetFileSctSize(fid, &sn)!= TRUE){
	    gdFsClose(fid);
    	return NULL;
    }
    
    wbuff = (Sint8 *)syMalloc(sn*2048+8);
    if(wbuff == NULL){
	    gdFsClose(fid);
    	return NULL;
    }
    if(gdFsRead(fid, sn, wbuff) !=  GDD_ERR_OK ){
		syFree(wbuff);
	    gdFsClose(fid);
		return NULL;
	}
    gdFsClose(fid);
    
    return wbuff;
}

/*******************************************************************/
/*                                                                 */
/*  Function Name   : nuCloseBinary				                   */
/*                                                                 */
/*  Function        : Free Work Buff.        					   */
/*                                                                 */
/*	Parameters      : Sint8 *wbuff: work buffer address			   */
/*                                                                 */
/*  Return Value    : void						                   */
/*                                                                 */
/*  Explanation     :                                              */
/*                                                                 */
/*  Note                                                           */
/*                                                                 */
/*******************************************************************/
void nuCloseBinary(Sint8 *wbuff)
{
    syFree(wbuff);
}

/*******************************************************************/
/*                                                                 */
/*  Function Name   : nuSwapCNK					                   */
/*                                                                 */
/*  Function        : General Funtion for Read Binary CNK NJA.	   */
/*                                                                 */
/*	Parameters      : Uint32 cnk:read chunk						   */
/*                                                                 */
/*  Return Value    : Uint32					                   */
/*                                                                 */
/*  Explanation     :                                              */
/*                                                                 */
/*  Note                                                           */
/*                                                                 */
/*******************************************************************/
Uint32 nuSwapCNK(Uint32 cnk)
{
    Uint32 rv;
    rv = (cnk&0x000000ff)<<24|(cnk&0x0000ff00)<<8|(cnk&0x00ff0000)>>8|(cnk&0xff000000)>>24;
    return rv;
}

/*******************************************************************/
/*                                                                 */
/*  Function Name   : nuReadBinary				                   */
/*                                                                 */
/*  Function        : Read Binary CNK NJA from Work Buff.		   */
/*                                                                 */
/*	Parameters      : Sint8 *wbuff:work buffer					   */
/*                    Uint32 *fpos                                 */
/*                    Uint32 *ptype                                */
/*  Return Value    : void *					                   */
/*                                                                 */
/*  Explanation     :                                              */
/*                                                                 */
/*  Note                                                           */
/*                                                                 */
/*******************************************************************/
void *nuReadBinary(Sint8 *wbuff, Uint32 *fpos, Uint32 *ptype)
{
    Sint8 *current;
    Sint8 *tmp;
    Uint8 buf0, buf1, buf2, buf3;
    Uint32 *addr;
    Uint32 cnk, size;
    Uint32 offset,  offset_from_base = 0;


    current = &wbuff[*fpos];
    
    syMemCopy(&cnk, current, 4);
    current += 4;
    
    syMemCopy(&size, current, 4);
    current += 4;


    *fpos += 8;
    cnk = nuSwapCNK(cnk);
    switch(cnk){
        case iff_NJINFO:
            *ptype = iff_NJINFO;
            goto _allocate_data_area_;
        case iff_NJCM:
            *ptype = iff_NJCM;
            goto _allocate_data_area_;
        case iff_NJBM:
            *ptype = iff_NJBM;
            goto _allocate_data_area_;
        case iff_NJTL:
            *ptype = iff_NJTL;
            goto _allocate_data_area_;
        case iff_NJLI:
            *ptype = iff_NJLI;
            goto _allocate_data_area_;
        case iff_NJCA:
            *ptype = iff_NJCA;
            goto _allocate_data_area_;
        case iff_NMDM:
            *ptype = iff_NMDM;
            goto _allocate_data_area_;
        case iff_NLIM:
            *ptype = iff_NLIM;
            goto _allocate_data_area_;
        case iff_NCAM:
            *ptype = iff_NCAM;
            goto _allocate_data_area_;
        case iff_NSSM:
            *ptype = iff_NSSM;
        _allocate_data_area_:
            tmp = (Sint8 *)syMalloc(size);
            if(tmp == NULL)
            	return NULL;
            syMemCopy(tmp, current, size);
            current += size;
            *fpos += size;
            break;
        default:
            *ptype = '****';
            return NULL;
    }
    /*-- Add BaseAddr ---------------------------------------*/
    syMemCopy(&cnk, current, 4);
    current += 4;
    *fpos += 4;
    cnk = nuSwapCNK(cnk);
    if(cnk == 'POF0'){
        syMemCopy(&size, current, 4);
        current += 4;
        *fpos += 4;
        while(size > 0){
            syMemCopy(&buf0, current, 1);
            current += 1;
            *fpos += 1;
            size--;
            switch(buf0&NUD_POF_CHAR_MASK){
                case NUD_POF_TYPE_PAD:
                    break;
                case NUD_POF_TYPE_CHAR:
                    offset = (Uint32)(buf0&NUD_POF_DATA_MASK);
                    goto _ADD_BASE_ADDRESS_;
                case NUD_POF_TYPE_SHORT:
                    syMemCopy(&buf1, current, 1);
                    current += 1;
                    size--;
                    *fpos += 1;
                    offset = (Uint32)((buf0&NUD_POF_DATA_MASK)<<8|buf1);
                    goto _ADD_BASE_ADDRESS_;
                case NUD_POF_TYPE_LONG:
                    syMemCopy(&buf1, current, 1);
                    current += 1;
                    size--;
                    syMemCopy(&buf2, current, 1);
                    current += 1;
                    size--;
                    syMemCopy(&buf3, current, 1);
                    current += 1;
                    size--;
                    *fpos += 3;
                    offset = (Uint32)((buf0&NUD_POF_DATA_MASK)<<24|(buf1<<16)|(buf2<<8)|buf3);
                _ADD_BASE_ADDRESS_:
                    offset *= 4;
                    offset_from_base += offset;
                    addr = (Uint32 *)(tmp+offset_from_base);
                    if(*addr)
                        *addr += (Uint32)tmp;
                    break;
            }
        }
    }
    return (void*)tmp;
}


/*-------------------------------------------------------------*/
