Created
July 22, 2017 09:11
-
-
Save InternetUnexplorer/2e266b6d45d39e767e06e7b2155452aa to your computer and use it in GitHub Desktop.
Reads and prints information about the contents of Blender (.blend) files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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