The data files used by Beats (BULK.BAR) are in a proprietary format that contain a number of zlib deflated files topped with a moderate header (not the simplest, but nothing like you'll see later). I first discovered the zlib'd files when I used the OS X program File Juicer in an attempt to find files embedded within the BAR. Jaeder Naub is the closest equivalent I could find for Windows, but it has troubles extracting the zlib'd files properly.
Before I start posting code it should be noted that any values posted are from the BULK.BAR file of JAM_0002. BAR files vary greatly across types and even within the same type, but the basic structure remains the same.
The header is as follows:
x00| E1 17 EF AD 00 00 00 01 Magic NumberWith this header info, one should have no problem (except maybe time) extracting the files for inflation.
x10| 05 00 00 00 Number of files in the BAR
This is important, as the size of the header depends on this.
Also the value is byte flipped or little endian. You'll see this A LOT.
From here on out there will be 16 byte chunks for each file. The order of these chunks isn't important.
I'll use the first chunk as an example:
x14| 5F AE 8F D1 Unknown related to zlib
I want to say it's a CRC, but I can't recreate it and all the JAM_000x BARs have the same value here. If it is a CRC, Beats semi-ignores it anyways; zeroing it causes failure, but leaving it despite a huge change in the file works OK.
x18| 00 00 00 00 Offset (minus header) of zlib
x1C| 03 01 00 00 Inflated size of zlib (259)*
x20| C4 00 00 00 Deflated size of zlib (196)*
And repeat for each file.
After each file is represented in the header, the first file appears , beginning with 78 DA.
I'm focusing on the Jamming files, but feel free to explore others. The visualizers contain a lot of XML and difficult GIM/MIG images. Themes have a bit of XML and PSMF background videos. I haven't really looked at the CLGs (songs) as there's already a method to add your own music. If you decrypt EBOOT.BIN you'll find an embedded BAR file. Be warned: there are A LOT of files in there, though this is where you'll find Java .class files; sounds, UI elements, and fonts; and even more XML.
*Inflating and deflating the files can be a pain as there are few tools that use the same algorithm. zlibc for Windows does both perfectly. If one was so inclined, it should be trivial to make a tool in Python for other platforms.
4 comments:
#include <zlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
unsigned int in_magic, in_filecount, *in_crcs, *in_offsets, *in_inflated, *in_deflated, in_length;
unsigned char *buf_inflated, *buf_deflated;
int i;
if(argc < 2) return !(printf("Note: You can run this from the command prompt.\nIn Windows, you can just drag a .bar file to the .exe, and that'll work too.\nUsage: %s <bar file>\n", argv[0])+(strncmp(argv[0], "/cygdrive", 9) ? 0 : getc(stdin)))-1;
FILE *in, *out;
in = fopen(argv[1], "r");
if(!in)
return !(printf("BAR file %s not found.\n", argv[1]))-1;
fread(&in_magic, sizeof(unsigned int), 1, in);
if(in_magic != 0xADEF17E1)
return !(printf("Invalid BAR file.\n", argv[1]))-1;
fseek(in, 0x10, SEEK_SET);
fread(&in_filecount, sizeof(unsigned int), 1, in);
in_crcs = (unsigned int *)malloc(in_filecount*sizeof(unsigned int));
in_offsets = (unsigned int *)malloc(in_filecount*sizeof(unsigned int));
in_inflated = (unsigned int *)malloc(in_filecount*sizeof(unsigned int));
in_deflated = (unsigned int *)malloc(in_filecount*sizeof(unsigned int));
printf("%i files found\n", in_filecount);
for(i=0; i < in_filecount; i++)
{
fseek(in, 0x14+0x10*i, SEEK_SET);
fread(&(in_crcs[i]), sizeof(unsigned int), 1, in);
fread(&(in_offsets[i]), sizeof(unsigned int), 1, in);
fread(&(in_inflated[i]), sizeof(unsigned int), 1, in);
fread(&(in_deflated[i]), sizeof(unsigned int), 1, in);
printf("File %i:\nCRC = 0x%08X\nOffset = header+0x%04X\ninflated size = %i\ndeflated size = %i\n",i,in_crcs[i],in_offsets[i],in_inflated[i],in_deflated[i]);
buf_inflated = (unsigned char*)malloc(in_inflated[i]*sizeof(unsigned char));
buf_deflated = (unsigned char*)malloc(in_deflated[i]*sizeof(unsigned char));
fseek(in, in_offsets[i], SEEK_SET);
fread(buf_deflated, sizeof(unsigned char), in_deflated[i], in);
z_stream z;
// Set up the zlib inflation
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
z.opaque = Z_NULL;
z.avail_in = 0;
z.next_in = Z_NULL;
inflateInit2(&z, -15);
// Set up the input and output streams
z.avail_in = in_deflated[i];
z.next_in = buf_deflated;
z.avail_out = in_inflated[i];
z.next_out = (Bytef *)buf_inflated;
printf("%i\n", inflate(&z, Z_NO_FLUSH));
int inflate_ok = inflateEnd(&z);
if(inflate_ok)
{
printf("Inflate failed (%i)\n\n",inflate_ok);
//error - can't handle it; you're fucked if this doesn't work and flash0 was erased :/
} else {
printf("Inflated OK (%i)\n\n",inflate_ok);
}
char fn[16];
sprintf(fn, "%i.BARPIECE", i);
out = fopen(fn, "w");
fwrite(buf_inflated, in_deflated[i], sizeof(unsigned char), out);
fclose(out);
free(buf_deflated);
free(buf_inflated);
}
free(in_deflated);
free(in_inflated);
free(in_offsets);
free(in_crcs);
fclose(in);
return 0;
}
/*
int deflate_file(FILE *f, int offset)
{
z_stream z;
// Set up the zlib inflation
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
z.opaque = Z_NULL;
z.avail_in = 0;
z.next_in = Z_NULL;
inflateInit2(&z, -15);
// Set up the input and output streams
z.avail_in = internal_filesize;
z.next_in = file->data;
z.avail_out = filesize;
void *output = malloc(filesize);
z.next_out = (Bytef *)output;
// et voila.
inflate(&z, Z_NO_FLUSH);
int inflate_ok = inflateEnd(&z);
if(inflate_ok)
{
//error - can't handle it; you're fucked if this doesn't work and flash0 was erased :/
} else {
if(file->needs_sigcheck)
GenerateSigCheck((u8 *)output);
sceIoWrite(out, (unsigned char *)output, filesize);
}
return 0;
}
*/
ignore that last one, this is better:
#include <zlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
unsigned int in_magic, in_filecount, *in_crcs, *in_offsets, *in_inflated, *in_deflated, in_length;
unsigned char *buf_inflated, *buf_deflated;
int i;
if(argc < 2) return !(printf("Note: You can run this from the command prompt.\nIn Windows, you can just drag a .bar file to the .exe, and that'll work too.\nUsage: %s <bar file>\n", argv[0])+(strncmp(argv[0], "/cygdrive", 9) ? 0 : getc(stdin)))-1;
FILE *in, *out;
in = fopen(argv[1], "r");
if(!in)
return !(printf("BAR file %s not found.\n", argv[1]))-1;
fread(&in_magic, sizeof(unsigned int), 1, in);
if(in_magic != 0xADEF17E1)
return !(printf("Invalid BAR file.\n", argv[1]))-1;
fseek(in, 0x10, SEEK_SET);
fread(&in_filecount, sizeof(unsigned int), 1, in);
in_crcs = (unsigned int *)malloc(in_filecount*sizeof(unsigned int));
in_offsets = (unsigned int *)malloc(in_filecount*sizeof(unsigned int));
in_inflated = (unsigned int *)malloc(in_filecount*sizeof(unsigned int));
in_deflated = (unsigned int *)malloc(in_filecount*sizeof(unsigned int));
printf("%i files found\n", in_filecount);
for(i=0; i < in_filecount; i++)
{
fseek(in, 0x14+0x10*i, SEEK_SET);
fread(&(in_crcs[i]), sizeof(unsigned int), 1, in);
fread(&(in_offsets[i]), sizeof(unsigned int), 1, in);
fread(&(in_inflated[i]), sizeof(unsigned int), 1, in);
fread(&(in_deflated[i]), sizeof(unsigned int), 1, in);
printf("File %i:\nCRC = 0x%08X\nOffset = header+0x%04X\ninflated size = %i\ndeflated size = %i\n",i+1,in_crcs[i],in_offsets[i],in_inflated[i],in_deflated[i]);
buf_inflated = (unsigned char*)malloc(in_inflated[i]*sizeof(unsigned char));
if(in_inflated[i] != in_deflated[i])
{
buf_deflated = (unsigned char*)malloc(in_deflated[i]*sizeof(unsigned char));
fseek(in, in_offsets[i], SEEK_SET);
fread(buf_deflated, sizeof(unsigned char), in_deflated[i], in);
z_stream z;
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
z.opaque = Z_NULL;
z.avail_in = 0;
z.next_in = Z_NULL;
inflateInit2(&z, -15);
z.avail_in = in_deflated[i];
z.next_in = buf_deflated;
z.avail_out = in_inflated[i];
z.next_out = (Bytef *)buf_inflated;
inflate(&z, Z_NO_FLUSH);
int inflate_ok = inflateEnd(&z);
if(inflate_ok)
{
printf("Inflate failed\n\n",inflate_ok);
return;
} else {
printf("Inflated OK. Writing...\n",inflate_ok);
char fn[16];
sprintf(fn, "%i.BARPIECE", i+1);
out = fopen(fn, "w");
fwrite(buf_inflated, in_deflated[i], sizeof(unsigned char), out);
fclose(out);
printf("Wrote OK\n\n");
}
free(buf_deflated);
} else {
printf("Not deflated. Writing...\n");
fread(buf_inflated, sizeof(unsigned char), in_deflated[i], in);
char fn[16];
sprintf(fn, "%i.BARPIECE", i+1);
out = fopen(fn, "w");
fwrite(buf_inflated, in_deflated[i], sizeof(unsigned char), out);
fclose(out);
printf("Wrote OK\n\n");
}
free(buf_inflated);
}
free(in_deflated);
free(in_inflated);
free(in_offsets);
free(in_crcs);
fclose(in);
return 0;
}
know what, I give up. I keep doing it wrong.
I didn't add 0x14+0x10*in_filecount to the offsets for each file part...
Here.
It'll unpack the .BAR file to its own subfolder. It can auto-detect the most typical file formats stored in .BARs and name the output appropriately.
Source is included, of course; you'll need zlib to build it.
Post a Comment