Skip to content
This repository has been archived by the owner on Jun 12, 2024. It is now read-only.

Commit

Permalink
added test-iff, removed minor bugs in IFF
Browse files Browse the repository at this point in the history
  • Loading branch information
septag committed May 5, 2020
1 parent 2864c18 commit 1b298d2
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 24 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ ipch
__pycache__
Thumbs.db
.build*
.clangd
*.sublime-workspace

# Gradle
.gradle
Expand All @@ -33,7 +35,6 @@ Thumbs.db
/build-*
/captures


# Generated files
docs/Doxyfile
docs/html
Expand Down
5 changes: 2 additions & 3 deletions include/sx/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
// int chunk = sx_iff_get_chunk(iff, fourcc, parent_id);
// while (chunk != -1) {
// sx_iff_read_chunk(chunk, data, ..);
// chunk = sx_iff_get_next_chunk(iff);
// chunk = sx_iff_get_next_chunk(iff, chunk);
// }
// sx_iff_read_chunk: Read chunk data. You should provide the chunk_id returned
// by get_chunk family of functions
Expand Down Expand Up @@ -226,7 +226,6 @@ typedef struct sx_iff_file {
sx_mem_writer* mwrite;
sx_file* disk;
};
int cur_chunk_id;
bool read_all;
} sx_iff_file;
#pragma pack(pop)
Expand All @@ -242,7 +241,7 @@ SX_API bool sx_iff_init_from_mem_writer(sx_iff_file* iff, sx_mem_writer* mwrite,
SX_API void sx_iff_release(sx_iff_file* iff);

SX_API int sx_iff_get_chunk(sx_iff_file* iff, uint32_t fourcc, int parent_id);
SX_API int sx_iff_get_next_chunk(sx_iff_file* iff);
SX_API int sx_iff_get_next_chunk(sx_iff_file* iff, int start_chunk_id);
SX_API bool sx_iff_read_chunk(sx_iff_file* iff, int chunk_id, void* chunk_data, int64_t size);

SX_API int sx_iff_put_chunk(sx_iff_file* iff, int parent_id, uint32_t fourcc,
Expand Down
57 changes: 37 additions & 20 deletions src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# endif
#endif // SX_

#define RIFF_SIGN sx_makefourcc('R', 'I', 'F', 'F')
#define SIFF_SIGN sx_makefourcc('S', 'I', 'F', 'F')

sx_mem_block* sx_mem_create_block(const sx_alloc* alloc, int64_t size, const void* data, int align)
{
Expand Down Expand Up @@ -213,6 +213,7 @@ int64_t sx_mem_seekr(sx_mem_reader* reader, int64_t offset, sx_whence whence)

typedef struct sx__file_win32 {
HANDLE handle;
sx_file_open_flags flags;
int64_t size;
} sx__file_win32;

Expand Down Expand Up @@ -264,6 +265,7 @@ bool sx_file_open(sx_file* file, const char* filepath, sx_file_open_flags flags)
}

f->handle = hfile;
f->flags = flags;
if (flags & (SX_FILE_READ|SX_FILE_APPEND)) {
LARGE_INTEGER llsize;
GetFileSizeEx(hfile, &llsize);
Expand Down Expand Up @@ -293,6 +295,14 @@ int64_t sx_file_read(sx_file* file, void* data, int64_t size)
sx_assert(f->handle && f->handle != INVALID_HANDLE_VALUE);
sx_assert_rel(size < UINT32_MAX);

if (f->flags & SX_FILE_NOCACHE) {
static size_t pagesz = 0;
if (pagesz == 0) {
pagesz = sx_os_pagesz();
}
sx_assert_rel((uintptr_t)data % pagesz == 0 && "buffers must be aligned with NoCache flag");
}

DWORD bytes_read;
if (!ReadFile(f->handle, data, (DWORD)size, &bytes_read, NULL)) {
return -1;
Expand Down Expand Up @@ -361,6 +371,7 @@ int64_t sx_file_size(const sx_file* file)

typedef struct sx__file_posix {
int id;
uint32_t flags;
int64_t size;
} sx__file_posix;

Expand Down Expand Up @@ -413,6 +424,7 @@ bool sx_file_open(sx_file* file, const char* filepath, sx_file_open_flags flags)
return false;
}
f->id = file_id;
f->flags = flags;
f->size = (int64_t)_stat.st_size;
return true;
}
Expand All @@ -431,8 +443,15 @@ int64_t sx_file_read(sx_file* file, void* data, int64_t size)
{
sx_assert(file);
sx__file_posix* f = (sx__file_posix*)file;

sx_assert(f->id && f->id != -1);

if (f->flags & SX_FILE_NOCACHE) {
static size_t pagesz = 0;
if (pagesz == 0) {
pagesz = sx_os_pagesz();
}
sx_assert_rel((uintptr_t)data % pagesz == 0 && "buffers must be aligned with NoCache flag");
}
return read(f->id, data, (size_t)size);
}

Expand Down Expand Up @@ -528,6 +547,7 @@ static inline int64_t sx__iff_read(sx_iff_file* iff, void* data, int64_t size)
case SX_IFFTYPE_MEM_READER:
return sx_mem_read(iff->mread, data, size);
case SX_IFFTYPE_DISK_READER:
case SX_IFFTYPE_DISK_WRITER:
return sx_file_read(iff->disk, data, size);
default:
sx_assert(0);
Expand Down Expand Up @@ -602,7 +622,7 @@ bool sx_iff_init_from_file_reader(sx_iff_file* iff, sx_file* file, sx_iff_flags
// read first chunk
sx_iff_chunk first_chunk;
sx__iff_read(iff, &first_chunk, sizeof(first_chunk));
if (first_chunk.fourcc != RIFF_SIGN || first_chunk.parent_id != -1 || first_chunk.size) {
if (first_chunk.fourcc != SIFF_SIGN || first_chunk.parent_id != -1 || first_chunk.size) {
sx_assert(0 && "invalid IFF file format");
return false;
}
Expand Down Expand Up @@ -634,8 +654,9 @@ bool sx_iff_init_from_file_writer(sx_iff_file* iff, sx_file* file, sx_iff_flags
// read first chunk (validate)
sx__iff_seek(iff, 0, SX_WHENCE_BEGIN);
sx_iff_chunk first_chunk;
sx__iff_read(iff, &first_chunk, sizeof(first_chunk));
if (first_chunk.fourcc != RIFF_SIGN || first_chunk.parent_id != -1 || first_chunk.size) {
int bytes_read = sx__iff_read(iff, &first_chunk, sizeof(first_chunk));
if (bytes_read != sizeof(first_chunk) || first_chunk.fourcc != SIFF_SIGN ||
first_chunk.parent_id != -1 || first_chunk.size) {
sx_assert(0 && "invalid IFF file format");
return false;
}
Expand All @@ -650,7 +671,7 @@ bool sx_iff_init_from_file_writer(sx_iff_file* iff, sx_file* file, sx_iff_flags
} else {
// write first chunk
sx_iff_chunk chunk = {
.fourcc = RIFF_SIGN,
.fourcc = SIFF_SIGN,
.parent_id = -1
};
sx__iff_write(iff, &chunk, sizeof(chunk));
Expand All @@ -675,7 +696,7 @@ bool sx_iff_init_from_mem_reader(sx_iff_file* iff, sx_mem_reader* mread, sx_iff_
// read first chunk
sx_iff_chunk first_chunk;
sx__iff_read(iff, &first_chunk, sizeof(first_chunk));
if (first_chunk.fourcc != RIFF_SIGN || first_chunk.parent_id != -1 || first_chunk.size) {
if (first_chunk.fourcc != SIFF_SIGN || first_chunk.parent_id != -1 || first_chunk.size) {
sx_assert(0 && "invalid IFF file format");
return false;
}
Expand Down Expand Up @@ -708,7 +729,7 @@ bool sx_iff_init_from_mem_writer(sx_iff_file* iff, sx_mem_writer* mwrite, sx_iff
sx__iff_seek(iff, 0, SX_WHENCE_BEGIN);
sx_iff_chunk first_chunk;
sx__iff_read(iff, &first_chunk, sizeof(first_chunk));
if (first_chunk.fourcc != RIFF_SIGN || first_chunk.parent_id != -1 || first_chunk.size) {
if (first_chunk.fourcc != SIFF_SIGN || first_chunk.parent_id != -1 || first_chunk.size) {
sx_assert(0 && "invalid IFF file format");
return false;
}
Expand All @@ -723,7 +744,7 @@ bool sx_iff_init_from_mem_writer(sx_iff_file* iff, sx_mem_writer* mwrite, sx_iff
} else {
// write first chunk
sx_iff_chunk chunk = {
.fourcc = RIFF_SIGN,
.fourcc = SIFF_SIGN,
.parent_id = -1
};
sx__iff_write(iff, &chunk, sizeof(chunk));
Expand Down Expand Up @@ -751,6 +772,7 @@ int sx_iff_get_chunk(sx_iff_file* iff, uint32_t fourcc, int parent_id)
int64_t r = sx__iff_read(iff, &chunk, sizeof(chunk));
if (r < (int64_t)sizeof(chunk)) {
sx_assert_rel(r == 0 && "file is probably corrupt");
iff->read_all = true;
break; // EOF
}

Expand All @@ -762,15 +784,13 @@ int sx_iff_get_chunk(sx_iff_file* iff, uint32_t fourcc, int parent_id)

sx_array_push(iff->alloc, iff->chunks, chunk);
if (chunk.fourcc == fourcc && parent_id == chunk.parent_id) {
iff->cur_chunk_id = sx_array_count(iff->chunks) - 1;
return iff->cur_chunk_id;
return sx_array_count(iff->chunks) - 1;
}
}
} else {
// search in existing chunks
for (int i = 0, c = sx_array_count(iff->chunks); i < c; i++) {
if (iff->chunks[i].fourcc == fourcc && iff->chunks[i].parent_id == parent_id) {
iff->cur_chunk_id = i;
return i;
}
}
Expand Down Expand Up @@ -803,23 +823,20 @@ bool sx_iff_read_chunk(sx_iff_file* iff, int chunk_id, void* chunk_data, int64_t
return true;
}

int sx_iff_get_next_chunk(sx_iff_file* iff)
int sx_iff_get_next_chunk(sx_iff_file* iff, int start_chunk_id)
{
sx_assert(iff);
sx_assert(sx_array_count(iff->chunks) > start_chunk_id);

int cur_chunk_id = iff->cur_chunk_id;
sx_assert(sx_array_count(iff->chunks) > cur_chunk_id);

sx_iff_chunk* chunk = &iff->chunks[cur_chunk_id];
sx_iff_chunk* chunk = &iff->chunks[start_chunk_id];
int parent_id = chunk->parent_id;

if (!iff->read_all) {
return sx_iff_get_chunk(iff, chunk->fourcc, parent_id);
} else {
for (int i = cur_chunk_id + 1, c = sx_array_count(iff->chunks); i < c; i++) {
for (int i = start_chunk_id + 1, c = sx_array_count(iff->chunks); i < c; i++) {
const sx_iff_chunk* test_chunk = &iff->chunks[i];
if (test_chunk->fourcc == chunk->fourcc && test_chunk->parent_id == parent_id) {
iff->cur_chunk_id = i;
return i;
}
}
Expand All @@ -846,6 +863,6 @@ int sx_iff_put_chunk(sx_iff_file* iff, int parent_id, uint32_t fourcc, const voi
sx__iff_write(iff, &chunk, sizeof(chunk));
sx__iff_write(iff, chunk_data, size);
sx_array_push(iff->alloc, iff->chunks, chunk);
return 0;
return sx_array_count(iff->chunks) - 1;
}

4 changes: 4 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ add_executable(test-bheap test-bheap.c)
target_link_libraries(test-bheap PRIVATE sx)
set_target_properties(test-bheap PROPERTIES FOLDER tests)

add_executable(test-iff test-iff.c)
target_link_libraries(test-iff PRIVATE sx)
set_target_properties(test-iff PROPERTIES FOLDER tests)

# skip test-fiber, test-threads in emscripten
if (NOT EMSCRIPTEN)
add_executable(test-fiber test-fiber.c)
Expand Down
135 changes: 135 additions & 0 deletions tests/test-iff.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include "sx/allocator.h"
#include "sx/io.h"
#include "sx/string.h"

#include <stdio.h>

static const uint8_t dummy_data[473] =
{
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x22, 0x3a,
0x20, 0x5b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a,
0x20, 0x22, 0x2e, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x22, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64,
0x65, 0x5f, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
0x62, 0x75, 0x69, 0x6c, 0x64, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2e, 0x76, 0x73, 0x63, 0x6f, 0x64, 0x65,
0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x22, 0x2e, 0x63, 0x6c, 0x61, 0x6e, 0x67, 0x64, 0x22, 0x2c, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62,
0x69, 0x6e, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2d, 0x2a, 0x22, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x5f,
0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x73,
0x22, 0x3a, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65,
0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x22, 0x2e, 0x74, 0x72, 0x61, 0x76, 0x69, 0x73, 0x2e, 0x79, 0x6d, 0x6c, 0x22,
0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2c,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x22, 0x2e, 0x63, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22,
0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x22, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x73, 0x2e, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x0a, 0x7d,
};

#define LEVEL1_FOURCC sx_makefourcc('L', 'V', 'L', '1')
#define LEVEL2_FOURCC sx_makefourcc('L', 'V', 'L', '2')

static void test_write_iff(const char* filename)
{
sx_file f;
if (sx_file_open(&f, filename, SX_FILE_WRITE)) {
sx_iff_file iff;
sx_iff_init_from_file_writer(&iff, &f, 0, sx_alloc_malloc());

int level1 = sx_iff_put_chunk(&iff, 0, LEVEL1_FOURCC, dummy_data, sizeof(dummy_data), 0, 0);
sx_iff_put_chunk(&iff, level1, LEVEL2_FOURCC, dummy_data, sizeof(dummy_data), 0, 0);
sx_iff_put_chunk(&iff, level1, LEVEL2_FOURCC, dummy_data, sizeof(dummy_data), 0, 0);
sx_iff_put_chunk(&iff, 0, LEVEL1_FOURCC, dummy_data, sizeof(dummy_data), 0, 0);

sx_iff_release(&iff);
sx_file_close(&f);
}
}

static void test_append_iff(const char* filename)
{
sx_file f;
if (sx_file_open(&f, filename, SX_FILE_WRITE|SX_FILE_APPEND)) {
sx_iff_file iff;
sx_iff_init_from_file_writer(&iff, &f, SX_IFFFLAG_APPEND|SX_IFFFLAG_READ_ALL_CHUNKS, sx_alloc_malloc());

int level1 = sx_iff_put_chunk(&iff, 0, LEVEL1_FOURCC, dummy_data, sizeof(dummy_data), 0, 0);
sx_iff_put_chunk(&iff, level1, LEVEL2_FOURCC, dummy_data, sizeof(dummy_data), 0, 0);
sx_iff_put_chunk(&iff, level1, LEVEL2_FOURCC, dummy_data, sizeof(dummy_data), 0, 0);
sx_iff_put_chunk(&iff, 0, LEVEL1_FOURCC, dummy_data, sizeof(dummy_data), 0, 0);

sx_iff_release(&iff);
sx_file_close(&f);
}
}

static const char* get_tabs(int depth)
{
static char depth_str[256];
for (int i = 0; i < depth; i++) {
depth_str[i] = '\t';
}
depth_str[depth] = '\0';
return depth_str;
}

static void test_load_iff(const char* filename)
{
sx_file f;
if (sx_file_open(&f, filename, SX_FILE_READ)) {
sx_iff_file iff;
sx_iff_init_from_file_reader(&iff, &f, 0, sx_alloc_malloc());

int depth = 0;
int level1 = sx_iff_get_chunk(&iff, LEVEL1_FOURCC, 0);
while (level1 != -1) {
printf("%sChunk [Level%d] - size: %u (parent: %d)\n",
get_tabs(depth), depth+1, (uint32_t)iff.chunks[level1].size, iff.chunks[level1].parent_id);

depth++;
int level2 = sx_iff_get_chunk(&iff, LEVEL2_FOURCC, level1);
while (level2 != -1) {
printf("%sChunk [level%d] - size: %u (parent: %d)\n",
get_tabs(depth), depth+1, (uint32_t)iff.chunks[level2].size, iff.chunks[level2].parent_id);
level2 = sx_iff_get_next_chunk(&iff, level2);
}
depth--;

level1 = sx_iff_get_next_chunk(&iff, level1);
}
}
}

int main(int argc, char* argv[])
{
if (argc != 2) {
puts("You must provide a command and a file:");
puts(" test-iff load");
puts(" test-iff save");
return -1;
}

const char* command = argv[1];

if (strcmp(command, "save") == 0) {
test_write_iff("test.bin");
} else if (strcmp(command, "load") == 0) {
test_load_iff("test.bin");
} else if (strcmp(command, "append") == 0) {
test_append_iff("test.bin");
}

return 0;
}

0 comments on commit 1b298d2

Please sign in to comment.