/*	----------------------
 *	P C V D U M P	V 1.00
 *	----------------------
 *	Displays .PCV (PCVIC system snapshot) files & checks them for validity.
 *	Versions supported: 1.0
 *
 *	Copyright (C) 16 jan 1998 by B.W. van Schooten.
 *
 *	This program is freely useable, and freely modifiable as long as it is
 *  made clear that the original program has been modified.
 */



#define USAGE \
"\n"\
"Usage:   PCVDUMP  sourcefile  targetfile\n"\
"\n"\
"The source file must be a PCV (Vic-20) system snapshot.\n"\
"Header information will be printed to stdout. The contents of the memory\n"\
"space will be decompressed and written to the targetfile. Diagnostic\n"\
"messages are written to stderr.\n"\
"\n"


#include 
#include 



#define ERROR_NONE	  0
#define ERROR_EOF	  1
#define ERROR_TOOLONG 2


char *decompressmsg[] = {
	"Done.\n",
	"\nERROR: EOF found when data was expected.\n",
	"\nERROR: Data runs past expected end address.\n"
};


	int
decompress (long, FILE *, FILE *);

	/* Usage: error=decompress(size, inputfile, outputfile)
	 * Decompresses Byterun-compressed data from inputfile, writing the result
	 * to outputfile.
	 *
	 * Byterun is a simple compression method, based on replacing a row of
	 * bytes which have the same value by a count and a value byte. It is used
	 * for example in ILBM images.
	 *
	 * This routine also updates the checksum as the data is read.
	 */


	void
interpretrsb100 (FILE *,int);

	/* Shows information of register state block (rsb) as it is found in
	 * version 1.00. File pointer should point to start of rsb.
	 * File pointer is left undefined.
	 */


	void
addtochecksum (unsigned char);

	/* Calculates new checksum according to given byte. Checksum is stored in
	 * GLOBAL variable checksum.
	 */


	void
closedown (int);

	/* Closes any open files and exits with supplied exit code
	 */




const char *headerstr="PCVIC system snapshot";

#define HEADERSTRLEN 22
	/* length includes zero terminator */


long checksum;


FILE *inp, *outp;





	void
main(int argc,char **argv) {

	int n,m;				/* loop counters */
	unsigned char c1,c2;	/* temp. input characters */
	int rsbsize;			/* size field of register state block */
	long rsbstart;			/* file pointer to start of reg.state block */
	int decompresserror;	/* error returned by decompress procedure */
	unsigned int checksumread; /* value of checksum as read from file */
	int version;			/* PCV version, ex. 100=1.00, 110=1.10 */

	inp=NULL;
	outp=NULL;
	checksum=0x7ffb;

	fprintf(stderr,"PCVDUMP 1.00, (C) 16 jan 1998 by B.W. van Schooten\n");

	if (argc!=3) {
		fprintf(stderr,USAGE);
		closedown(EXIT_SUCCESS);
	}



	/*
	 * OPEN FILES
	 */

	inp=fopen(argv[1],"rb");
	if (!inp) {
		fprintf(stderr,"ERROR: Cannot open file %s.\n",argv[1]);
		closedown(EXIT_FAILURE);
	}

	outp=fopen(argv[2],"wb");
	if (!outp) {
		fprintf(stderr,"ERROR: Cannot write file %s.\n",argv[2]);
		closedown(EXIT_FAILURE);
	}


	/*
	 * MATCH HEADER
	 */

	n=0;
	while (1) {
		c1=(unsigned char)fgetc(inp);
		if (feof(inp)) {
			fprintf(stderr,"ERROR: EOF in header.\n");
			closedown(EXIT_FAILURE);
		}
		if (c1!=headerstr[n]) break;
		n++;
		if (n==HEADERSTRLEN) break;
	}

	if (n!=HEADERSTRLEN) {
		fprintf(stderr,"ERROR: Header does not match.\n");
		closedown(EXIT_FAILURE);
	}



	/*
	 * GET VERSION NUMBER
	 */

	c1=(unsigned char)fgetc(inp);
	addtochecksum(c1);
	c2=(unsigned char)fgetc(inp);
	addtochecksum(c2);

	if (feof(inp)) {
		fprintf(stderr,"ERROR: EOF in version number.\n");
		closedown(EXIT_FAILURE);
	}
	if (c1>=100) {
		fprintf(stderr,"ERROR: minor version out of valid range.\n");
		closedown(EXIT_FAILURE);
	}
	version=c1+100*c2;
	printf("SnapshotVersion=%d.%02d\n",(int)c2,(int)c1);


	/*
	 * GET SIZE OF REGISTER STATE BLOCK
	 */

	c1=(unsigned char)fgetc(inp);
	addtochecksum(c1);
	c2=(unsigned char)fgetc(inp);
	addtochecksum(c2);

	if (feof(inp)) {
		fprintf(stderr,"ERROR: EOF in register state block size.\n");
		closedown(EXIT_FAILURE);
	}
	rsbsize=(int)c1 + 256*(int)c2;
		printf("RSBSize=%u\n",rsbsize);
	if (rsbsize>32767) {
		fprintf(stderr,"ERROR: Register state block size more than 32767.\n");
		closedown(EXIT_FAILURE);
	}


	rsbstart = ftell(inp);


	/*
	 * CHECKSUM OVER REGISTER STATE BLOCK
	 */

	for (n=0; n128) {			 /* 129..255: duplicate byte n times */

			databyte=(unsigned char)fgetc(inp);
			addtochecksum(databyte);
			if (feof(inp)) return (ERROR_EOF);
			for (n=0; n<257-leaderbyte; n++) {
				fputc(databyte, outp);
				runningtotal++;
			}
		}
										 /* 128: ignore byte */

		if (runningtotal==bytes) return(ERROR_NONE);
		if (runningtotal>bytes)  return(ERROR_TOOLONG);

	}

}



	void
