📄 libsnss.c
字号:
/**************************************************************************/
/*
libsnss.c
(C) 2000 The SNSS Group
See README.TXT file for license and terms of use.
$Id: libsnss.c,v 1.1.1.1 2003/01/09 13:37:05 Rick Exp $
*/
/**************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libsnss.h"
/**************************************************************************/
/* This section deals with endian-specific code. */
/**************************************************************************/
static unsigned int
swap32 (unsigned int source)
{
#ifdef USE_LITTLE_ENDIAN
char buffer[4];
buffer[0] = ((char *) &source)[3];
buffer[1] = ((char *) &source)[2];
buffer[2] = ((char *) &source)[1];
buffer[3] = ((char *) &source)[0];
return *((unsigned int *) buffer);
#else /* !USE_LITTLE_ENDIAN */
return source;
#endif /* !USE_LITTLE_ENDIAN */
}
static unsigned short
swap16 (unsigned short source)
{
#ifdef USE_LITTLE_ENDIAN
char buffer[2];
buffer[0] = ((char *) &source)[1];
buffer[1] = ((char *) &source)[0];
return *((unsigned short *) buffer);
#else /* !USE_LITTLE_ENDIAN */
return source;
#endif /* !USE_LITTLE_ENDIAN */
}
/**************************************************************************/
/* support functions */
/**************************************************************************/
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
/**************************************************************************/
static SNSS_RETURN_CODE
SNSS_ReadBlockHeader (SnssBlockHeader *header, SNSS_FILE *snssFile)
{
char headerBytes[12];
if (fread (headerBytes, 12, 1, snssFile->fp) != 1)
{
return SNSS_READ_FAILED;
}
strncpy (header->tag, &headerBytes[0], TAG_LENGTH);
header->tag[4] = '\0';
header->blockVersion = *((unsigned int *) &headerBytes[4]);
header->blockVersion = swap32 (header->blockVersion);
header->blockLength = *((unsigned int *) &headerBytes[8]);
header->blockLength = swap32 (header->blockLength);
return SNSS_OK;
}
/**************************************************************************/
static SNSS_RETURN_CODE
SNSS_WriteBlockHeader (SnssBlockHeader *header, SNSS_FILE *snssFile)
{
char headerBytes[12];
unsigned int tempInt;
strncpy (&headerBytes[0], header->tag, TAG_LENGTH);
tempInt = swap32 (header->blockVersion);
headerBytes[4] = ((char *) &tempInt)[0];
headerBytes[5] = ((char *) &tempInt)[1];
headerBytes[6] = ((char *) &tempInt)[2];
headerBytes[7] = ((char *) &tempInt)[3];
tempInt = swap32 (header->blockLength);
headerBytes[8] = ((char *) &tempInt)[0];
headerBytes[9] = ((char *) &tempInt)[1];
headerBytes[10] = ((char *) &tempInt)[2];
headerBytes[11] = ((char *) &tempInt)[3];
if (fwrite (headerBytes, 12, 1, snssFile->fp) != 1)
{
return SNSS_WRITE_FAILED;
}
return SNSS_OK;
}
/**************************************************************************/
const char *
SNSS_GetErrorString (SNSS_RETURN_CODE code)
{
switch (code)
{
case SNSS_OK:
return "no error";
case SNSS_BAD_FILE_TAG:
return "not an SNSS file";
case SNSS_OPEN_FAILED:
return "could not open SNSS file";
case SNSS_CLOSE_FAILED:
return "could not close SNSS file";
case SNSS_READ_FAILED:
return "could not read from SNSS file";
case SNSS_WRITE_FAILED:
return "could not write to SNSS file";
case SNSS_OUT_OF_MEMORY:
return "out of memory";
case SNSS_UNSUPPORTED_BLOCK:
return "unsupported block type";
default:
return "unknown error";
}
}
/**************************************************************************/
/* functions for reading and writing SNSS file headers */
/**************************************************************************/
static SNSS_RETURN_CODE
SNSS_ReadFileHeader (SNSS_FILE *snssFile)
{
if (fread (snssFile->headerBlock.tag, 4, 1, snssFile->fp) != 1)
{
return SNSS_READ_FAILED;
}
if (0 != strncmp(snssFile->headerBlock.tag, "SNSS", 4))
{
return SNSS_BAD_FILE_TAG;
}
snssFile->headerBlock.tag[4] = '\0';
if (fread (&snssFile->headerBlock.numberOfBlocks, sizeof (unsigned int), 1, snssFile->fp) != 1)
{
return SNSS_READ_FAILED;
}
snssFile->headerBlock.numberOfBlocks = swap32 (snssFile->headerBlock.numberOfBlocks);
return SNSS_OK;
}
/**************************************************************************/
static SNSS_RETURN_CODE
SNSS_WriteFileHeader (SNSS_FILE *snssFile)
{
unsigned int tempInt;
char writeBuffer[8];
/* always place the SNSS tag in this field */
strncpy (&writeBuffer[0], "SNSS", 4);
tempInt = swap32 (snssFile->headerBlock.numberOfBlocks);
writeBuffer[4] = ((char *) &tempInt)[0];
writeBuffer[5] = ((char *) &tempInt)[1];
writeBuffer[6] = ((char *) &tempInt)[2];
writeBuffer[7] = ((char *) &tempInt)[3];
if (fwrite (writeBuffer, 8, 1, snssFile->fp) != 1)
{
return SNSS_WRITE_FAILED;
}
return SNSS_OK;
}
/**************************************************************************/
/* general file manipulation functions */
/**************************************************************************/
SNSS_RETURN_CODE
SNSS_OpenFile (SNSS_FILE **snssFile, const char *filename, SNSS_OPEN_MODE mode)
{
*snssFile = malloc(sizeof(SNSS_FILE));
if (NULL == *snssFile)
{
return SNSS_OUT_OF_MEMORY;
}
(*snssFile)->mode = mode;
if (SNSS_OPEN_READ == mode)
(*snssFile)->fp = fopen (filename, "rb");
else
{
(*snssFile)->fp = fopen (filename, "wb");
(*snssFile)->headerBlock.numberOfBlocks = 0;
}
if (NULL == (*snssFile)->fp)
{
free(*snssFile);
*snssFile = NULL;
return SNSS_OPEN_FAILED;
}
if (SNSS_OPEN_READ == mode)
return SNSS_ReadFileHeader(*snssFile);
else
return SNSS_WriteFileHeader(*snssFile);
}
/**************************************************************************/
SNSS_RETURN_CODE
SNSS_CloseFile (SNSS_FILE **snssFile)
{
int prevLoc;
SNSS_RETURN_CODE code;
/* file was never open, so this should indicate success- kinda. */
if (NULL == *snssFile)
{
return SNSS_OK;
}
if (SNSS_OPEN_WRITE == (*snssFile)->mode)
{
prevLoc = ftell((*snssFile)->fp);
fseek((*snssFile)->fp, 0, SEEK_SET);
/* write the header again to get block count correct */
if (SNSS_OK != (code = SNSS_WriteFileHeader(*snssFile)))
return SNSS_CLOSE_FAILED;
fseek((*snssFile)->fp, prevLoc, SEEK_SET);
}
if (fclose ((*snssFile)->fp) != 0)
{
return SNSS_CLOSE_FAILED;
}
free(*snssFile);
*snssFile = NULL;
return SNSS_OK;
}
/**************************************************************************/
SNSS_RETURN_CODE
SNSS_GetNextBlockType (SNSS_BLOCK_TYPE *blockType, SNSS_FILE *snssFile)
{
char tagBuffer[TAG_LENGTH + 1];
if (fread (tagBuffer, TAG_LENGTH, 1, snssFile->fp) != 1)
{
return SNSS_READ_FAILED;
}
tagBuffer[TAG_LENGTH] = '\0';
/* reset the file pointer to the start of the block */
if (fseek (snssFile->fp, -TAG_LENGTH, SEEK_CUR) != 0)
{
return SNSS_READ_FAILED;
}
/* figure out which type of block it is */
if (strcmp (tagBuffer, "BASR") == 0)
{
*blockType = SNSS_BASR;
return SNSS_OK;
}
else if (strcmp (tagBuffer, "VRAM") == 0)
{
*blockType = SNSS_VRAM;
return SNSS_OK;
}
else if (strcmp (tagBuffer, "SRAM") == 0)
{
*blockType = SNSS_SRAM;
return SNSS_OK;
}
else if (strcmp (tagBuffer, "MPRD") == 0)
{
*blockType = SNSS_MPRD;
return SNSS_OK;
}
else if (strcmp (tagBuffer, "CNTR") == 0)
{
*blockType = SNSS_CNTR;
return SNSS_OK;
}
else if (strcmp (tagBuffer, "SOUN") == 0)
{
*blockType = SNSS_SOUN;
return SNSS_OK;
}
else
{
*blockType = SNSS_UNKNOWN_BLOCK;
return SNSS_OK;
}
}
/**************************************************************************/
SNSS_RETURN_CODE
SNSS_SkipNextBlock (SNSS_FILE *snssFile)
{
unsigned int blockLength;
/* skip the block's tag and version */
if (fseek (snssFile->fp, TAG_LENGTH + sizeof (unsigned int), SEEK_CUR) != 0)
{
return SNSS_READ_FAILED;
}
/* get the block data length */
if (fread (&blockLength, sizeof (unsigned int), 1, snssFile->fp) != 1)
{
return SNSS_READ_FAILED;
}
blockLength = swap32 (blockLength);
/* skip over the block data */
if (fseek (snssFile->fp, blockLength, SEEK_CUR) != 0)
{
return SNSS_READ_FAILED;
}
return SNSS_OK;
}
/**************************************************************************/
/* functions for reading and writing base register blocks */
/**************************************************************************/
static SNSS_RETURN_CODE
SNSS_ReadBaseBlock (SNSS_FILE *snssFile)
{
char blockBytes[BASE_BLOCK_LENGTH];
SnssBlockHeader header;
if (SNSS_ReadBlockHeader (&header, snssFile) != SNSS_OK)
{
return SNSS_READ_FAILED;
}
if (fread (blockBytes, MIN (header.blockLength, BASE_BLOCK_LENGTH), 1, snssFile->fp) != 1)
{
return SNSS_READ_FAILED;
}
snssFile->baseBlock.regA = blockBytes[0x0];
snssFile->baseBlock.regX = blockBytes[0x1];
snssFile->baseBlock.regY = blockBytes[0x2];
snssFile->baseBlock.regFlags = blockBytes[0x3];
snssFile->baseBlock.regStack = blockBytes[0x4];
snssFile->baseBlock.regPc = *((unsigned short *) &blockBytes[0x5]);
snssFile->baseBlock.regPc = swap16 (snssFile->baseBlock.regPc);
snssFile->baseBlock.reg2000 = blockBytes[0x7];
snssFile->baseBlock.reg2001 = blockBytes[0x8];
memcpy (&snssFile->baseBlock.cpuRam, &blockBytes[0x9], 0x800);
memcpy (&snssFile->baseBlock.spriteRam, &blockBytes[0x809], 0x100);
memcpy (&snssFile->baseBlock.ppuRam, &blockBytes[0x909], 0x1000);
memcpy (&snssFile->baseBlock.palette, &blockBytes[0x1909], 0x20);
memcpy (&snssFile->baseBlock.mirrorState, &blockBytes[0x1929], 0x4);
snssFile->baseBlock.vramAddress = *((unsigned short *) &blockBytes[0x192D]);
snssFile->baseBlock.vramAddress = swap16 (snssFile->baseBlock.vramAddress);
snssFile->baseBlock.spriteRamAddress = blockBytes[0x192F];
snssFile->baseBlock.tileXOffset = blockBytes[0x1930];
return SNSS_OK;
}
/**************************************************************************/
static SNSS_RETURN_CODE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -