RZX SDK library

This commit is contained in:
fabio.olimpieri 2015-02-19 08:39:29 +00:00
parent 212dfeefbf
commit 265be3cb86
2 changed files with 950 additions and 0 deletions

815
src/rzx_lib/rzx.c Normal file
View File

@ -0,0 +1,815 @@
/*
R Z X
Input Recording Library for ZX Spectrum emulators
=================================================================
Library version: 0.12 - last updated: 04 August 2002
Created by Ramsoft ZX Spectrum demogroup
This is free software. Permission to use it in non-commercial and
commercial products is hereby granted at the terms of the present
licence:
** WORK IN PROGRESS ** (in short: FREE FOR ALL)
- A link to the official site of the RZX specifications and SDK
should be provided either in the program executable or into the
accompanying documentation.
- The present licence must be not be removed or altered.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rzx.h"
#ifndef _MSC_VER
#include <unistd.h>
#endif
#ifdef RZX_USE_COMPRESSION
#include <zlib.h>
#endif
/* RZX block IDs */
#define RZXBLK_CREATOR 0x10
#define RZXBLK_SESSION 0x11
#define RZXBLK_COMMENT 0x12
#define RZXBLK_SECURITY 0x20
#define RZXBLK_SNAP 0x30
#define RZXBLK_DATA 0x80
/* RZX internal status codes */
#define RZX_INIT 0x0001
#define RZX_IRB 0x0002
#define RZX_PROT 0x0004
#define RZX_PACK 0x0008
RZX_INFO rzx;
/* ======================================================================== */
#define LLO(x) (rzx_u8)(x&0xFF)
#define LHI(x) (rzx_u8)((x&0xFF00)>>8)
#define HLO(x) (rzx_u8)((x&0xFF0000)>>16)
#define HHI(x) (rzx_u8)((x&0xFF000000)>>24)
#define RZXBLKBUF 512
#define RZXINPUTMAX 32768
static int rzx_status=0;
static FILE *rzxfile=NULL;
static RZX_CALLBACK emul_handler=0;
static RZX_EMULINFO host_emul;
static RZX_EMULINFO file_emul;
static rzx_u8 *file_emul_data=0;
static RZX_SNAPINFO rzx_snap;
static RZX_IRBINFO rzx_irb;
#ifdef RZX_USE_COMPRESSION
/* Compression functions and data structures */
#define ZBUFLEN 16384
static z_stream zs;
static rzx_u8 *zbuf=0;
static int zmode=0;
static rzx_u32 packed_bytes=0;
int rzx_pwrite(rzx_u8 *buffer, int len)
{
int err;
zs.avail_in=len;
zs.next_in=buffer;
while(zs.avail_in>0)
{
if(zs.avail_out==0)
{
zs.next_out=zbuf;
err=fwrite(zbuf,1,ZBUFLEN,rzxfile);
packed_bytes+=err;
zs.avail_out=ZBUFLEN;
}
err=deflate(&zs,Z_NO_FLUSH);
}
return len-zs.avail_in;
}
int rzx_pread(rzx_u8 *buffer, int len)
{
zs.next_out=buffer;
zs.avail_out=len;
while(zs.avail_out>0)
{
if(zs.avail_in==0)
{
zs.avail_in=fread(zbuf,1,ZBUFLEN,rzxfile);
if(zs.avail_in==0) return 0;
zs.next_in=zbuf;
}
inflate(&zs,Z_NO_FLUSH);
}
return len-zs.avail_out;
}
int rzx_pclose()
{
int len, done=0,err;
zs.avail_in=0;
while(!zmode)
{
len=ZBUFLEN-zs.avail_out;
if(len>0)
{
err=fwrite(zbuf,1,len,rzxfile);
packed_bytes+=err;
zs.next_out=zbuf;
zs.avail_out=ZBUFLEN;
}
if(done) break;
err=deflate(&zs,Z_FINISH);
done=(zs.avail_out>0 || err==Z_STREAM_END);
}
if(zbuf!=0) {free(zbuf); zbuf=0;}
return 0;
}
int rzx_popen(long offset, char *mode)
{
int err;
zmode=((mode[0]|0x20)=='r')?1:0;
memset(&zs,0,sizeof(zs));
zbuf=(rzx_u8*)malloc(ZBUFLEN);
if(zmode)
{
zs.next_in=zbuf;
err=inflateInit2(&zs,15);
}
else
{
err=deflateInit2(&zs,9,Z_DEFLATED,15,9,Z_DEFAULT_STRATEGY);
zs.next_out=zbuf;
}
zs.avail_out=ZBUFLEN;
packed_bytes=0;
if(err!=Z_OK) return -1;
fseek(rzxfile,offset,SEEK_SET);
return 0;
}
#endif
typedef struct
{
rzx_u8 type;
rzx_u32 length;
long start;
rzx_u8 buff[RZXBLKBUF];
} RZX_BLKHDR;
static RZX_BLKHDR block;
static rzx_u32 rzx_framecount=0;
#ifdef RZX_DEBUG
rzx_u16 INmax=0;
rzx_u16 INcount=0;
rzx_u8 *inputbuffer=NULL;
#else
static rzx_u16 INmax=0;
static rzx_u16 INcount=0;
static rzx_u8 *inputbuffer=NULL;
#endif
static rzx_u16 INold=0;
static rzx_u8 *oldbuffer=NULL;
int rzx_scan()
{
long fpos=10;
memset(&file_emul,0,sizeof(RZX_EMULINFO));
do
{
fseek(rzxfile,fpos,SEEK_SET);
if(fread(block.buff,5,1,rzxfile)<1) break;
block.type=block.buff[0];
block.length=block.buff[1]+256*block.buff[2]+65536*block.buff[3]+16777216*block.buff[4];
/* printf("rzx_scan: block %02X len=%05i\n",block.type,block.length); */
if(block.length==0) return RZX_INVALID;
switch(block.type)
{
case RZXBLK_CREATOR:
/* read the info about the emulator which created this RZX */
fread(block.buff,24,1,rzxfile);
strncpy(file_emul.name,block.buff,19);
file_emul.ver_major=block.buff[20]+256*block.buff[21];
file_emul.ver_minor=block.buff[22]+256*block.buff[23];
/* check for custom data */
file_emul.length=block.length-29;
if(file_emul.length>0)
{
if(file_emul.data!=0) free(file_emul.data);
file_emul.data=(rzx_u8*)malloc(file_emul.length);
fread(file_emul.data,file_emul.length,1,rzxfile);
}
else file_emul.data=0;
break;
case RZXBLK_SECURITY:
/* signal that the RZX contains at least one encrypted block */
rzx.options|=RZX_PROTECTED;
rzx.options|=RZX_SEALED;
break;
case RZXBLK_DATA:
fread(block.buff,13,1,rzxfile);
default:
break;
}
fpos+=block.length;
} while(1);
//if(strlen(file_emul.name)>0)
fseek(rzxfile,10,SEEK_SET);
block.start=10;
block.length=0;
block.type=0;
return emul_handler(RZXMSG_CREATOR,&file_emul);
}
void rzx_close_irb()
{
long pos,len;
#ifdef RZX_USE_COMPRESSION
rzx_pclose();
#endif
/* suppress empty IRBs */
if(!rzx_framecount)
{
fseek(rzxfile,block.start,SEEK_SET);
rzx_status&=~RZX_IRB;
return;
}
/* update the IRB header */
pos=ftell(rzxfile);
len=pos-block.start;
block.buff[0]=LLO(len);
block.buff[1]=LHI(len);
block.buff[2]=HLO(len);
block.buff[3]=HHI(len);
block.buff[4]=LLO(rzx_framecount);
block.buff[5]=LHI(rzx_framecount);
block.buff[6]=HLO(rzx_framecount);
block.buff[7]=HHI(rzx_framecount);
fseek(rzxfile,block.start+1,SEEK_SET);
fwrite(block.buff,8,1,rzxfile);
fseek(rzxfile,pos,SEEK_SET);
block.start=pos;
/* signal that we have exited the IRB */
rzx_status&=~RZX_IRB;
}
int rzx_seek_irb()
{
int done=0;
long fpos;
FILE *snapfile;
while(!done)
{
if(fread(block.buff,5,1,rzxfile)<1) return RZX_FINISHED;
block.type=block.buff[0];
#ifndef RZX_BIG_ENDIAN
block.length=*((rzx_u32*)(&block.buff[1]));
#else
block.length=block.buff[1]+256*block.buff[2]+65536*block.buff[3]+16777216*block.buff[4];
#endif
if(block.length==0) return RZX_INVALID;
switch(block.type)
{
case RZXBLK_SNAP:
fread(block.buff,12,1,rzxfile);
strcpy(rzx_snap.filename,"");
rzx_snap.options=0x00;
if(!(block.buff[0]&0x01))
{
/* embedded snap */
#ifdef RZX_USE_COMPRESSION
if(block.buff[0]&0x02) rzx_snap.options|=RZX_COMPRESSED;
fpos=ftell(rzxfile);
rzx_popen(fpos,"rb");
#endif
strcpy(rzx_snap.filename,"rzxtemp.");
strcat(rzx_snap.filename,&block.buff[4]);
#ifndef RZX_BIG_ENDIAN
rzx_snap.length=*((rzx_u32*)&block.buff[8]);
#else
rzx_snap.length=block.buff[8]+256*block.buff[9]+65536*block.buff[10]+16777216*block.buff[11];
#endif
/* extract to tempfile */
snapfile=fopen(rzx_snap.filename,"wb");
/* if you can't, skip to next block */
if(snapfile==NULL) break;
/* ok */
rzx_snap.options|=RZX_EXTERNAL|RZX_REMOVE;
fpos=rzx_snap.length;
while(fpos>0)
{
done=(fpos>RZXBLKBUF)?RZXBLKBUF:fpos;
#ifdef RZX_USE_COMPRESSION
if(rzx_snap.options&RZX_COMPRESSED) rzx_pread(block.buff,done);
else fread(block.buff,done,1,rzxfile);
#else
fread(block.buff,done,1,rzxfile);
#endif
fwrite(block.buff,done,1,snapfile);
fpos-=done;
}
#ifdef RZX_USE_COMPRESSION
rzx_pclose();
#endif
fclose(snapfile);
done=0;
}
else
{
/* external snap, read descriptor */
fread(&block.buff[12],block.length-17,1,rzxfile);
strcpy(rzx_snap.filename,&block.buff[16]);
rzx_snap.options|=RZX_EXTERNAL;
}
/* tell the host emulator to load the snapshot */
emul_handler(RZXMSG_LOADSNAP,&rzx_snap);
if(rzx_snap.options&RZX_REMOVE) remove(rzx_snap.filename);
break;
case RZXBLK_DATA:
/* recording block found, initialize the values */
fread(block.buff,13,1,rzxfile);
#ifndef RZX_BIG_ENDIAN
rzx_framecount=*((rzx_u32*)&block.buff[0]);
#else
rzx_framecount=block.buff[0]+256*block.buff[1]+65536*block.buff[2]+16777216*block.buff[3];
#endif
rzx_status|=RZX_IRB;
if(block.buff[9]&0x01) rzx_status|=RZX_PROT;
else rzx_status&=~RZX_PROT;
if(block.buff[9]&0x02) rzx_status|=RZX_PACK;
else rzx_status&=~RZX_PACK;
#ifndef RZX_USE_COMPRESSION
if(rzx_status&RZX_PACK) return RZX_UNSUPPORTED;
#endif
rzx_irb.framecount=rzx_framecount;
rzx_irb.options=0;
if(rzx_status&RZX_PROT) rzx_irb.options|=RZX_PROTECTED;
if(rzx_status&RZX_PACK) rzx_irb.options|=RZX_COMPRESSED;
/* notify the emulator the new parameters */
emul_handler(RZXMSG_IRBNOTIFY,&rzx_irb);
#ifdef RZX_USE_COMPRESSION
if(rzx_status&RZX_PACK)
{
fpos=ftell(rzxfile);
rzx_popen(fpos,"rb");
}
#endif
/* all done */
return RZX_OK;
break;
case RZXBLK_SECURITY:
/* set the new security parameters */
break;
default:
break;
}
/* seek the next block in the file */
block.start+=block.length;
fseek(rzxfile,block.start,SEEK_SET);
}
return RZX_OK;
}
/* ======================================================================== */
int rzx_init(const RZX_EMULINFO *emul, const RZX_CALLBACK callback)
{
if((emul==0)||(callback==0)) return RZX_INVALID;
/* register the host emulator */
host_emul=(*emul);
emul_handler=callback;
rzx.mode=RZX_IDLE;
rzx.options=0;
memset(&file_emul,0,sizeof(RZX_EMULINFO));
rzx_status=RZX_INIT;
return RZX_OK;
}
int rzx_playback(const char *filename)
{
if(filename==0) return RZX_INVALID;
if(inputbuffer==NULL)
{
inputbuffer=(rzx_u8*)malloc(RZXINPUTMAX);
if(inputbuffer==NULL) return RZX_NOMEMORY;
memset(inputbuffer,0,RZXINPUTMAX);
}
if(oldbuffer==NULL)
{
oldbuffer=(rzx_u8*)malloc(RZXINPUTMAX);
if(oldbuffer==NULL) return RZX_NOMEMORY;
memset(oldbuffer,0,RZXINPUTMAX);
}
memset(block.buff,0,RZXBLKBUF);
rzx.mode=RZX_IDLE;
rzx_status&=~RZX_IRB;
rzxfile=fopen(filename,"rb");
if(rzxfile==NULL) return RZX_NOTFOUND;
memset(&block,0,16);
fread(block.buff,6,1,rzxfile);
if(memcmp(block.buff,"RZX!",4))
{
/* not an RZX file */
rzx_close();
return RZX_INVALID;
}
/* save info about the RZX */
strcpy(rzx.filename, filename);
rzx.ver_major=block.buff[4];
rzx.ver_minor=block.buff[5];
/* pre-scan the file to collect useful information and stats */
if(rzx_scan()!=RZX_OK)
{
rzx_close();
return RZX_INVALID;
}
/* ok, open the first IRB */
rzx.mode=RZX_PLAYBACK;
if(rzx_seek_irb()!=RZX_OK)
{
rzx_close();
return RZX_FINISHED;
}
INcount=0;
INold=0xFFFF;
return RZX_OK;
}
int rzx_record(const char *filename)
{
if(filename==0) return RZX_INVALID;
if(inputbuffer==NULL)
{
inputbuffer=(rzx_u8*)malloc(RZXINPUTMAX);
if(inputbuffer==NULL) return RZX_NOMEMORY;
memset(inputbuffer,0,RZXINPUTMAX);
}
if(oldbuffer==NULL)
{
oldbuffer=(rzx_u8*)malloc(RZXINPUTMAX);
if(oldbuffer==NULL) return RZX_NOMEMORY;
memset(oldbuffer,0,RZXINPUTMAX);
}
memset(block.buff,0,RZXBLKBUF);
rzx.mode=RZX_IDLE;
rzxfile=fopen(filename,"wb");
if(rzxfile==NULL)
{
rzx_close();
return RZX_NOTFOUND;
}
strcpy(rzx.filename,filename);
/* write the main RZX header */
memcpy(block.buff,"RZX!",4);
block.buff[4]=LHI(RZX_LIBRARY_VERSION);
block.buff[5]=LLO(RZX_LIBRARY_VERSION);
/* add the Creator Information Block */
block.buff[10]=RZXBLK_CREATOR;
block.length=29+host_emul.length;
block.buff[11]=LLO(block.length);
block.buff[12]=LHI(block.length);
block.buff[13]=HLO(block.length);
block.buff[14]=HHI(block.length);
memcpy(&block.buff[15],&host_emul,24);
#ifdef RZX_BIG_ENDIAN
block.buff[25]=LLO(host_emul.ver_major);
block.buff[26]=LHI(host_emul.ver_major);
block.buff[27]=LLO(host_emul.ver_minor);
block.buff[28]=LHI(host_emul.ver_minor);
#endif
fwrite(block.buff,10+block.length,1,rzxfile);
if(host_emul.length>0) fwrite(host_emul.data,host_emul.length,1,rzxfile);
block.start=10;
rzx.mode=RZX_RECORD;
rzx_status&=~RZX_IRB;
INcount=0;
INold=0xFFFF;
return RZX_OK;
}
void rzx_close(void)
{
switch(rzx.mode)
{
case RZX_PLAYBACK:
rzx_pclose();
break;
case RZX_RECORD:
/* is there an IRB to close? */
if(rzx_status&RZX_IRB) rzx_close_irb();
break;
default:
break;
}
if(rzxfile!=NULL)
{
fclose(rzxfile);
rzxfile=NULL;
}
rzx.mode=RZX_IDLE;
rzx_status=RZX_INIT;
if(file_emul_data!=0)
{
free(file_emul_data);
file_emul_data=0;
}
if(inputbuffer!=NULL)
{
free(inputbuffer);
inputbuffer=NULL;
}
if(oldbuffer!=NULL)
{
free(oldbuffer);
oldbuffer=NULL;
}
}
int rzx_update(rzx_u16 *icount)
{
rzx_u8 *xchgp;
long fpos;
switch(rzx.mode)
{
case RZX_PLAYBACK:
/* check if we are at the beginning */
if((rzx_status&RZX_IRB)&&(!rzx_framecount)) rzx_status&=~RZX_IRB;
/* need to seek another IRB? */
if(!(rzx_status&RZX_IRB))
{
if(rzx_seek_irb()!=RZX_OK)
{
/* no more IRBs, finished */
rzx_close();
return RZX_FINISHED;
}
}
/* fetch the instruction and IN counters */
INold=INmax;
#ifdef RZX_USE_COMPRESSION
if(rzx_status&RZX_PACK) rzx_pread(block.buff,4);
else fread(block.buff,4,1,rzxfile);
#else
fread(block.buff,4,1,rzxfile);
#endif
#ifndef RZX_BIG_ENDIAN
(*icount)=((rzx_u16*)&block.buff)[0];
INmax=((rzx_u16*)&block.buff)[1];
#else
(*icount)=block.buff[0]+256*block.buff[1];
INmax=block.buff[2]+256*block.buff[3];
#endif
/* update the input array */
#ifdef RZX_USE_COMPRESSION
if(INmax&&(INmax!=0xFFFF))
{
if(rzx_status&RZX_PACK) rzx_pread(inputbuffer,INmax);
else fread(inputbuffer,INmax,1,rzxfile);
}
else INmax=INold;
#else
if(INmax&&(INmax!=0xFFFF)) fread(inputbuffer,INmax,1,rzxfile);
else INmax=INold;
#endif
INcount=0;
rzx_framecount--;
break;
case RZX_RECORD:
/* close if parameters are not valid */
if((!icount)&&(rzx_status&RZX_IRB))
{
rzx_close_irb();
break;
}
/* need to start a new IRB? */
if(!(rzx_status&RZX_IRB))
{
/* ask the emulator about the params */
memset(&rzx_irb,0,sizeof(RZX_IRBINFO));
emul_handler(RZXMSG_IRBNOTIFY,&rzx_irb);
/* fill in the IRB header */
block.start=ftell(rzxfile);
memset(block.buff,0,18);
block.buff[0]=RZXBLK_DATA;
rzx_status&=~RZX_PACK;
#ifdef RZX_USE_COMPRESSION
if(rzx_irb.options&RZX_COMPRESSED)
{
block.buff[14]|=0x02;
rzx_status|=RZX_PACK;
}
#endif
#ifndef RZX_BIG_ENDIAN
*((rzx_u32*)&block.buff[10])=rzx_irb.tstates;
#else
block.buff[10]=LLO(rzx_irb.tstates);
block.buff[11]=LHI(rzx_irb.tstates);
block.buff[12]=HLO(rzx_irb.tstates);
block.buff[13]=HHI(rzx_irb.tstates);
#endif
fwrite(block.buff,18,1,rzxfile);
rzx_status|=RZX_IRB;
rzx_framecount=0;
#ifdef RZX_USE_COMPRESSION
if(rzx_status&RZX_PACK)
{
fpos=ftell(rzxfile);
rzx_popen(fpos,"wb");
}
#endif
}
/* prepare the frame data */
if(INold==INcount)
if(!memcmp(inputbuffer,oldbuffer,INcount)) INcount=0xFFFF;
#ifndef RZX_BIG_ENDIAN
((rzx_u16*)&block.buff)[0]=(*icount);
((rzx_u16*)&block.buff)[1]=INcount;
#else
block.buff[0]=LLO(*icount);
block.buff[1]=LHI(*icount);
block.buff[2]=LLO(INcount);
block.buff[3]=LHI(INcount);
#endif
#ifdef RZX_USE_COMPRESSION
if(rzx_status&RZX_PACK) rzx_pwrite(block.buff,4);
else fwrite(block.buff,4,1,rzxfile);
if(INcount&&(INcount!=0xFFFF))
{
if(rzx_status&RZX_PACK) rzx_pwrite(inputbuffer,INcount);
else fwrite(inputbuffer,INcount,1,rzxfile);
xchgp=inputbuffer;
inputbuffer=oldbuffer;
oldbuffer=xchgp;
INold=INcount;
}
#else
fwrite(block.buff,4,1,rzxfile);
if(INcount&&(INcount!=0xFFFF))
{
fwrite(inputbuffer,INcount,1,rzxfile);
xchgp=inputbuffer;
inputbuffer=oldbuffer;
oldbuffer=xchgp;
INold=INcount;
}
#endif
INcount=0;
rzx_framecount++;
break;
default:
return RZX_INVALID;
break;
}
return RZX_OK;
}
void rzx_store_input(rzx_u8 value)
{
if(INcount<RZXINPUTMAX) inputbuffer[INcount++]=value;
}
rzx_u8 rzx_get_input(void)
{
if(INcount>=INmax) return RZX_SYNCLOST;
return inputbuffer[INcount++];
}
int rzx_add_snapshot(const char *filename, const rzx_u32 flags)
{
FILE *snapfile;
long snaplen;
long fpos=0;
int blocklen=17,i;
if(filename==0) return RZX_INVALID;
snapfile=fopen(filename,"rb");
if(snapfile==NULL) return RZX_NOTFOUND;
if(rzx_status&RZX_IRB) rzx_close_irb();
/* find the length of the snapshot file */
fseek(snapfile,0,SEEK_END);
snaplen=ftell(snapfile);
fseek(snapfile,0,SEEK_SET);
memset(block.buff,0,RZXBLKBUF);
/* fill in the structures */
block.buff[0]=RZXBLK_SNAP;
if(flags&RZX_EXTERNAL)
{
/* leave the snapshot outside the RZX file */
blocklen+=4+strlen(filename)+1;
block.buff[5]=0x01;
}
else blocklen+=snaplen;
block.buff[1]=LLO(blocklen);
block.buff[2]=LHI(blocklen);
block.buff[3]=HLO(blocklen);
block.buff[4]=HHI(blocklen);
/* find the filename extension and store it into the header */
i=0; while((i<strlen(filename))&&(filename[i]!='.')) i++;
i++; if(i<strlen(filename)) strncpy(&block.buff[9],&filename[i],3);
block.buff[13]=LLO(snaplen);
block.buff[14]=LHI(snaplen);
block.buff[15]=HLO(snaplen);
block.buff[16]=HHI(snaplen);
/* write the snapshot or the descriptor */
if(flags&RZX_EXTERNAL)
{
/* fill in the external descriptor */
strcpy(&block.buff[21],filename);
fwrite(block.buff,blocklen,1,rzxfile);
}
else
{
/* embedded snapshot */
#ifdef RZX_USE_COMPRESSION
if(flags&RZX_COMPRESSED) block.buff[5]|=0x02;
#endif
fwrite(block.buff,17,1,rzxfile);
#ifdef RZX_USE_COMPRESSION
if(flags&RZX_COMPRESSED)
{
fpos=ftell(rzxfile);
rzx_popen(fpos,"wb");
}
#endif
/* copy the snapshot */
while(snaplen>0)
{
i=(snaplen>RZXBLKBUF)?RZXBLKBUF:snaplen;
fread(block.buff,i,1,snapfile);
#ifdef RZX_USE_COMPRESSION
if(flags&RZX_COMPRESSED) rzx_pwrite(block.buff,i);
else fwrite(block.buff,i,1,rzxfile);
#else
fwrite(block.buff,i,1,rzxfile);
#endif
snaplen-=i;
}
#ifdef RZX_USE_COMPRESSION
if(flags&RZX_COMPRESSED)
{
rzx_pclose();
i=ftell(rzxfile);
blocklen=17+i-fpos;
fseek(rzxfile,fpos-16,SEEK_SET);
block.buff[1]=LLO(blocklen);
block.buff[2]=LHI(blocklen);
block.buff[3]=HLO(blocklen);
block.buff[4]=HHI(blocklen);
fwrite(&block.buff[1],4,1,rzxfile);
fseek(rzxfile,i,SEEK_SET);
}
#endif
}
fclose(snapfile); snapfile=NULL;
/* remove the snapshot if requested */
if(flags&RZX_REMOVE) remove(filename);
return RZX_OK;
}
int rzx_add_comment(const char *text, const rzx_u32 flags)
{
if(rzx_status&RZX_IRB) rzx_close_irb();
/* to do! */
return RZX_OK;
}
#ifdef __cplusplus
}
#endif

135
src/rzx_lib/rzx.h Normal file
View File

@ -0,0 +1,135 @@
/*
R Z X
Input Recording Library for ZX Spectrum emulators
=================================================================
Library version: 0.12 - last updated: 4 August 2002
<license goes here>
*/
#ifndef RZX_LIBRARY_INCLUDE
#define RZX_LIBRARY_INCLUDE
#ifdef __cplusplus
extern "C" {
#endif
#define RZX_LIBRARY_VERSION 0x000C
#define RZX_LIBRARY_BUILD 31
/* ******************** Configuration options ******************** */
/* If needed, please edit the data types definitions as requested */
typedef unsigned char rzx_u8; /* must be unsigned 8-bit */
typedef unsigned short int rzx_u16; /* must be unsigned 16-bit */
typedef unsigned long int rzx_u32; /* must be unsigned 32-bit */
/* Uncomment the next line for Motorola-byte-order CPUs */
#define RZX_BIG_ENDIAN
/* Uncomment the next line to enable compression support */
#define RZX_USE_COMPRESSION
/* Uncomment this to enable some exports for debugging */
//#define RZX_DEBUG
/* *************************************************************** */
/* RZX error codes */
#define RZX_OK 0
#define RZX_NOTFOUND -1
#define RZX_INVALID -2
#define RZX_FINISHED -3
#define RZX_UNSUPPORTED -4
#define RZX_NOMEMORY -5
#define RZX_SYNCLOST -6
/* RZX operation mode */
#define RZX_IDLE 0
#define RZX_PLAYBACK 1
#define RZX_RECORD 2
/* RZX callback messages */
#define RZXMSG_CREATOR 1
#define RZXMSG_LOADSNAP 2
#define RZXMSG_IRBNOTIFY 3
/* RZX global flags */
#define RZX_PROTECTED 0x0001
#define RZX_SEALED 0x0002
#define RZX_REMOVE 0x0004
#define RZX_EXTERNAL 0x0008
#define RZX_COMPRESSED 0x0010
/* RZX data types */
typedef rzx_u32 (*RZX_CALLBACK)(int msg, void *param);
typedef struct
{
int mode;
char filename[260];
rzx_u8 ver_major;
rzx_u8 ver_minor;
rzx_u32 options;
} RZX_INFO;
typedef struct
{
char name[20];
rzx_u16 ver_major;
rzx_u16 ver_minor;
rzx_u8 *data;
rzx_u32 length;
rzx_u32 options;
} RZX_EMULINFO;
typedef struct
{
char filename[260];
rzx_u32 length;
rzx_u32 options;
} RZX_SNAPINFO;
typedef struct
{
rzx_u32 framecount;
rzx_u32 tstates;
rzx_u32 options;
} RZX_IRBINFO;
/* RZX public data structures */
extern RZX_INFO rzx;
/* RZX functions API */
int rzx_init(const RZX_EMULINFO *emul, const RZX_CALLBACK callback);
int rzx_record(const char *filename);
int rzx_playback(const char *filename);
void rzx_close(void);
int rzx_update(rzx_u16 *icount);
void rzx_store_input(rzx_u8 value);
rzx_u8 rzx_get_input(void);
int rzx_add_snapshot(const char *filename, const rzx_u32 flags);
int rzx_add_comment(const char *text, const rzx_u32 flags);
#ifdef RZX_DEBUG
extern rzx_u16 INcount;
extern rzx_u16 INmax;
extern rzx_u8 *inputbuffer;
#endif
#ifdef __cplusplus
}
#endif
#endif