Skip to content

Instantly share code, notes, and snippets.

@lynxluna
Created April 9, 2012 01:41
Show Gist options
  • Save lynxluna/2340756 to your computer and use it in GitHub Desktop.
Save lynxluna/2340756 to your computer and use it in GitHub Desktop.
Big File Reader
/*
* Copyright (c) 2012, Muhammad Sumyandityo Noor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
// For reading Electronic Arts' .big files archives
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>
// Per File Entry Headers
struct big_entry_file_header {
uint32_t offset; // big-endian
uint32_t size; // big-endian
};
// Archive header
struct big_header {
char ident[4];
uint32_t archive_size; // little-endian
uint32_t number_of_files; // big-endian
uint32_t first_file_offset; // big-endian
};
// Endian Check
enum
{
O32_LITTLE_ENDIAN = 0x03020100ul,
O32_BIG_ENDIAN = 0x00010203ul,
O32_PDP_ENDIAN = 0x01000302ul
};
static const union { unsigned char bytes[4]; uint32_t value; } o32_host_order =
{ { 0, 1, 2, 3 } };
#define O32_HOST_ORDER (o32_host_order.value)
// byte swap 32-bit
static unsigned int inline
swapped( unsigned int num ) {
return ((num>>24)&0xff) | // move byte 3 to byte 0
((num<<8)&0xff0000) | // move byte 1 to byte 2
((num>>8)&0xff00) | // move byte 2 to byte 1
((num<<24)&0xff000000); // byte 0 to byte 3
}
// convert big endian to native endian
static unsigned int inline
big2native( unsigned int num ) {
if (O32_HOST_ORDER == O32_LITTLE_ENDIAN) {
return swapped(num);
}
else {
return num;
}
}
// convert little endian to native endian
static unsigned int inline
little2native(unsigned int num) {
if (O32_HOST_ORDER == O32_BIG_ENDIAN) {
return swapped(num);
}
else {
return num;
}
}
int main( int argc, char **argv ) {
// file stat
struct stat sb;
// file length
off_t len;
// mapped memory address
char *p;
// file handle
int fd;
// archive header address
struct big_header *ph;
// hard coded [sorry, just for test !^_^]
fd = open("/Applications/Command & Conquer Generals/Generals Data"
"/Terrain.big", O_RDONLY);
if (fstat(fd, &sb) == -1) {
perror("fstat");
return 1;
}
if (!S_ISREG(sb.st_mode)) {
fprintf (stderr, "%s is not a file\n", "Invalid Big File");
return 1;
}
p = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
ph = (struct big_header*) p;
printf("Size of File : ");
if (little2native(ph->archive_size) >= 1024*1024) {
float s = little2native(ph->archive_size) / (1024.0f * 1024.0f);
printf("%.2f MB", s);
}
else if (little2native(ph->archive_size) >= 1024) {
float s = little2native(ph->archive_size) / 1024.0f;
printf("%.2f KB", s);
}
else {
printf("%ul bytes", little2native(ph->archive_size));
}
printf("\n");
printf("Number of Files : %u\n", big2native(ph->number_of_files));
printf("First File Offset : 0x%x\n", big2native(ph->first_file_offset));
char *f = p + sizeof(struct big_header);
char *d = f;
int i;
for (i = 0; i < big2native(ph->number_of_files); ++i) {
struct big_entry_file_header *eh = (struct big_entry_file_header*)d;
d += sizeof(struct big_entry_file_header);
printf("%s - ", d);
while (*d != '\0') {
++d;
}
++d;
printf("Size %u, Offset 0x%x\n", big2native(eh->size),
big2native(eh->offset));
}
close(fd);
munmap(p, sb.st_size);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment