Skip to content

Instantly share code, notes, and snippets.

@InternetUnexplorer
Created July 22, 2017 09:11
Show Gist options
  • Save InternetUnexplorer/2e266b6d45d39e767e06e7b2155452aa to your computer and use it in GitHub Desktop.
Save InternetUnexplorer/2e266b6d45d39e767e06e7b2155452aa to your computer and use it in GitHub Desktop.
Reads and prints information about the contents of Blender (.blend) files
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <error.h>
struct BlendFile
{
int ptr_size;
int endianness;
int version_num;
struct FileBlock *block_head;
};
struct FileBlock
{
char code[4];
int size;
int SDNA_index;
int count;
char *data;
struct FileBlock *next;
};
/*
struct SDNA
{
int name_c;
char **name_v;
int type_c;
char **type_v;
short *type_len_v;
int struct_c;
short *struct_type;
int *struct_field_c;
short **struct_field_type;
short **struct_field_name;
};
*/
struct BlendFile *read_blendfile(FILE *file);
static int fread_w(void *buffer, size_t size, size_t count, FILE *stream);
static int fseek_w(FILE *stream, long int offset, int origin);
static void file_err(FILE *file);
struct BlendFile *read_blendfile(FILE *file)
{
char header_buf[12];
if(fread_w(header_buf, 1, 12, file)) return NULL;
int ptr_size, endianness, version_num;
if(strncmp("BLENDER", header_buf, 7))
{
fprintf(stderr, "error: File header is malformed\n");
return NULL;
}
ptr_size = header_buf[7] == '_' ? 4 : 8;
endianness = header_buf[8] == 'V';
sscanf(header_buf+9, "%3d", &version_num);
struct FileBlock *block_head = NULL;
struct FileBlock *block_tail = NULL;
for (;;)
{
struct FileBlock *block = malloc(sizeof(struct FileBlock));
if (block == NULL)
{
perror("error");
return NULL;
}
if (fread_w(block->code, 1, 4, file)) return NULL;
if (fread_w(&block->size, 4, 1, file)) return NULL;
if (fseek_w(file, ptr_size, SEEK_CUR)) return NULL;
if (fread_w(&block->SDNA_index, 4, 1, file)) return NULL;
if (fread_w(&block->count, 4, 1, file)) return NULL;
char *data = malloc(block->size);
if (data == NULL)
{
perror("error");
return NULL;
}
if (fread_w(data, 1, block->size, file)) return NULL;
block->data = data;
if (block_head == NULL)
block_head = block;
else
block_tail->next = block;
block_tail = block;
if (!strncmp("ENDB", block->code, 4)) break;
}
struct BlendFile *blendfile = malloc(sizeof(struct BlendFile));
if (blendfile == NULL)
{
perror("error");
return NULL;
}
blendfile->ptr_size = ptr_size;
blendfile->endianness = endianness;
blendfile->version_num = version_num;
blendfile->block_head = block_head;
return blendfile;
}
static int fread_w(void *buffer, size_t size, size_t count, FILE *stream)
{
if (fread(buffer, size, count, stream) != count)
{
file_err(stream);
return 1;
}
return 0;
}
static int fseek_w(FILE *stream, long int offset, int origin)
{
if (fseek(stream, offset, origin) == -1)
{
file_err(stream);
return 1;
}
return 0;
}
static void file_err(FILE *file)
{
if (feof(file)) fprintf(stderr, "error: Unexpected end of file\n");
else perror("error");
}
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr,
"error: Not enough arguments\n"
"usage: %s <file>\n",
argv[0]
);
return 2;
}
FILE *file = fopen(argv[1], "rb");
if (file == NULL)
{
perror(argv[1]);
return 1;
}
struct BlendFile *result = read_blendfile(file);
if (fclose(file) == -1) perror("io error");
if (result == NULL) return 1;
printf("-- %s\n"
" Pointer Size: %d (%d-bit)\n"
" Endianness: %d (%s)\n"
" Blender Version: %.2f\n"
"\n"
"-- File Blocks:\n"
, argv[1]
, result->ptr_size
, result->ptr_size << 3
, result->endianness
, result->endianness ? "big" : "little"
, result->version_num / 100.0f
);
struct FileBlock *node = result->block_head;
while (node != NULL)
{
printf(" code: %.4s, size: %d, SDNA index: %d, count: %d\n"
, node->code
, node->size
, node->SDNA_index
, node->count
);
node = node->next;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment