On Sunday 29 August 2004 12:49, Alexandre Prokoudine wrote:
> As soon as you need testing/gdb/etc, you can count on me ;-)

Thanks!

I have started yesterday, but there are already some modest results. Attached 
is a test program that verifies if some file has a legal cakewalk format. It 
can be used within a script to verify many files in a batch process:

#!/bin/sh
DIR=${1:-"."}
find $DIR -iname '*.wrk' -print -exec caketest {} \;

You can also use it to dump the file contents, with more or less detail. It is 
not finished. There are a lot of chunk types that I can't identify now, and 
appear as "unknown type". I have files identified as version 2.0 and 3.0, I 
would like to hear about more versions.

$ caketest -h
Usage: caketest [options] filename

Available options:
  -h,--help                  this help
  -V,--version               show version
  -v,--verbose               show chunk types
  -d,--dump                  dump chunk types and payload


Please let me know if it works for you.

Regards,
Pedro
/*
* Cakewalk (WRK) file format test
*
* Copyright (c) 2004 Pedro Lopez-Cabanillas  All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>

FILE *file;
unsigned char *buffer;
char *HEADER = "CAKEWALK";
int verbose = 0;
int dump = 0;
int vma, vme;

#define ERR_FILE	"Error reading file\n"
#define ERR_CORRUPTED	"Error: corrupted file\n"
#define ERR_FORMAT	"Error: bad file format\n"

#define	VERSION_STR	"0.2"
#define BUFSIZE 	0x1024

#define TRACK_CHUNK	1
#define STREAM_CHUNK	2
#define VARS_CHUNK	3
#define TEMPO_CHUNK	4
#define METER_CHUNK	5
#define SYSEX_CHUNK	6
#define MEMRGN_CHUNK	7	
#define COMMENTS_CHUNK	8
#define TRKOFFS_CHUNK	9
#define TIMEBASE_CHUNK	10 // if present should be the first chunk in the file.
#define TIMEFMT_CHUNK	11
#define TRKREPS_CHUNK	12
#define TRKPATCH_CHUNK	14
#define THRU_CHUNK	16
#define	LYRICS_CHUNK	18
#define VARIABLE_CHUNK	26
#define END_CHUNK	255

static const struct chunks_struct {
        const int identifier;
        const char* description;
} chunks[] = {
	{TRACK_CHUNK,	"Track"},
        {STREAM_CHUNK,	"Stream"},
        {VARS_CHUNK,	"Global Variables"},
        {TEMPO_CHUNK,	"Tempo List"},
        {METER_CHUNK,	"Meter Map"},
        {SYSEX_CHUNK,	"Sysex"},
        {MEMRGN_CHUNK,	"Memory Region"},
        {COMMENTS_CHUNK,"Comments"},
        {TRKOFFS_CHUNK,	"Track Offsets"},
        {TIMEBASE_CHUNK,"Timebase"},
        {TIMEFMT_CHUNK,	"Time Format"},
        {TRKREPS_CHUNK,	"Track Repetitions"},
        {TRKPATCH_CHUNK,"Track Patch"},
        {THRU_CHUNK,	"Thru Expanded Parameters"},
        {LYRICS_CHUNK,	"Lyrics"},
        {VARIABLE_CHUNK,"Variable Record"},
        {END_CHUNK,	"END"}
};
#define CHUNKS_COUNT (sizeof(chunks) / sizeof(chunks[0]))

void failure(char *message) {
	fprintf(stderr, message);
	exit(EXIT_FAILURE);
}	

int readchar() {
	int rc = fgetc(file);
	if (rc < 0)
		failure(ERR_CORRUPTED);
	return rc;
}

void readFileVersion()
{
	readchar();
	vme = readchar();
	vma = readchar();
}

void hexdump(void *data, int size) {
    char *buf = data;
    char out_left[160], out_right[160], line[160];
    char token[160];
    unsigned char c;
    int i,j,row;

    if (size<0)
	return;
    row = 0;
    while (row<size) {
	memset(out_left, ' ', 80);
	memset(out_right, ' ', 80);
	for (i=j=0; i<16; i++) {
	    if (row+i<size) {
		c = *buf++;

		sprintf(token, "%02x", c);
		memcpy(out_left + j, token, 2);
		j+=2; 
		if ((i+1) % 4 == 0)
		    j++;
	
		if (c>31 && c<127)
		    out_right[i] = c;
		else
		    out_right[i] = '.';
	    }
	}

	sprintf(line, "  %08x                                                                     \n", row);
	memcpy(line+16, out_left, 40);
	memcpy(line+56, out_right, 16);
	printf("%s", line);
	row+=16;
    }
    printf("\n");
}

void readBuffer(long count, int printit)
{
	if (count == 0) {
		return;
	} else if (count > BUFSIZE) {
		if (fseek(file, count, SEEK_CUR) < 0)
			failure(ERR_CORRUPTED);
	} else {
		if (fread(buffer, count, 1, file) != 1)
			failure(ERR_CORRUPTED);
		if (printit)
			hexdump(buffer, count);
	}
}

void printChunk(int id) {
	int i;
	for (i=0; i<CHUNKS_COUNT; ++i) {
		if (chunks[i].identifier == id) {
			printf("\t%3i:\t%s\n", id, chunks[i].description);
			return;
		}
	}	
	printf("\t%3i:\tUnknown\n", id);
}

int readChunk()
{
	int ck_len;
	int ck = readchar();
	if (verbose) printChunk(ck);
	if (ck != END_CHUNK) {
		if (fread(&ck_len, sizeof(ck_len), 1, file) != 1)
			failure(ERR_CORRUPTED);
		readBuffer(ck_len, dump);
	}
	return ck;
}

void cakeTest(char *fileName)
{
	int ck_id;
	file = fopen(fileName, "r");
	if (!file) {
		failure(ERR_FILE);
	} else {
		readBuffer(strlen(HEADER), 0);
		if (strcmp(buffer, HEADER)) {
			failure(ERR_FORMAT);
		} else {
			readFileVersion();
			if (verbose) {
				printf("file version: %d.%d\n", vma, vme);
				printf("file chunks:\n");
			}
			do {
				ck_id = readChunk();
			} while (ck_id != END_CHUNK);
			fgetc(file);
			if (!feof(file)) {
				failure(ERR_CORRUPTED);
			}
		}
		fclose(file);
	}
}

static void help(const char *progname)
{
        fprintf(stderr, "Usage: %s [options] filename\n"
                "\nAvailable options:\n"
                "  -h,--help                  this help\n"
                "  -V,--version               show version\n"
                "  -v,--verbose               show chunk types\n"
                "  -d,--dump                  dump chunk types and payload\n",
                progname);
}

static void version(const char *progname)
{
        fprintf(stderr, "%s version " VERSION_STR "\n", progname);
}


int main(int argc, char *argv[])
{
	int c;
        static char short_options[] = "hVvd";
        static struct option long_options[] = {
                {"help", 0, NULL, 'h'},
                {"version", 0, NULL, 'V'},
                {"verbose", 0, NULL, 'v'},
                {"dump", 0, NULL, 'd'},
                { }
        };
		
        while ((c = getopt_long(argc, argv, short_options,
                                long_options, NULL)) != -1) {
                switch (c) {
                case 'h':
                        help(argv[0]);
                        return 0;
                case 'V':
                        version(argv[0]);
                        return 0;
                case 'v':
                	verbose = 1;
                	break;
                case 'd':
                	verbose = 1;
                	dump = 1;
                	break;
                }
        }
        
	buffer = malloc(BUFSIZE);
	cakeTest(argv[optind]);
	free(buffer);
	return EXIT_SUCCESS;
}

Reply via email to