interpretrsb100(FILE *inp, int rsbsize) {
	unsigned char c1,c2;
	unsigned int value;

	if (rsbsize!=35) {
		fprintf(stderr,"WARNING: Register state block size should be 35.\n");
	}
	c1=(unsigned char)fgetc(inp);
	c2=(unsigned char)fgetc(inp);
	value=c1+256*c2;
	printf("X=$%04X\n",value);
	if (c2!=0) fprintf(stderr,"WARNING: Hi byte must be 0.\n");

	c1=(unsigned char)fgetc(inp);
	c2=(unsigned char)fgetc(inp);
	value=c1+256*c2;
	printf("Y=$%04X\n",value);
	if (c2!=0) fprintf(stderr,"WARNING: Hi byte must be 0.\n");

	c1=(unsigned char)fgetc(inp);
	c2=(unsigned char)fgetc(inp);
	value=c1+256*c2;
	printf("S=$%04X\n",value);
	if (c2!=1) fprintf(stderr,"WARNING: Hi byte must be 1.\n");

	c1=(unsigned char)fgetc(inp);
	printf("OLDSCANCOUNT=$%02X\n",c1);

	c1=(unsigned char)fgetc(inp);
	printf("AUXFLAGS=%02X\n",c1);
	if (c1 & 0xc3) fprintf(stderr,"WARNING: Bit 0,1,6,7 should all be 0.\n");
	if (!(c1 & 0x20)) fprintf(stderr,"WARNING: Bit 5 should always be 1.\n");

	c1=(unsigned char)fgetc(inp);
	c2=(unsigned char)fgetc(inp);
	value=c1+256*c2;
	printf("SCANLINE=$%02X\n",value);
	if (value>32767)
		fprintf(stderr,"WARNING: Value should not exceed 32767.\n");

	c1=(unsigned char)fgetc(inp);
	printf("IFR1=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("IER1=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("IFR2=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("IER2=$%02X\n",c1);

	c1=(unsigned char)fgetc(inp);
	printf("PERIP1B=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("LATCH1B=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("PERIP1A=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("LATCH1A=$%02X\n",c1);

	c1=(unsigned char)fgetc(inp);
	printf("PERIP2B=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("LATCH2B=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("PERIP2A=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("LATCH2A=$%02X\n",c1);

	c1=(unsigned char)fgetc(inp);
	printf("TIMERSTATUS=$%02X\n",c1);
	if (c1 & 0xf0) fprintf(stderr,"WARNING: high four bits should be zero.\n");

	c1=(unsigned char)fgetc(inp);
	printf("V1T2LATCHL=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("V2T2LATCHL=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("V1T2TIMERL=$%02X\n",c1);
	c1=(unsigned char)fgetc(inp);
	printf("V2T2TIMERL=$%02X\n",c1);

	c1=(unsigned char)fgetc(inp);
	printf("NMIFLANK=$%02X\n",c1);

	c1=(unsigned char)fgetc(inp);
	printf("MEMCONFIG=$%02X\n",c1);
	if (c1 & 0xd0)
		fprintf(stderr,"WARNING: Bit 7,6 and 3 should all be zero.\n");

	c1=(unsigned char)fgetc(inp);
	c2=(unsigned char)fgetc(inp);
	value=c1+256*c2;
	printf("PC=$%04X\n",value);

	c1=(unsigned char)fgetc(inp);
	c2=(unsigned char)fgetc(inp);
	printf("MAINFLAGS=$%02X(H) $%02X(L)\n",c2,c1);
	if (c2 & 0xbe)
		fprintf(stderr,
			"WARNING: Bit 7,5,4,3,2,1 of high byte should be zero.\n");

	c1=(unsigned char)fgetc(inp);
	printf("A=$%02X\n",c1);

	c1=(unsigned char)fgetc(inp);
	printf("SCANCOUNT=$%02X\n",c1);

}



	void
addtochecksum(unsigned char nextbyte) {
	long tmp1,tmp2, carryout;

	tmp1=checksum;
	tmp2=(long)nextbyte;

	/*
	 * ROL W[checksum],1
	 */
	tmp1 <<= 1;
	carryout = (tmp1 & 0x10000);
	if (carryout) tmp1 |= 1;
	tmp1 &= 0xffff;

	/*
	 * CBW
	 */
	if (tmp2 >= 128) tmp2 |= 0xff00;

	/*
	 * ADD [checksum],AX
	 */
	tmp1 += tmp2;
	tmp1 &= 0xffff;
	checksum=tmp1;
/*	  printf("C%x ",(int) checksum);*/
}



	void
closedown(int exitcode) {

	if (inp) fclose(inp);
	if (outp) fclose(outp);

	exit(exitcode);
}


    Source: geocities.com/timessquare/alley/3583

               ( geocities.com/timessquare/alley)                   ( geocities.com/timessquare)