Register FAQ Search Today's Posts Mark Forums Read
Go Back   JazzJackrabbit Community Forums » Open Forums » General Jazz Jackrabbit Talk

Get tileset and music file

Cataphract

JCF Member

Joined: Sep 2002

Posts: 24

Cataphract is doing well so far

Feb 13, 2007, 08:51 PM
Cataphract is offline
Reply With Quote
Question Get tileset and music file

Hey, has anyone done the reverse engineering and found out how to read the level files and retrieve the filename of the tileset and the music file? And, while we are at it, the next level
It would be a lot helpful to write some code to read this and figure out missing dependencies in one's level collection.

Thanks.
Grytolle

JCF Member

Joined: Sep 2004

Posts: 4,126

Grytolle is a forum legendGrytolle is a forum legendGrytolle is a forum legend

Feb 13, 2007, 09:04 PM
Grytolle is offline
Reply With Quote
That's no doubt been done
__________________
<center></center>
Violet CLM

JCF Éminence Grise

Joined: Mar 2001

Posts: 11,090

Violet CLM has disabled reputation

Feb 13, 2007, 09:55 PM
Violet CLM is offline
Reply With Quote
Totally on the front page.
__________________
Neobeo

JCF Member

Joined: Sep 2002

Posts: 409

Neobeo is an asset to this forumNeobeo is an asset to this forum

Feb 14, 2007, 05:27 AM
Neobeo is offline
Reply With Quote
Whatever has been said. In addition, if you program in C++, I have created some (messy and uncommented) classes that deal with such files, which you might be interested in.
__________________
<TABLE border=1><TR><TD>Facts:
Jazz Sprite Dynamite (JSD)
Tileset Extractor
Neobeo's Firetruck

</TD><TD>Myths:
Jazz Creation Station Plus (JCS+) - 10%
Coming soon - a dedicated server! - 25%
Jazz Sprite Dynamite v2 (JSDv2) - 2%
Another generic single-player level - 0%
</TD></TR></TABLE>
Cataphract

JCF Member

Joined: Sep 2002

Posts: 24

Cataphract is doing well so far

Feb 14, 2007, 08:50 AM
Cataphract is offline
Reply With Quote
(-), I only asked how to extract a few strings, not a complete file specification
I'm only writing a mIRC script, but I guess that since I have to use zlib, I'll have to write a mIRC DLL in C/C++, so, yes, I'm interested in what you have.
Thank you
Dermo

JCF Member

Joined: Jun 2005

Posts: 1,743

Dermo should make better posts

Feb 14, 2007, 09:33 AM
Dermo is offline
Reply With Quote
IRC Client

Are you going to release this when you're done Cata?

(If not can u give it to just me? I won't give it out to anyone else )
__________________
Yes, I am, in fact, ALWAYS the one to blame for everything. And none of your are full of yourself. Good job.

Do you like Stijn? Take my poll!




Windows is not a virus. A virus is small and efficient...

Note to Stijn: how am i even getting away with this
Cataphract

JCF Member

Joined: Sep 2002

Posts: 24

Cataphract is doing well so far

Feb 14, 2007, 04:59 PM
Cataphract is offline
Reply With Quote
Unhappy

To Drmoo: it'll be part of version 4 of my add on.

I've followed you example, but I always find a mismatch between what you say to be the declared size of the output stream and the actual size of the output stream as reported by uncompress(). I'm using zlib 1.2.3

Code:
#include <stdio.h>
#include <stdlib.h>
#include "zlib/zlib.h"

#define err(str)	fwrite(str "\n", 1, strlen(str)+2, stderr)

int main(int argc, char **argv) {
  FILE *file;
  int compsize,uncompsize,actuncompsize; //assumed to be 32bit long
  int resuncomp; //to hold the result of uncompress
  char *inputstream,*outputstream;
  if (argc < 2) { err("Give the file as a second argument."); return 1; }
  
  if ((file = fopen(argv[1],"rb")) == NULL) { perror("Could not open the file for reading"); return 1; }
  
  if (fseek(file, (long int) 254, SEEK_SET) != 0) {
	perror("Error setting the position for reading");
	return 1;
  }
  
  if (fread(&compsize, 4, 1, file) == 0) {
	perror("Could not read the size of the input stream");
	return 1;
  };
  inputstream = malloc (compsize);
  if (inputstream == NULL) {
	perror("Could not allocate memory for the input stream");
	return 1;
  };
  
  if (fread(&uncompsize, 4, 1, file) == 0) {
	perror("Could not read the size of the output stream");
	return 1;
  }
  outputstream = malloc (uncompsize);
  
  if (inputstream == NULL) {
	perror("Could not allocate memory for the output stream");
	return 1;
  };
   
  if (fread(inputstream, 1, compsize, file) < compsize) {
	perror("Could not read the input stream");
	return 1;
  };
  if (fclose(file) != 0)  { perror("Error closing the file"); return 1; }
  
  actuncompsize = uncompsize;
  actuncompsize = 1000000; outputstream = realloc (outputstream,1000000); //testing purposes
  resuncomp = uncompress(outputstream, &actuncompsize, inputstream, compsize);
  printf("input size %i, actual output size %i, "
	"expected output size %i\n",compsize,actuncompsize,uncompsize);
  //if (resuncomp != Z_OK) { err("Error uncompressing the input stream."); return 1; }
  //if (uncompsize != actuncompsize) { perror("Output stream had an unexpected size."); return 1; }
  
  
  printf("Written: %u bytes\n",fwrite(outputstream, 1, actuncompsize, fopen("t:\\j\\out.txt","wb")));

  return 0;
}
examples:

battle 3 (the 1998 file):
input size 3264, actual output size 33517, expected output size 16814
Written: 33517 bytes

ab5btl11.j2l
input size 2039, actual output size 34029, expected output size 6810
Written: 34029 bytes

ab5btl12.j2l
input size 1389, actual output size 34029, expected output size 5452
Written: 34029 bytes

Actual output size for 1.24 files is usually 73069.

Last edited by Cataphract; Feb 14, 2007 at 05:12 PM.
Neobeo

JCF Member

Joined: Sep 2002

Posts: 409

Neobeo is an asset to this forumNeobeo is an asset to this forum

Feb 14, 2007, 06:41 PM
Neobeo is offline
Reply With Quote
There are 4 data streams, and the sizes you are reading from (offset 254) actually refer to the 4th one. What you want to read, or are reading, is the first data stream, so you need the sizes for that. I would suggest you read the first 262 bytes into a STRUCT of some sort, but if not you can always try the following amendments (marked in red):

Code:
if (fseek(file, (long int) 230, SEEK_SET) != 0) {
	perror("Error setting the position for reading");
	return 1;
  }
  
  if (fread(&compsize, 4, 1, file) == 0) {
	perror("Could not read the size of the input stream");
	return 1;
  };
  inputstream = malloc (compsize);
  if (inputstream == NULL) {
	perror("Could not allocate memory for the input stream");
	return 1;
  };
  
  if (fread(&uncompsize, 4, 1, file) == 0) {
	perror("Could not read the size of the output stream");
	return 1;
  }

fseek(file, 24, SEEK_CUR);
And I'll hopefully be releasing my classes soon, if I don't get lazy for some reason or another.
__________________
<TABLE border=1><TR><TD>Facts:
Jazz Sprite Dynamite (JSD)
Tileset Extractor
Neobeo's Firetruck

</TD><TD>Myths:
Jazz Creation Station Plus (JCS+) - 10%
Coming soon - a dedicated server! - 25%
Jazz Sprite Dynamite v2 (JSDv2) - 2%
Another generic single-player level - 0%
</TD></TR></TABLE>
Cataphract

JCF Member

Joined: Sep 2002

Posts: 24

Cataphract is doing well so far

Feb 15, 2007, 05:48 PM
Cataphract is offline
Reply With Quote
Somehow I got the idea the stream was immediately preceded by the sizes.

Anyhow, I've finished the program, now it's just a matter of rearranging it and compile as a dll to use with mIRC. Maybe then I'll start doing something more interesting with the level files.

I'm going to post the code for the completeness of this thread.
Thanks to those who replied.

j2linfo.h
Code:
typedef struct cstream {
	long 	compSize;
	long	uncompSize;
	char	*compData;
	char	*uncompData;
} cstream, *cstreamP;

int uncompressStream(cstreamP st);
cstreamP newStream(void);


typedef struct LEVLheader {
	char		magic[4];
	char		passwordHash[3];
	char		hideLevel;
	char		levelName[32];
	short		version;
	long		fileSize;
	long		CRC32;
	cstreamP	stream[4];
} LEVLheader, *LEVLheaderP;

LEVLheaderP newLEVLheader(void);
int populateLVLheader(LEVLheaderP head,FILE *f);

//debugging
void memdump(unsigned char* data,int interval);
j2linfo.c
Code:
#include <stdio.h>
#include <stdlib.h>
#include "zlib/zlib.h"

#include "j2linfo.h"

#define err(str)	fwrite(str "\n", 1, strlen(str)+2, stderr)

void *chkmal(void *ptr) {
	if (ptr == NULL) { err("Could not allocate memory"); exit(2); };
	return ptr;
}
void memdump(unsigned char* data,int interval) {
	int i = -1;
	while (++i < interval) {
	  printf(" %X ",(unsigned int) (*(data+i)));
	}
	printf("\n");
}

int uncompressStream(cstreamP st) {
	long ucs = st->uncompSize;
	long resuncomp; //to hold the result of uncompress

	if (st->compData == NULL) return 1;
	if (st->uncompData != NULL) free(st->uncompData);
	st->uncompData = malloc(st->uncompSize);
	if (st->uncompData == NULL) return 2;
	
	printf("About to call uncompress:\n"
	  "size of compressed data: %i\n"
	  "size of uncompressed data: %i\n\n",st->compSize,st->uncompSize
	);
	
	resuncomp = uncompress(st->uncompData, &ucs, st->compData, st->compSize);
	
	if (resuncomp != Z_OK)  return 3;
	if (ucs != st->uncompSize) return 4;
	
	return 0;
}
cstreamP newStream(void) {
	cstreamP		ret;
	ret = malloc(sizeof *ret);
	if (ret == NULL) return NULL;
	memset(ret,0,sizeof *ret);
	return ret;
}
LEVLheaderP newLEVLheader(void) {
	LEVLheaderP		ret;
	ret = malloc(sizeof *ret);	
	if (ret == NULL) return NULL;
	memset(ret,0,sizeof *ret);
	return ret;
}

int populateLVLheader(LEVLheaderP head,FILE *f) {
  if (fread(head->magic,4, 1, f) == 0) {
	perror("Could not read the magic string of the LEVL header");
	return 1;
  }
  if (fread(head->passwordHash,3, 1, f) == 0) {
	perror("Could not read the password hash string of the LEVL header");
	return 1;
  }
  if (fread(&head->hideLevel,1, 1, f) == 0) {
	perror("Could not read the hide level byte of the LEVL header");
	return 1;
  }
  if (fread(head->levelName,32, 1, f) == 0) {
	perror("Could not read the level name of the LEVL header");
	return 1;
  }
  if (fread(&head->version,2, 1, f) == 0) {
	perror("Could not read the version out of the LEVL header");
	return 1;
  }
  if (fread(&head->fileSize,4, 1, f) == 0) {
	perror("Could not read the file size out of the LEVL header");
	return 1;
  }
  if (fread(&head->CRC32,4, 1, f) == 0) {
	perror("Could not read the checksum of the LEVL header");
	return 1;
  }
  return 0;
}

int main(int argc, char **argv) {
  FILE *file;
  char *inputstream,*outputstream;
  LEVLheaderP head;
  int i;
  char outname[50] = "";
  char gendata[19+32*6];
  
  head = chkmal(newLEVLheader());
  
  if (argc < 2) { err("Give the file as a second argument."); return 1; }
  
  if ((file = fopen(argv[1],"rb")) == NULL) { perror("Could not open the file for reading"); return 1; }
  
  if (fseek(file, (long int) 180, SEEK_SET) != 0) {
	perror("Error setting the position for reading");
	return 1;
  }
  
  //Read header. I will not read into the struct as that is not portable
  if (populateLVLheader(head,file) != 0) return 1;
  
  if (memcmp(head->magic, "LEVL", 4) != 0) {
	err("This does not appear to be a valid Jazz2 level file.");
	return 1;
  }
  
  i = -1; while (i++ < 3) {
	head->stream[i] = newStream();
	
	if (head->stream[i] == NULL) exit(1);
	if (fread(&(head->stream[i]->compSize), sizeof(long), 1, file) == 0) {
		perror("Could not read the compressed size of a stream");
		return 1;
	}
	if (fread(&(head->stream[i]->uncompSize), sizeof(long), 1, file) == 0) {
		perror("Could not read the uncompressed size of a stream");
		return 1;
	}
  }
  
  i = -1; while (i++ < 3) {
    head->stream[i]->compData = chkmal(malloc(head->stream[i]->compSize));
    head->stream[i]->uncompData = chkmal(malloc(head->stream[i]->uncompSize));
	  
    if (fread(head->stream[i]->compData, 1, head->stream[i]->compSize, file) == 0) {
		perror("Could not read the compressed data some stream");
		return 1;
    }
	if (uncompressStream(head->stream[i]) != 0) {
		err("Error uncompressing stream.");
		return 1;
	};
  }
  
  if (fclose(file) != 0)  { perror("Error closing the file"); return 1; }
  
  i = -1; while (i++ < 3) {
    sprintf(outname,"t:\\j\\out%i.txt",i+1);
	
    printf(
	  "Written: %u bytes\n",
	  fwrite(head->stream[i]->uncompData,
	  1,
	  head->stream[i]->uncompSize,
	  fopen(outname,"wb"))
	);
  }
  
  if (head->stream[0]->uncompSize < 19+32*6) {
	err("Bad stream 1"); return 1;
  }
  else memcpy(gendata,head->stream[0]->uncompData,19+32*6);
  
  //make sure the strings are always null-terminated
  i = 0; while (i++ < 6) { *(gendata+19+32*i-1) = '\x00'; }

  printf(
	"\nLEVEL INFORMATION\n"
	"Level name: %s\n"
	"Tileset: %s\n"
	"Bonus Level: %s\n"
	"Next Level: %s\n"
	"SecretLevel: %s\n"
	"MusicFile: %s\n",
	gendata+19,gendata+19+32*1,gendata+19+32*2,
	gendata+19+32*3,gendata+19+32*4,gendata+19+32*5
  );
  
  return 0;
}
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On

Forum Jump

All times are GMT -8. The time now is 09:32 PM.