From 7791683280378a8b5e04e2fb2e6142e72a2e6362 Mon Sep 17 00:00:00 2001 From: koshkokoshka Date: Tue, 5 Sep 2023 22:07:46 +0200 Subject: [PATCH] Add source code --- README.md | 5 +- a.fbx | Bin 0 -> 26428 bytes fbx.c | 292 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fbx.h | 54 ++++++++++ main.c | 45 +++++++++ 5 files changed, 394 insertions(+), 2 deletions(-) create mode 100644 a.fbx create mode 100644 fbx.c create mode 100644 fbx.h create mode 100644 main.c diff --git a/README.md b/README.md index ffb521a..ec63f31 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ -# c-fbx-parser -Compact .FBX parser written in C language +# Compact .FBX parser + +Compact .FBX parser written in C language \ No newline at end of file diff --git a/a.fbx b/a.fbx new file mode 100644 index 0000000000000000000000000000000000000000..cf63966704c3c9e3261f4677aaa3dd8025207e40 GIT binary patch literal 26428 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 HMbrKlgG0Xt literal 0 HcmV?d00001 diff --git a/fbx.c b/fbx.c new file mode 100644 index 0000000..69e39c6 --- /dev/null +++ b/fbx.c @@ -0,0 +1,292 @@ +#include "fbx.h" + +#include +#include +#include + +FBXNodeList *FBXNodeList_Create(size_t initial_capacity) +{ + FBXNodeList *list = malloc(sizeof(FBXNodeList)); + if (list == NULL) { + return NULL; + } + + list->length = 0; + list->capacity = initial_capacity; + + if (initial_capacity > 0) { + list->nodes = malloc(sizeof(FBXNode) * initial_capacity); + if (list->nodes == NULL) { + free(list); + return NULL; + } + } else { + list->nodes = NULL; + } + + return list; +} + +bool FBXNodeList_Resize(FBXNodeList *list, size_t capacity) +{ + void *memory_address; + if (list->nodes == NULL) { + memory_address = malloc(sizeof(FBXNode)); + } else { + memory_address = realloc(list->nodes, sizeof(FBXNode) * capacity); + } + if (memory_address == NULL) { + return false; + } + list->nodes = memory_address; + list->capacity = capacity; + return true; +} + +bool FBXNodeList_Truncate(FBXNodeList *list) +{ + if (list->length == list->capacity) { + return true; + } + return FBXNodeList_Resize(list, list->length); +} + +bool FBXNodeList_Insert(FBXNodeList *list, FBXNode *node) +{ + size_t new_length = list->length + 1; + if (new_length > list->capacity) { + + size_t new_capacity = list->capacity + list->capacity; // grow capacity + if (new_capacity == 0) { + new_capacity = 1; + } + + if (FBXNodeList_Resize(list, new_capacity) == false) { + return false; + } + } + + memcpy(&list->nodes[list->length], node, sizeof(FBXNode)); + list->length = new_length; + + return true; +} + +bool FBX_ParseNodeProperty(FILE *file, FBXNodeProperty *property) +{ + // Read property type + fread(&property->type, sizeof(uint8_t), 1, file); + + // Read property value + switch (property->type) { + case 'Y': { /* i16 */ + fread(&property->Y.value, sizeof(int16_t), 1, file); + break; + } + case 'C': { /* u8 (bool) */ + fread(&property->C.value, sizeof(bool), 1, file); + break; + } + case 'I': { /* i32 */ + fread(&property->I.value, sizeof(int32_t), 1, file); + break; + } + case 'F': { /* f32 */ + fread(&property->F.value, sizeof(float), 1, file); + break; + } + case 'D': { /* f64 */ + fread(&property->D.value, sizeof(double), 1, file); + break; + } + case 'L': { /* i64 */ + fread(&property->L.value, sizeof(int64_t), 1, file); + break; + } + case 'f': { /* f32[] */ + fread(&property->f.length, sizeof(uint32_t), 1, file); + fread(&property->f.encoding, sizeof(uint32_t), 1, file); + fread(&property->f.compressed_length, sizeof(uint32_t), 1, file); + if (property->f.encoding == 0) { + fseek(file, sizeof(float) * property->f.length, SEEK_CUR); + } else { + fseek(file, property->f.compressed_length, SEEK_CUR); + } + break; + } + case 'd': { /* f64[] */ + fread(&property->d.length, sizeof(uint32_t), 1, file); + fread(&property->d.encoding, sizeof(uint32_t), 1, file); + fread(&property->d.compressed_length, sizeof(uint32_t), 1, file); + if (property->d.encoding == 0) { + fseek(file, sizeof(double ) * property->d.length, SEEK_CUR); + } else { + fseek(file, property->d.compressed_length, SEEK_CUR); + } + break; + } + case 'l': { /* i64[] */ + fread(&property->l.length, sizeof(uint32_t), 1, file); + fread(&property->l.encoding, sizeof(uint32_t), 1, file); + fread(&property->l.compressed_length, sizeof(uint32_t), 1, file); + if (property->l.encoding == 0) { + fseek(file, sizeof(int64_t) * property->l.length, SEEK_CUR); + } else { + fseek(file, property->l.compressed_length, SEEK_CUR); + } + break; + } + case 'i': { /* i32[] */ + fread(&property->i.length, sizeof(uint32_t), 1, file); + fread(&property->i.encoding, sizeof(uint32_t), 1, file); + fread(&property->i.compressed_length, sizeof(uint32_t), 1, file); + if (property->i.encoding == 0) { + fseek(file, sizeof(int32_t) * property->i.length, SEEK_CUR); + } else { + fseek(file, property->i.compressed_length, SEEK_CUR); + } + break; + } + case 'b': { /* u8[] (bool[]) */ + fread(&property->b.length, sizeof(uint32_t), 1, file); + fread(&property->b.encoding, sizeof(uint32_t), 1, file); + fread(&property->b.compressed_length, sizeof(uint32_t), 1, file); + if (property->b.encoding == 0) { + fseek(file, sizeof(bool) * property->b.length, SEEK_CUR); + } else { + fseek(file, property->b.compressed_length, SEEK_CUR); + } + break; + } + case 'S': { /* raw string */ + fread(&property->S.length, sizeof(uint32_t), 1, file); + fseek(file, property->S.length, SEEK_CUR); + break; + } + case 'R': { /* raw binary */ + fread(&property->R.length, sizeof(uint32_t), 1, file); + fseek(file, property->R.length, SEEK_CUR); + break; + } + default: { + return false; // invalid property type + } + } + + return true; +} + +bool FBX_ParseNode(FILE *file, FBXNode *node) +{ + // Read node record + fread(&node->end_offset, sizeof(uint32_t), 1, file); + if (ferror(file) != 0) { + return false; + } + fread(&node->properties_count, sizeof(uint32_t), 1, file); + if (ferror(file) != 0) { + return false; + } + fread(&node->properties_list_length, sizeof(uint32_t), 1, file); + if (ferror(file) != 0) { + return false; + } + fread(&node->name_length, sizeof(uint8_t), 1, file); + if (ferror(file) != 0) { + return false; // failed to read a node + } + + // Read node name + fread(node->name, 1, node->name_length, file); + if (ferror(file) != 0) { + return false; // failed to read a node name + } + node->name[node->name_length] = '\0'; // end string with the '\0' character +// fseek(file, node->name_length, SEEK_CUR); + + // Read node properties + FBXNodeProperty property; + for (int i = 0; i < node->properties_count; ++i) { + if (!FBX_ParseNodeProperty(file, &property)) { + return false; + } + } +// fseek(file, node->properties_list_length, SEEK_CUR); + + return true; +} + +FBXNodeList *FBX_ParseNodes(FILE *file) +{ + FBXNodeList *list = FBXNodeList_Create(0); + if (list == NULL) { + return NULL; + } + + while (1) { + FBXNode node; + memset(&node, 0, sizeof(FBXNode)); + if (FBX_ParseNode(file, &node) == false) { + break; + } + if (node.end_offset == 0) { + break; // no more list + } + + if (ftell(file) != node.end_offset) { + // Recursive parse subnodes + node.subnodes = FBX_ParseNodes(file); + + // Skip to the next node + if (fseek(file, node.end_offset, SEEK_SET) != 0) { + break; + } + } + + if (FBXNodeList_Insert(list, &node) == false) { + break; + } + } + + FBXNodeList_Truncate(list); + + return list; +} + +FBXNodeList *FBX_Parse(const char *path) +{ + FBXNodeList *nodes = NULL; + + // Open file handle + FILE *file = NULL; + if (fopen_s(&file, path, "rb") != 0) { + goto FUNCTION_END; + } + + // Check file signature + char buffer[21]; + fread(buffer, 21, 1, file); + if (ferror(file) != 0) { + goto FUNCTION_END; + } + const char *FBX_SIGNATURE = "Kaydara FBX Binary "; + if (strncmp(buffer, FBX_SIGNATURE, 20) != 0) { + goto FUNCTION_END; + } + + // Skip to the beginning of the first node + if (fseek(file, 27, SEEK_SET) != 0) { + goto FUNCTION_END; + } + + // Read nodes + nodes = FBX_ParseNodes(file); + + // Cleanup and exit +FUNCTION_END: + if (file != NULL) { + fclose(file); + } + + return nodes; +} \ No newline at end of file diff --git a/fbx.h b/fbx.h new file mode 100644 index 0000000..349989e --- /dev/null +++ b/fbx.h @@ -0,0 +1,54 @@ +#ifndef FBX_H +#define FBX_H + +#include +#include + +#define FBX_NODE_NAME_MAX 0xFF + +struct FBXNode; +struct FBXNodeProperty; +struct FBXNodeList; + +typedef struct FBXNode FBXNode; +typedef struct FBXNodeProperty FBXNodeProperty; +typedef struct FBXNodeList FBXNodeList; + +struct FBXNodeList { + size_t length; + size_t capacity; + struct FBXNode *nodes; +}; + +struct FBXNode { + uint32_t end_offset; + uint32_t properties_count; + uint32_t properties_list_length; + uint8_t name_length; + char name[FBX_NODE_NAME_MAX]; + struct FBXNodeList *subnodes; +}; + +struct FBXNodeProperty { + uint8_t type; + union { + struct { int16_t value; } Y; // i16 + struct { bool value; } C; // u8 + struct { int32_t value; } I; // i32 + struct { float value; } F; // f32 + struct { double value; } D; // f64 + struct { int64_t value; } L; // i64 + struct { int length; int encoding; int compressed_length; float *value; } f; // f32[] + struct { int length; int encoding; int compressed_length; double *value; } d; // f64[] + struct { int length; int encoding; int compressed_length; int64_t *value; } l; // i64[] + struct { int length; int encoding; int compressed_length; int32_t *value; } i; // i32[] + struct { int length; int encoding; int compressed_length; bool *value; } b; // u8[] + struct { int length; char *value; } S; // string + struct { int length; uint8_t *value; } R; // raw + void *value; + }; +}; + +FBXNodeList *FBX_Parse(const char *path); + +#endif \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..0a6bd0e --- /dev/null +++ b/main.c @@ -0,0 +1,45 @@ +#include "fbx.h" + +#include + +void PrintNodeNames(int gap, FBXNodeList *node_list) +{ + // Loop over each node + for (int i = 0; i < node_list->length; ++i) { + FBXNode *node = &node_list->nodes[i]; + + // Print node name + for (int j = 0; j < gap; ++j) { + printf("\t"); + } + printf("- %s\n", node->name); + + // Print sub node_list + if (node->subnodes != NULL) { + PrintNodeNames(gap + 1, node->subnodes); + } + } +} + +int main(int argc, char *argv[]) +{ + // Get file path + const char *fbx_path; + if (argc <= 1) { + fbx_path = "a.fbx"; // fallback file name + } else { + fbx_path = argv[1]; + } + + // Parse .FBX file + FBXNodeList *node_list = FBX_Parse(fbx_path); + if (node_list == NULL) { + printf("Failed to open \"%s\"\n", fbx_path); + return 1; + } + + // Print node names + PrintNodeNames(0, node_list); + + return 0; +}