server -> client tile sync

This commit is contained in:
jacob 2026-01-16 20:54:12 -06:00
parent 27c337202d
commit f88c33e332
20 changed files with 945 additions and 2204 deletions

View File

@ -482,9 +482,9 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
ASE_DecodedImage result = Zi; ASE_DecodedImage result = Zi;
BB_Buff bb = BB_BuffFromString(encoded); BB_Buff bb = BB_BuffFromString(encoded);
BB_Reader br = BB_ReaderFromBuffNoDebug(&bb); BB_Reader bbr = BB_ReaderFromBuffNoDebug(&bb);
ASE_Header ase_header; ASE_Header ase_header;
BB_ReadBytes(&br, StringFromStruct(&ase_header)); BB_ReadBytes(&bbr, StringFromStruct(&ase_header));
if (ase_header.magic != 0xA5E0) if (ase_header.magic != 0xA5E0)
{ {
@ -530,7 +530,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
for (u16 i = 0; i < ase_header.frames; ++i) for (u16 i = 0; i < ase_header.frames; ++i)
{ {
ASE_FrameHeader frame_header; ASE_FrameHeader frame_header;
BB_ReadBytes(&br, StringFromStruct(&frame_header)); BB_ReadBytes(&bbr, StringFromStruct(&frame_header));
u32 num_chunks = frame_header.chunks_new; u32 num_chunks = frame_header.chunks_new;
if (num_chunks == 0) if (num_chunks == 0)
@ -544,20 +544,20 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
for (u32 j = 0; j < num_chunks; ++j) for (u32 j = 0; j < num_chunks; ++j)
{ {
u32 chunk_size = BB_ReadUBits(&br, 32); u32 chunk_size = BB_ReadUBits(&bbr, 32);
ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16); ASE_ChunkKind chunk_type = BB_ReadUBits(&bbr, 16);
// Chunk size includes size & type // Chunk size includes size & type
Assert(chunk_size >= 6); Assert(chunk_size >= 6);
chunk_size -= 6; chunk_size -= 6;
u64 chunk_end_pos = BB_GetCurrentReaderByte(&br) + chunk_size; u64 chunk_end_pos = BB_GetCurrentReaderByte(&bbr) + chunk_size;
switch (chunk_type) switch (chunk_type)
{ {
default: default:
{ {
BB_ReadSeekToByte(&br, chunk_end_pos); BB_ReadSeekToByte(&bbr, chunk_end_pos);
} break; } break;
////////////////////////////// //////////////////////////////
@ -569,14 +569,14 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
layer->next = layer_head; layer->next = layer_head;
layer_head = layer; layer_head = layer;
layer->flags = BB_ReadUBits(&br, 16); layer->flags = BB_ReadUBits(&bbr, 16);
layer->type = BB_ReadUBits(&br, 16); layer->type = BB_ReadUBits(&bbr, 16);
layer->child_level = BB_ReadUBits(&br, 16); layer->child_level = BB_ReadUBits(&bbr, 16);
// Ignoring layer default width & height // Ignoring layer default width & height
BB_ReadSeekBytes(&br, sizeof(u16) * 2); BB_ReadSeekBytes(&bbr, sizeof(u16) * 2);
layer->blend_mode = BB_ReadUBits(&br, 16); layer->blend_mode = BB_ReadUBits(&bbr, 16);
if (layer->blend_mode != 0) if (layer->blend_mode != 0)
{ {
ASE_PushError( ASE_PushError(
@ -587,21 +587,21 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
goto abort; goto abort;
} }
layer->opacity = BB_ReadUBits(&br, 8); layer->opacity = BB_ReadUBits(&bbr, 8);
if (!(ase_header.flags & 1)) if (!(ase_header.flags & 1))
{ {
layer->opacity = 255; layer->opacity = 255;
} }
BB_ReadSeekBytes(&br, sizeof(u8) * 3); BB_ReadSeekBytes(&bbr, sizeof(u8) * 3);
u16 str_len = BB_ReadUBits(&br, 16); u16 str_len = BB_ReadUBits(&bbr, 16);
layer->name = (String) { str_len, PushStructsNoZero(scratch.arena, u8, str_len) }; layer->name = (String) { str_len, PushStructsNoZero(scratch.arena, u8, str_len) };
BB_ReadBytes(&br, layer->name); BB_ReadBytes(&bbr, layer->name);
if (layer->type == 2) if (layer->type == 2)
{ {
layer->tileset_index = BB_ReadUBits(&br, 32); layer->tileset_index = BB_ReadUBits(&bbr, 32);
} }
layer->index = num_layers++; layer->index = num_layers++;
@ -623,13 +623,13 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
} }
cel_tail = cel; cel_tail = cel;
cel->layer_index = BB_ReadUBits(&br, 16); cel->layer_index = BB_ReadUBits(&bbr, 16);
cel->x_pos = BB_ReadIBits(&br, 16); cel->x_pos = BB_ReadIBits(&bbr, 16);
cel->y_pos = BB_ReadIBits(&br, 16); cel->y_pos = BB_ReadIBits(&bbr, 16);
cel->opacity = BB_ReadUBits(&br, 8); cel->opacity = BB_ReadUBits(&bbr, 8);
cel->type = BB_ReadUBits(&br, 16); cel->type = BB_ReadUBits(&bbr, 16);
cel->z_index = BB_ReadIBits(&br, 16); cel->z_index = BB_ReadIBits(&bbr, 16);
BB_ReadSeekBytes(&br, sizeof(u8) * 5); BB_ReadSeekBytes(&bbr, sizeof(u8) * 5);
cel->frame_index = num_frames; cel->frame_index = num_frames;
@ -638,22 +638,22 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
case ASE_CelKind_RawImage: case ASE_CelKind_RawImage:
{ {
// Unsupported // Unsupported
BB_ReadSeekToByte(&br, chunk_end_pos); BB_ReadSeekToByte(&bbr, chunk_end_pos);
} break; } break;
case ASE_CelKind_Linked: case ASE_CelKind_Linked:
{ {
cel->frame_pos = BB_ReadUBits(&br, 16); cel->frame_pos = BB_ReadUBits(&bbr, 16);
// Actual linking happens later after iteration // Actual linking happens later after iteration
} break; } break;
case ASE_CelKind_CompressedImage: case ASE_CelKind_CompressedImage:
{ {
cel->width = BB_ReadUBits(&br, 16); cel->width = BB_ReadUBits(&bbr, 16);
cel->height = BB_ReadUBits(&br, 16); cel->height = BB_ReadUBits(&bbr, 16);
cel->pixels = PushStructsNoZero(scratch.arena, u32, cel->width * cel->height); cel->pixels = PushStructsNoZero(scratch.arena, u32, cel->width * cel->height);
u8 *huffman_encoded = BB_ReadBytesRaw(&br, chunk_end_pos - BB_GetCurrentReaderByte(&br)); u8 *huffman_encoded = BB_ReadBytesRaw(&bbr, chunk_end_pos - BB_GetCurrentReaderByte(&bbr));
if (huffman_encoded) if (huffman_encoded)
{ {
ASE_Inflate((u8 *)cel->pixels, huffman_encoded); ASE_Inflate((u8 *)cel->pixels, huffman_encoded);
@ -770,7 +770,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
} }
// Assert all data was read // Assert all data was read
Assert(BB_NumBytesRemaining(&br) == 0); Assert(BB_NumBytesRemaining(&bbr) == 0);
abort: abort:
@ -791,9 +791,9 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
ASE_DecodedSheet result = Zi; ASE_DecodedSheet result = Zi;
BB_Buff bb = BB_BuffFromString(encoded); BB_Buff bb = BB_BuffFromString(encoded);
BB_Reader br = BB_ReaderFromBuffNoDebug(&bb); BB_Reader bbr = BB_ReaderFromBuffNoDebug(&bb);
ASE_Header ase_header; ASE_Header ase_header;
BB_ReadBytes(&br, StringFromStruct(&ase_header)); BB_ReadBytes(&bbr, StringFromStruct(&ase_header));
if (ase_header.magic != 0xA5E0) if (ase_header.magic != 0xA5E0)
{ {
@ -825,7 +825,7 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
for (u16 i = 0; i < ase_header.frames; ++i) for (u16 i = 0; i < ase_header.frames; ++i)
{ {
ASE_FrameHeader frame_header; ASE_FrameHeader frame_header;
BB_ReadBytes(&br, StringFromStruct(&frame_header)); BB_ReadBytes(&bbr, StringFromStruct(&frame_header));
u32 num_chunks = frame_header.chunks_new; u32 num_chunks = frame_header.chunks_new;
if (num_chunks == 0) if (num_chunks == 0)
@ -857,27 +857,27 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
for (u32 j = 0; j < num_chunks; ++j) for (u32 j = 0; j < num_chunks; ++j)
{ {
u32 chunk_size = BB_ReadUBits(&br, 32); u32 chunk_size = BB_ReadUBits(&bbr, 32);
ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16); ASE_ChunkKind chunk_type = BB_ReadUBits(&bbr, 16);
// Chunk size includes size & type // Chunk size includes size & type
Assert(chunk_size >= 6); Assert(chunk_size >= 6);
chunk_size -= 6; chunk_size -= 6;
u64 chunk_end_pos = BB_GetCurrentReaderByte(&br) + chunk_size; u64 chunk_end_pos = BB_GetCurrentReaderByte(&bbr) + chunk_size;
switch (chunk_type) switch (chunk_type)
{ {
default: default:
{ {
BB_ReadSeekToByte(&br, chunk_end_pos); BB_ReadSeekToByte(&bbr, chunk_end_pos);
} break; } break;
//- Decode tags //- Decode tags
case ASE_ChunkKind_Tags: case ASE_ChunkKind_Tags:
{ {
u16 frame_span_count = BB_ReadUBits(&br, 16); u16 frame_span_count = BB_ReadUBits(&bbr, 16);
BB_ReadSeekBytes(&br, 8); BB_ReadSeekBytes(&bbr, 8);
for (u16 k = 0; k < frame_span_count; ++k) for (u16 k = 0; k < frame_span_count; ++k)
{ {
@ -885,13 +885,13 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
span->next = first_span; span->next = first_span;
first_span = span; first_span = span;
span->start = BB_ReadUBits(&br, 16); span->start = BB_ReadUBits(&bbr, 16);
span->end = BB_ReadUBits(&br, 16); span->end = BB_ReadUBits(&bbr, 16);
BB_ReadSeekBytes(&br, 13); BB_ReadSeekBytes(&bbr, 13);
u16 str_len = BB_ReadUBits(&br, 16); u16 str_len = BB_ReadUBits(&bbr, 16);
span->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) }; span->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) };
BB_ReadBytes(&br, span->name); BB_ReadBytes(&bbr, span->name);
++num_spans; ++num_spans;
} }
@ -907,15 +907,15 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
slice_key->next = first_slice_key; slice_key->next = first_slice_key;
first_slice_key = slice_key; first_slice_key = slice_key;
u32 num_slices = BB_ReadUBits(&br, 32); u32 num_slices = BB_ReadUBits(&bbr, 32);
slice_key->num_slices = num_slices; slice_key->num_slices = num_slices;
u32 flags = BB_ReadUBits(&br, 32); u32 flags = BB_ReadUBits(&bbr, 32);
BB_ReadSeekBytes(&br, 4); BB_ReadSeekBytes(&bbr, 4);
u16 str_len = BB_ReadUBits(&br, 16); u16 str_len = BB_ReadUBits(&bbr, 16);
slice_key->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) }; slice_key->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) };
BB_ReadBytes(&br, slice_key->name); BB_ReadBytes(&bbr, slice_key->name);
for (u32 k = 0; k < num_slices; ++k) for (u32 k = 0; k < num_slices; ++k)
{ {
@ -923,20 +923,20 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
slice->next = slice_key->first_slice; slice->next = slice_key->first_slice;
slice_key->first_slice = slice; slice_key->first_slice = slice;
u32 start = BB_ReadUBits(&br, 32); u32 start = BB_ReadUBits(&bbr, 32);
i32 x = BB_ReadIBits(&br, 32); i32 x = BB_ReadIBits(&bbr, 32);
i32 y = BB_ReadIBits(&br, 32); i32 y = BB_ReadIBits(&bbr, 32);
u32 width = BB_ReadUBits(&br, 32); u32 width = BB_ReadUBits(&bbr, 32);
u32 height = BB_ReadUBits(&br, 32); u32 height = BB_ReadUBits(&bbr, 32);
if (flags & 0x01) if (flags & 0x01)
{ {
// Skip 9-patches info // Skip 9-patches info
BB_ReadSeekBytes(&br, 128); BB_ReadSeekBytes(&bbr, 128);
} }
if (flags & 0x02) if (flags & 0x02)
{ {
// Skip pivot info // Skip pivot info
BB_ReadSeekBytes(&br, 64); BB_ReadSeekBytes(&bbr, 64);
} }
slice->start = start; slice->start = start;
@ -955,7 +955,7 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
} }
// Assert all data was read // Assert all data was read
Assert(BB_NumBytesRemaining(&br) == 0); Assert(BB_NumBytesRemaining(&bbr) == 0);
result.image_size = VEC2(image_width, image_height); result.image_size = VEC2(image_width, image_height);
result.frame_size = VEC2(frame_width, frame_height); result.frame_size = VEC2(frame_width, frame_height);

View File

@ -59,46 +59,56 @@ BB_Writer BB_WriterFromBuffNoDebug(BB_Buff *bb)
return result; return result;
} }
// FIXME: Handle overflowed bw void BB_ResetWriter(BB_Writer *bbw)
u64 BB_GetNumBitsWritten(BB_Writer *bw)
{ {
return bw->cur_bit; bbw->overflowed = 0;
bbw->cur_bit = 0;
if (bbw->bb->is_backed_by_arena)
{
ResetArena(bbw->bb->arena);
}
} }
// FIXME: Handle overflowed bw // FIXME: Handle overflowed bbw
u64 BB_GetNumBytesWritten(BB_Writer *bw) u64 BB_GetNumBitsWritten(BB_Writer *bbw)
{ {
return (bw->cur_bit + 7) >> 3; return bbw->cur_bit;
} }
// FIXME: Handle overflowed bw // FIXME: Handle overflowed bbw
String BB_GetWritten(Arena *arena, BB_Writer *bw) u64 BB_GetNumBytesWritten(BB_Writer *bbw)
{
return (bbw->cur_bit + 7) >> 3;
}
// FIXME: Handle overflowed bbw
String BB_GetWritten(Arena *arena, BB_Writer *bbw)
{ {
String result = Zi; String result = Zi;
result.len = (bw->cur_bit + 7) >> 3; result.len = (bbw->cur_bit + 7) >> 3;
result.text = PushStructsNoZero(arena, u8, result.len); result.text = PushStructsNoZero(arena, u8, result.len);
CopyBytes(result.text, bw->base, result.len); CopyBytes(result.text, bbw->base, result.len);
return result; return result;
} }
// FIXME: Handle overflowed bw // FIXME: Handle overflowed bbw
u8 *BB_GetWrittenRaw(BB_Writer *bw) u8 *BB_GetWrittenRaw(BB_Writer *bbw)
{ {
return bw->base; return bbw->base;
} }
// Returns 1 if num_bits would cause the writer to overflow its fixed buffer size (if writer is not backed by a dynamic arena bitbuff) // Returns 1 if num_bits would cause the writer to overflow its fixed buffer size (if writer is not backed by a dynamic arena bitbuff)
b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits) b32 BB_CheckWriterOverflowBits(BB_Writer *bbw, u64 num_bits)
{ {
b32 result = 0; b32 result = 0;
BB_Buff *bb = bw->bb; BB_Buff *bb = bbw->bb;
if (bw->overflowed) if (bbw->overflowed)
{ {
result = 1; result = 1;
} }
else else
{ {
u64 bytes_needed = (bw->cur_bit + num_bits + 7) >> 3; u64 bytes_needed = (bbw->cur_bit + num_bits + 7) >> 3;
if (bb->is_backed_by_arena) if (bb->is_backed_by_arena)
{ {
Arena *arena = bb->arena; Arena *arena = bb->arena;
@ -119,8 +129,8 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
Assert(0); Assert(0);
#endif #endif
result = 1; result = 1;
bw->cur_bit = max_len << 3; bbw->cur_bit = max_len << 3;
bw->overflowed = 1; bbw->overflowed = 1;
} }
} }
} }
@ -131,74 +141,74 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
//~ Align writer //~ Align writer
// Align the pos to the next byte // Align the pos to the next byte
void BB_WriteAlignToNextByte(BB_Writer *bw) void BB_WriteAlignToNextByte(BB_Writer *bbw)
{ {
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
if ((bw->cur_bit & 7) != 0) if ((bbw->cur_bit & 7) != 0)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_AlignNextByte, 0); BB_WriteDebugMagic(bbw, BB_DebugMagicKind_AlignNextByte, 0);
} }
#endif #endif
bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7; bbw->cur_bit += (8 - (bbw->cur_bit & 7)) & 7;
} }
void BB_WriteAlignBytes(BB_Writer *bw, u64 align) void BB_WriteAlignBytes(BB_Writer *bbw, u64 align)
{ {
BB_WriteAlignToNextByte(bw); BB_WriteAlignToNextByte(bbw);
BB_WriteDebugMagic(bw, BB_DebugMagicKind_AlignBytes, align); BB_WriteDebugMagic(bbw, BB_DebugMagicKind_AlignBytes, align);
if (align > 0) if (align > 0)
{ {
u64 new_pos = (bw->cur_bit >> 3); u64 new_pos = (bbw->cur_bit >> 3);
new_pos += (align - 1); new_pos += (align - 1);
new_pos -= new_pos % align; new_pos -= new_pos % align;
if (BB_CheckWriterOverflowBits(bw, (new_pos << 3) - bw->cur_bit)) if (BB_CheckWriterOverflowBits(bbw, (new_pos << 3) - bbw->cur_bit))
{ {
return; return;
} }
bw->cur_bit = new_pos << 3; bbw->cur_bit = new_pos << 3;
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Write bits //~ Write bits
void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits) void BB_WriteUBitsNoMagic(BB_Writer *bbw, u64 value, u8 num_bits)
{ {
Assert(num_bits > 0 && (num_bits == 64 || value <= ~(U64Max << num_bits))); // Bit count must be able to hold value Assert(num_bits > 0 && (num_bits == 64 || value <= ~(U64Max << num_bits))); // Bit count must be able to hold value
if (BB_CheckWriterOverflowBits(bw, num_bits)) if (BB_CheckWriterOverflowBits(bbw, num_bits))
{ {
return; return;
} }
u8 offset = bw->cur_bit & 7; u8 offset = bbw->cur_bit & 7;
if (offset != 0) if (offset != 0)
{ {
// Write unaligned bits // Write unaligned bits
u8 *at = bw->base + (bw->cur_bit >> 3); u8 *at = bbw->base + (bbw->cur_bit >> 3);
u8 num_mix_bits = MinU8((8 - offset), num_bits); u8 num_mix_bits = MinU8((8 - offset), num_bits);
u8 mix_byte = (u8)((value & ((1 << num_mix_bits) - 1)) << offset); u8 mix_byte = (u8)((value & ((1 << num_mix_bits) - 1)) << offset);
*at |= mix_byte; *at |= mix_byte;
value >>= num_mix_bits; value >>= num_mix_bits;
num_bits -= num_mix_bits; num_bits -= num_mix_bits;
bw->cur_bit += num_mix_bits; bbw->cur_bit += num_mix_bits;
} }
// cur_bit is now aligned to byte // cur_bit is now aligned to byte
u8 *at = bw->base + (bw->cur_bit >> 3); u8 *at = bbw->base + (bbw->cur_bit >> 3);
u8 num_bytes = (num_bits + 7) >> 3; u8 num_bytes = (num_bits + 7) >> 3;
CopyBytes(at, &value, num_bytes); CopyBytes(at, &value, num_bytes);
bw->cur_bit += num_bits; bbw->cur_bit += num_bits;
} }
void BB_WriteUBits(BB_Writer *bw, u64 value, u8 num_bits) void BB_WriteUBits(BB_Writer *bbw, u64 value, u8 num_bits)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_UBits, num_bits); BB_WriteDebugMagic(bbw, BB_DebugMagicKind_UBits, num_bits);
BB_WriteUBitsNoMagic(bw, value, num_bits); BB_WriteUBitsNoMagic(bbw, value, num_bits);
} }
void BB_WriteIBits(BB_Writer *bw, i64 value, u8 num_bits) void BB_WriteIBits(BB_Writer *bbw, i64 value, u8 num_bits)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_IBits, num_bits); BB_WriteDebugMagic(bbw, BB_DebugMagicKind_IBits, num_bits);
u64 ubits; u64 ubits;
if (value >= 0) if (value >= 0)
{ {
@ -208,13 +218,13 @@ void BB_WriteIBits(BB_Writer *bw, i64 value, u8 num_bits)
{ {
ubits = BB_TwosComplimentFromUint(-value, num_bits); ubits = BB_TwosComplimentFromUint(-value, num_bits);
} }
BB_WriteUBits(bw, ubits, num_bits); BB_WriteUBits(bbw, ubits, num_bits);
} }
// Returns written bit to make writing delta encoding logic cleaner // Returns written bit to make writing delta encoding logic cleaner
b32 BB_WriteBit(BB_Writer *bw, u8 value) b32 BB_WriteBit(BB_Writer *bbw, u8 value)
{ {
BB_WriteUBits(bw, value, 1); BB_WriteUBits(bbw, value, 1);
return value; return value;
} }
@ -223,24 +233,24 @@ b32 BB_WriteBit(BB_Writer *bw, u8 value)
// Writes a variable length unsigned integer. // Writes a variable length unsigned integer.
// Value is written in chunks of 7 bits w/ 8th bit signaling continuation. // Value is written in chunks of 7 bits w/ 8th bit signaling continuation.
void BB_WriteUV(BB_Writer *bw, u64 value) void BB_WriteUV(BB_Writer *bbw, u64 value)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_UV, 0); BB_WriteDebugMagic(bbw, BB_DebugMagicKind_UV, 0);
while (value > 0x7F) while (value > 0x7F)
{ {
u8 cont_byte = 0x80 | (value & 0x7F); u8 cont_byte = 0x80 | (value & 0x7F);
BB_WriteUBits(bw, cont_byte, 8); BB_WriteUBits(bbw, cont_byte, 8);
value >>= 7; value >>= 7;
} }
BB_WriteUBits(bw, value, 8); BB_WriteUBits(bbw, value, 8);
} }
// Writes a variable length signed integer. // Writes a variable length signed integer.
// Similar to BB_WriteUV, except the 7th bit of the first byte is a sign bit // Similar to BB_WriteUV, except the 7th bit of the first byte is a sign bit
// indicating that the value is stored in twos compliment. // indicating that the value is stored in twos compliment.
void BB_WriteIV(BB_Writer *bw, i64 value) void BB_WriteIV(BB_Writer *bbw, i64 value)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_IV, 0); BB_WriteDebugMagic(bbw, BB_DebugMagicKind_IV, 0);
u8 sign_bit; u8 sign_bit;
u64 tc; u64 tc;
if (value >= 0) if (value >= 0)
@ -268,107 +278,107 @@ void BB_WriteIV(BB_Writer *bw, i64 value)
tc >>= 6; tc >>= 6;
first_byte |= (tc > 0) << 7; // Cont bit first_byte |= (tc > 0) << 7; // Cont bit
first_byte |= sign_bit << 6; // Sign bit first_byte |= sign_bit << 6; // Sign bit
BB_WriteUBits(bw, first_byte, 8); BB_WriteUBits(bbw, first_byte, 8);
if (tc > 0) if (tc > 0)
{ {
while (tc > 0x7F) while (tc > 0x7F)
{ {
u8 cont_byte = 0x80 | (tc & 0x7F); u8 cont_byte = 0x80 | (tc & 0x7F);
BB_WriteUBits(bw, cont_byte, 8); BB_WriteUBits(bbw, cont_byte, 8);
tc >>= 7; tc >>= 7;
} }
BB_WriteUBits(bw, tc, 8); BB_WriteUBits(bbw, tc, 8);
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Write floating point //~ Write floating point
void BB_WriteF32(BB_Writer *bw, f32 value) void BB_WriteF32(BB_Writer *bbw, f32 value)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_F32, 0); BB_WriteDebugMagic(bbw, BB_DebugMagicKind_F32, 0);
BB_WriteUBits(bw, *(u32 *)&value, 32); BB_WriteUBits(bbw, *(u32 *)&value, 32);
} }
void BB_WriteF64(BB_Writer *bw, f64 value) void BB_WriteF64(BB_Writer *bbw, f64 value)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_F64, 0); BB_WriteDebugMagic(bbw, BB_DebugMagicKind_F64, 0);
BB_WriteUBits(bw, *(u64 *)&value, 64); BB_WriteUBits(bbw, *(u64 *)&value, 64);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Write Uid //~ Write Uid
void BB_WriteUid(BB_Writer *bw, Uid value) void BB_WriteUid(BB_Writer *bbw, Uid value)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_Uid, 128); BB_WriteDebugMagic(bbw, BB_DebugMagicKind_Uid, 128);
BB_WriteUBits(bw, value.hi, 64); BB_WriteUBits(bbw, value.hi, 64);
BB_WriteUBits(bw, value.lo, 64); BB_WriteUBits(bbw, value.lo, 64);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Write raw data //~ Write raw data
void BB_WriteString(BB_Writer *bw, String s) void BB_WriteString(BB_Writer *bbw, String s)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_String, 0); BB_WriteDebugMagic(bbw, BB_DebugMagicKind_String, 0);
BB_WriteUV(bw, s.len); BB_WriteUV(bbw, s.len);
BB_WriteBytes(bw, s); BB_WriteBytes(bbw, s);
} }
void BB_WriteBytes(BB_Writer *bw, String bytes) void BB_WriteBytes(BB_Writer *bbw, String bytes)
{ {
// Align start of bytes // Align start of bytes
BB_WriteAlignToNextByte(bw); BB_WriteAlignToNextByte(bbw);
u64 num_bits = bytes.len << 3; u64 num_bits = bytes.len << 3;
if (BB_CheckWriterOverflowBits(bw, num_bits)) if (BB_CheckWriterOverflowBits(bbw, num_bits))
{ {
return; return;
} }
u8 *at = bw->base + (bw->cur_bit >> 3); u8 *at = bbw->base + (bbw->cur_bit >> 3);
CopyBytes(at, bytes.text, bytes.len); CopyBytes(at, bytes.text, bytes.len);
bw->cur_bit += num_bits; bbw->cur_bit += num_bits;
} }
void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes) void BB_WriteSeekBytes(BB_Writer *bbw, u64 num_bytes)
{ {
BB_WriteAlignToNextByte(bw); BB_WriteAlignToNextByte(bbw);
u64 num_bits = num_bytes << 3; u64 num_bits = num_bytes << 3;
if (BB_CheckWriterOverflowBits(bw, num_bits)) if (BB_CheckWriterOverflowBits(bbw, num_bits))
{ {
return; return;
} }
bw->cur_bit += num_bits; bbw->cur_bit += num_bits;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Writer debug //~ Writer debug
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
void BB_WriteDebugMarker(BB_Writer *bw, String name) void BB_WriteDebugMarker(BB_Writer *bbw, String name)
{ {
bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7; bbw->cur_bit += (8 - (bbw->cur_bit & 7)) & 7;
for (u64 i = 0; i < name.len; ++i) for (u64 i = 0; i < name.len; ++i)
{ {
BB_WriteUBitsNoMagic(bw, name.text[i], 8); BB_WriteUBitsNoMagic(bbw, name.text[i], 8);
} }
} }
void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits) void BB_WriteDebugMagic(BB_Writer *bbw, BB_DebugMagicKind magic, u8 num_bits)
{ {
if (bw->debug_enabled) if (bbw->debug_enabled)
{ {
if (BB_CheckWriterOverflowBits(bw, 24)) if (BB_CheckWriterOverflowBits(bbw, 24))
{ {
return; return;
} }
u64 magic_ubits = (u64)magic | ((u64)num_bits << 16); u64 magic_ubits = (u64)magic | ((u64)num_bits << 16);
BB_WriteUBitsNoMagic(bw, magic_ubits, 24); BB_WriteUBitsNoMagic(bbw, magic_ubits, 24);
} }
} }
#endif #endif
@ -408,44 +418,44 @@ BB_Reader BB_ReaderFromBuffNoDebug(BB_Buff *bb)
} }
// Returns the number of bits read from the bitbuff // Returns the number of bits read from the bitbuff
// FIXME: Handle overflowed br // FIXME: Handle overflowed bbr
u64 BB_GetCurrentReaderBit(BB_Reader *br) u64 BB_GetCurrentReaderBit(BB_Reader *bbr)
{ {
return br->cur_bit; return bbr->cur_bit;
} }
// Returns the number of *full* bytes read from the bitbuff // Returns the number of *full* bytes read from the bitbuff
// FIXME: Handle overflowed br // FIXME: Handle overflowed bbr
u64 BB_GetCurrentReaderByte(BB_Reader *br) u64 BB_GetCurrentReaderByte(BB_Reader *bbr)
{ {
return br->cur_bit >> 3; return bbr->cur_bit >> 3;
} }
// Returns the number of bits left until the bitbuff overflows // Returns the number of bits left until the bitbuff overflows
// FIXME: Handle overflowed br // FIXME: Handle overflowed bbr
u64 BB_NumBitsRemaining(BB_Reader *br) u64 BB_NumBitsRemaining(BB_Reader *bbr)
{ {
return (br->base_len << 3) - br->cur_bit; return (bbr->base_len << 3) - bbr->cur_bit;
} }
// Returns the number of *full* bytes left until the bitbuff overflows // Returns the number of *full* bytes left until the bitbuff overflows
// FIXME: Handle overflowed br // FIXME: Handle overflowed bbr
u64 BB_NumBytesRemaining(BB_Reader *br) u64 BB_NumBytesRemaining(BB_Reader *bbr)
{ {
return br->base_len - (br->cur_bit >> 3); return bbr->base_len - (bbr->cur_bit >> 3);
} }
b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits) b32 BB_CheckReaderOverflowBits(BB_Reader *bbr, u64 num_bits)
{ {
b32 result = 0; b32 result = 0;
if (br->overflowed) if (bbr->overflowed)
{ {
result = 1; result = 1;
} }
else else
{ {
u64 bits_needed = br->cur_bit + num_bits; u64 bits_needed = bbr->cur_bit + num_bits;
u64 base_len_bits = br->base_len << 3; u64 base_len_bits = bbr->base_len << 3;
if (bits_needed > base_len_bits) if (bits_needed > base_len_bits)
{ {
// Tried to read past bitbuff memory // Tried to read past bitbuff memory
@ -453,8 +463,8 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits)
Assert(0); Assert(0);
#endif #endif
result = 1; result = 1;
br->cur_bit = base_len_bits; bbr->cur_bit = base_len_bits;
br->overflowed = 1; bbr->overflowed = 1;
} }
} }
return result; return result;
@ -464,62 +474,62 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits)
//~ Align reader //~ Align reader
// Align the pos to the next byte // Align the pos to the next byte
void BB_ReadAlignToNextByte(BB_Reader *br) void BB_ReadAlignToNextByte(BB_Reader *bbr)
{ {
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
if ((br->cur_bit & 7) != 0) if ((bbr->cur_bit & 7) != 0)
{ {
BB_ReadDebugMagic(br, BB_DebugMagicKind_AlignNextByte, 0); BB_ReadDebugMagic(bbr, BB_DebugMagicKind_AlignNextByte, 0);
} }
#endif #endif
br->cur_bit += (8 - (br->cur_bit & 7)) & 7; bbr->cur_bit += (8 - (bbr->cur_bit & 7)) & 7;
} }
void BB_ReadAlignBytes(BB_Reader *br, u64 align) void BB_ReadAlignBytes(BB_Reader *bbr, u64 align)
{ {
BB_ReadAlignToNextByte(br); BB_ReadAlignToNextByte(bbr);
BB_ReadDebugMagic(br, BB_DebugMagicKind_AlignBytes, align); BB_ReadDebugMagic(bbr, BB_DebugMagicKind_AlignBytes, align);
if (align > 0) if (align > 0)
{ {
u64 new_pos = (br->cur_bit >> 3); u64 new_pos = (bbr->cur_bit >> 3);
new_pos += (align - 1); new_pos += (align - 1);
new_pos -= new_pos % align; new_pos -= new_pos % align;
if (BB_CheckReaderOverflowBits(br, (new_pos << 3) - br->cur_bit)) if (BB_CheckReaderOverflowBits(bbr, (new_pos << 3) - bbr->cur_bit))
{ {
return; return;
} }
br->cur_bit = new_pos << 3; bbr->cur_bit = new_pos << 3;
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Read bits //~ Read bits
u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_bits) u64 BB_ReadUBitsNoMagic(BB_Reader *bbr, u8 num_bits)
{ {
if (BB_CheckReaderOverflowBits(br, num_bits)) if (BB_CheckReaderOverflowBits(bbr, num_bits))
{ {
return 0; return 0;
} }
u64 result = 0; u64 result = 0;
u8 offset = br->cur_bit & 7; u8 offset = bbr->cur_bit & 7;
u8 num_trailing_bits = 0; u8 num_trailing_bits = 0;
if (offset) if (offset)
{ {
u8 *at = br->base + (br->cur_bit >> 3); u8 *at = bbr->base + (bbr->cur_bit >> 3);
num_trailing_bits = MinU8(8 - offset, num_bits); num_trailing_bits = MinU8(8 - offset, num_bits);
u8 mix_byte = *at; u8 mix_byte = *at;
mix_byte >>= offset; mix_byte >>= offset;
mix_byte &= (1 << num_trailing_bits) - 1; mix_byte &= (1 << num_trailing_bits) - 1;
result = mix_byte; result = mix_byte;
num_bits -= num_trailing_bits; num_bits -= num_trailing_bits;
br->cur_bit += num_trailing_bits; bbr->cur_bit += num_trailing_bits;
} }
// cur_bit is now aligned to byte // cur_bit is now aligned to byte
u8 *at = br->base + (br->cur_bit >> 3); u8 *at = bbr->base + (bbr->cur_bit >> 3);
u8 num_bytes = (num_bits + 7) >> 3; u8 num_bytes = (num_bits + 7) >> 3;
u64 tmp = 0; u64 tmp = 0;
CopyBytes(&tmp, at, num_bytes); CopyBytes(&tmp, at, num_bytes);
@ -530,27 +540,27 @@ u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_bits)
} }
tmp &= mask; tmp &= mask;
result |= tmp << num_trailing_bits; result |= tmp << num_trailing_bits;
br->cur_bit += num_bits; bbr->cur_bit += num_bits;
return result; return result;
} }
u64 BB_ReadUBits(BB_Reader *br, u8 num_bits) u64 BB_ReadUBits(BB_Reader *bbr, u8 num_bits)
{ {
BB_ReadDebugMagic(br, BB_DebugMagicKind_UBits, num_bits); BB_ReadDebugMagic(bbr, BB_DebugMagicKind_UBits, num_bits);
return BB_ReadUBitsNoMagic(br, num_bits); return BB_ReadUBitsNoMagic(bbr, num_bits);
} }
i64 BB_ReadIBits(BB_Reader *br, u8 num_bits) i64 BB_ReadIBits(BB_Reader *bbr, u8 num_bits)
{ {
Assert(num_bits > 1); Assert(num_bits > 1);
BB_ReadDebugMagic(br, BB_DebugMagicKind_IBits, num_bits); BB_ReadDebugMagic(bbr, BB_DebugMagicKind_IBits, num_bits);
u64 tc = BB_ReadUBits(br, num_bits); u64 tc = BB_ReadUBits(bbr, num_bits);
return BB_IntFromTwosCompliment(tc, num_bits); return BB_IntFromTwosCompliment(tc, num_bits);
} }
u8 BB_ReadBit(BB_Reader *br) u8 BB_ReadBit(BB_Reader *bbr)
{ {
return BB_ReadUBits(br, 1); return BB_ReadUBits(bbr, 1);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -558,14 +568,14 @@ u8 BB_ReadBit(BB_Reader *br)
// Read a variable length unsigned integer. // Read a variable length unsigned integer.
// See BB_WriteUV for details. // See BB_WriteUV for details.
u64 BB_ReadUV(BB_Reader *br) u64 BB_ReadUV(BB_Reader *bbr)
{ {
BB_ReadDebugMagic(br, BB_DebugMagicKind_UV, 0); BB_ReadDebugMagic(bbr, BB_DebugMagicKind_UV, 0);
u64 result = 0; u64 result = 0;
for (u64 i = 0; i <= 9; ++i) for (u64 i = 0; i <= 9; ++i)
{ {
u64 part = BB_ReadUBits(br, 8); u64 part = BB_ReadUBits(bbr, 8);
u8 is_last_part = part <= 0x7F; u8 is_last_part = part <= 0x7F;
result |= (part & 0x7F) << (i * 7); result |= (part & 0x7F) << (i * 7);
if (is_last_part) if (is_last_part)
@ -578,10 +588,10 @@ u64 BB_ReadUV(BB_Reader *br)
// Read a variable length signed integer. // Read a variable length signed integer.
// See BB_WriteIV for details. // See BB_WriteIV for details.
i64 BB_ReadIV(BB_Reader *br) i64 BB_ReadIV(BB_Reader *bbr)
{ {
BB_ReadDebugMagic(br, BB_DebugMagicKind_IV, 0); BB_ReadDebugMagic(bbr, BB_DebugMagicKind_IV, 0);
u8 first_byte = BB_ReadUBits(br, 8); u8 first_byte = BB_ReadUBits(bbr, 8);
u8 cont_bit = first_byte & 0x80; u8 cont_bit = first_byte & 0x80;
u8 sign_bit = first_byte & 0x40; u8 sign_bit = first_byte & 0x40;
@ -591,7 +601,7 @@ i64 BB_ReadIV(BB_Reader *br)
{ {
for (u64 i = 0; i <= 9; ++i) for (u64 i = 0; i <= 9; ++i)
{ {
u64 part = BB_ReadUBits(br, 8); u64 part = BB_ReadUBits(bbr, 8);
u8 is_last_part = part <= 0x7F; u8 is_last_part = part <= 0x7F;
tc |= (part & 0x7F) << num_bits; tc |= (part & 0x7F) << num_bits;
num_bits += 7; num_bits += 7;
@ -620,40 +630,40 @@ i64 BB_ReadIV(BB_Reader *br)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Read floating point //~ Read floating point
f32 BB_ReadF32(BB_Reader *br) f32 BB_ReadF32(BB_Reader *bbr)
{ {
BB_ReadDebugMagic(br, BB_DebugMagicKind_F32, 0); BB_ReadDebugMagic(bbr, BB_DebugMagicKind_F32, 0);
u32 ubits = BB_ReadUBits(br, 32); u32 ubits = BB_ReadUBits(bbr, 32);
return *(f32 *)&ubits; return *(f32 *)&ubits;
} }
f64 BB_ReadF64(BB_Reader *br) f64 BB_ReadF64(BB_Reader *bbr)
{ {
BB_ReadDebugMagic(br, BB_DebugMagicKind_F64, 0); BB_ReadDebugMagic(bbr, BB_DebugMagicKind_F64, 0);
u64 ubits = BB_ReadUBits(br, 64); u64 ubits = BB_ReadUBits(bbr, 64);
return *(f64 *)&ubits; return *(f64 *)&ubits;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Read Uid //~ Read Uid
Uid BB_ReadUid(BB_Reader *br) Uid BB_ReadUid(BB_Reader *bbr)
{ {
BB_ReadDebugMagic(br, BB_DebugMagicKind_Uid, 128); BB_ReadDebugMagic(bbr, BB_DebugMagicKind_Uid, 128);
u64 hi = BB_ReadUBits(br, 64); u64 hi = BB_ReadUBits(bbr, 64);
u64 lo = BB_ReadUBits(br, 64); u64 lo = BB_ReadUBits(bbr, 64);
return UID(hi, lo); return UID(hi, lo);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Read raw data //~ Read raw data
String BB_ReadString(Arena *arena, BB_Reader *br) String BB_ReadString(Arena *arena, BB_Reader *bbr)
{ {
BB_ReadDebugMagic(br, BB_DebugMagicKind_String, 0); BB_ReadDebugMagic(bbr, BB_DebugMagicKind_String, 0);
String result = Zi; String result = Zi;
u64 len = BB_ReadUV(br); u64 len = BB_ReadUV(bbr);
u8 *src = BB_ReadBytesRaw(br, len); u8 *src = BB_ReadBytesRaw(bbr, len);
if (src != 0) if (src != 0)
{ {
result.len = len; result.len = len;
@ -664,9 +674,9 @@ String BB_ReadString(Arena *arena, BB_Reader *br)
} }
// Will fill dst with zeroes if bitbuff overflows // Will fill dst with zeroes if bitbuff overflows
void BB_ReadBytes(BB_Reader *br, String out) void BB_ReadBytes(BB_Reader *bbr, String out)
{ {
u8 *src = BB_ReadBytesRaw(br, out.len); u8 *src = BB_ReadBytesRaw(bbr, out.len);
if (src) if (src)
{ {
CopyBytes(out.text, src, out.len); CopyBytes(out.text, src, out.len);
@ -678,48 +688,48 @@ void BB_ReadBytes(BB_Reader *br, String out)
} }
// Will return 0 on bitbuff overflow. Result should be checked. // Will return 0 on bitbuff overflow. Result should be checked.
u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes) u8 *BB_ReadBytesRaw(BB_Reader *bbr, u64 num_bytes)
{ {
BB_ReadAlignToNextByte(br); BB_ReadAlignToNextByte(bbr);
u64 num_bits = num_bytes << 3; u64 num_bits = num_bytes << 3;
if (BB_CheckReaderOverflowBits(br, num_bits)) if (BB_CheckReaderOverflowBits(bbr, num_bits))
{ {
return 0; return 0;
} }
u8 *raw = br->base + (br->cur_bit >> 3); u8 *raw = bbr->base + (bbr->cur_bit >> 3);
br->cur_bit += num_bits; bbr->cur_bit += num_bits;
return raw; return raw;
} }
void BB_ReadSeekBytes(BB_Reader *br, u64 num_bytes) void BB_ReadSeekBytes(BB_Reader *bbr, u64 num_bytes)
{ {
BB_ReadAlignToNextByte(br); BB_ReadAlignToNextByte(bbr);
u64 num_bits = num_bytes << 3; u64 num_bits = num_bytes << 3;
if (BB_CheckReaderOverflowBits(br, num_bits)) if (BB_CheckReaderOverflowBits(bbr, num_bits))
{ {
return; return;
} }
br->cur_bit += num_bits; bbr->cur_bit += num_bits;
} }
void BB_ReadSeekToByte(BB_Reader *br, u64 pos) void BB_ReadSeekToByte(BB_Reader *bbr, u64 pos)
{ {
u64 cur_byte_pos = br->cur_bit >> 3; u64 cur_byte_pos = bbr->cur_bit >> 3;
if (pos >= cur_byte_pos) if (pos >= cur_byte_pos)
{ {
BB_ReadSeekBytes(br, pos - cur_byte_pos); BB_ReadSeekBytes(bbr, pos - cur_byte_pos);
} }
else else
{ {
// Tried to seek byte backwards in reader // Tried to seek byte backwards in reader
Assert(0); Assert(0);
br->overflowed = 1; bbr->overflowed = 1;
br->cur_bit = (br->base_len << 3); bbr->cur_bit = (bbr->base_len << 3);
} }
} }
@ -728,15 +738,15 @@ void BB_ReadSeekToByte(BB_Reader *br, u64 pos)
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
void BB_ReadDebugMagic(BB_Reader *br, BB_DebugMagicKind expected_magic, u8 expected_num_bits) void BB_ReadDebugMagic(BB_Reader *bbr, BB_DebugMagicKind expected_magic, u8 expected_num_bits)
{ {
if (br->debug_enabled) if (bbr->debug_enabled)
{ {
if (BB_CheckReaderOverflowBits(br, 24)) if (BB_CheckReaderOverflowBits(bbr, 24))
{ {
return; return;
} }
u64 stored = BB_ReadUBitsNoMagic(br, 24); u64 stored = BB_ReadUBitsNoMagic(bbr, 24);
BB_DebugMagicKind stored_magic = stored & 0xFFFF; BB_DebugMagicKind stored_magic = stored & 0xFFFF;
u8 stored_num_bits = (stored >> 16) & 0xFF; u8 stored_num_bits = (stored >> 16) & 0xFF;
@ -748,12 +758,12 @@ void BB_ReadDebugMagic(BB_Reader *br, BB_DebugMagicKind expected_magic, u8 expec
} }
} }
void BB_ReadDebugMarker(BB_Reader *br, String name) void BB_ReadDebugMarker(BB_Reader *bbr, String name)
{ {
br->cur_bit += (8 - (br->cur_bit & 7)) & 7; bbr->cur_bit += (8 - (bbr->cur_bit & 7)) & 7;
for (u64 i = 0; i < name.len; ++i) for (u64 i = 0; i < name.len; ++i)
{ {
u8 c_stored = BB_ReadUBitsNoMagic(br, 8); u8 c_stored = BB_ReadUBitsNoMagic(bbr, 8);
u8 c_expected = name.text[i]; u8 c_expected = name.text[i];
Assert(c_expected == c_stored); Assert(c_expected == c_stored);
} }
@ -858,72 +868,72 @@ void BB_Test(void)
String encoded = Zi; String encoded = Zi;
{ {
BB_Buff bb = BB_AcquireDynamicBuff(Gibi(64)); BB_Buff bb = BB_AcquireDynamicBuff(Gibi(64));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bbw = BB_WriterFromBuff(&bb);
for (u64 i = 0; i < countof(cases); ++i) for (u64 i = 0; i < countof(cases); ++i)
{ {
struct test_case c = cases[i]; struct test_case c = cases[i];
if (c.kind == kind_ubits) if (c.kind == kind_ubits)
{ {
BB_WriteUBits(&bw, c.ubits.v, c.ubits.num_bits); BB_WriteUBits(&bbw, c.ubits.v, c.ubits.num_bits);
} }
else if (c.kind == kind_ibits) else if (c.kind == kind_ibits)
{ {
BB_WriteIBits(&bw, c.ibits.v, c.ibits.num_bits); BB_WriteIBits(&bbw, c.ibits.v, c.ibits.num_bits);
} }
else if (c.kind == kind_uv) else if (c.kind == kind_uv)
{ {
BB_WriteUV(&bw, c.uv.v); BB_WriteUV(&bbw, c.uv.v);
} }
else if (c.kind == kind_iv) else if (c.kind == kind_iv)
{ {
BB_WriteIV(&bw, c.iv.v); BB_WriteIV(&bbw, c.iv.v);
} }
else if (c.kind == kind_string) else if (c.kind == kind_string)
{ {
BB_WriteString(&bw, c.s.v); BB_WriteString(&bbw, c.s.v);
} }
else else
{ {
Assert(0); Assert(0);
} }
} }
encoded = BB_GetWritten(scratch.arena, &bw); encoded = BB_GetWritten(scratch.arena, &bbw);
} }
{ {
BB_Buff bb = BB_BuffFromString(encoded); BB_Buff bb = BB_BuffFromString(encoded);
BB_Reader br = BB_ReaderFromBuff(&bb); BB_Reader bbr = BB_ReaderFromBuff(&bb);
for (u64 i = 0; i < countof(cases); ++i) for (u64 i = 0; i < countof(cases); ++i)
{ {
struct test_case c = cases[i]; struct test_case c = cases[i];
if (c.kind == kind_ubits) if (c.kind == kind_ubits)
{ {
u64 w = c.ubits.v; u64 w = c.ubits.v;
u64 r = BB_ReadUBits(&br, c.ubits.num_bits); u64 r = BB_ReadUBits(&bbr, c.ubits.num_bits);
Assert(r == w); Assert(r == w);
} }
else if (c.kind == kind_ibits) else if (c.kind == kind_ibits)
{ {
i64 w = c.ibits.v; i64 w = c.ibits.v;
i64 r = BB_ReadIBits(&br, c.ubits.num_bits); i64 r = BB_ReadIBits(&bbr, c.ubits.num_bits);
Assert(r == w); Assert(r == w);
} }
else if (c.kind == kind_uv) else if (c.kind == kind_uv)
{ {
u64 w = c.uv.v; u64 w = c.uv.v;
u64 r = BB_ReadUV(&br); u64 r = BB_ReadUV(&bbr);
Assert(r == w); Assert(r == w);
} }
else if (c.kind == kind_iv) else if (c.kind == kind_iv)
{ {
i64 w = c.iv.v; i64 w = c.iv.v;
i64 r = BB_ReadIV(&br); i64 r = BB_ReadIV(&bbr);
Assert(r == w); Assert(r == w);
} }
else if (c.kind == kind_string) else if (c.kind == kind_string)
{ {
String w = c.s.v; String w = c.s.v;
String r = BB_ReadString(scratch.arena, &br); String r = BB_ReadString(scratch.arena, &bbr);
Assert(MatchString(r, w)); Assert(MatchString(r, w));
} }
else else

View File

@ -74,52 +74,54 @@ BB_Buff BB_BuffFromString(String s);
BB_Writer BB_WriterFromBuff(BB_Buff *bb); BB_Writer BB_WriterFromBuff(BB_Buff *bb);
BB_Writer BB_WriterFromBuffNoDebug(BB_Buff *bb); BB_Writer BB_WriterFromBuffNoDebug(BB_Buff *bb);
u64 BB_GetNumBitsWritten(BB_Writer *bw); void BB_ResetWriter(BB_Writer *bbw);
u64 BB_GetNumBytesWritten(BB_Writer *bw);
String BB_GetWritten(Arena *arena, BB_Writer *bw); u64 BB_GetNumBitsWritten(BB_Writer *bbw);
u8 *BB_GetWrittenRaw(BB_Writer *bw); u64 BB_GetNumBytesWritten(BB_Writer *bbw);
b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits); String BB_GetWritten(Arena *arena, BB_Writer *bbw);
u8 *BB_GetWrittenRaw(BB_Writer *bbw);
b32 BB_CheckWriterOverflowBits(BB_Writer *bbw, u64 num_bits);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Writer ops //~ Writer ops
//- Align //- Align
void BB_WriteAlignToNextByte(BB_Writer *bw); void BB_WriteAlignToNextByte(BB_Writer *bbw);
void BB_WriteAlignBytes(BB_Writer *bw, u64 align); void BB_WriteAlignBytes(BB_Writer *bbw, u64 align);
//- Bits //- Bits
void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits); void BB_WriteUBitsNoMagic(BB_Writer *bbw, u64 value, u8 num_bits);
void BB_WriteUBits(BB_Writer *bw, u64 value, u8 num_bits); void BB_WriteUBits(BB_Writer *bbw, u64 value, u8 num_bits);
void BB_WriteIBits(BB_Writer *bw, i64 value, u8 num_bits); void BB_WriteIBits(BB_Writer *bbw, i64 value, u8 num_bits);
b32 BB_WriteBit(BB_Writer *bw, u8 value); b32 BB_WriteBit(BB_Writer *bbw, u8 value);
//- Variable length integers //- Variable length integers
void BB_WriteUV(BB_Writer *bw, u64 value); void BB_WriteUV(BB_Writer *bbw, u64 value);
void BB_WriteIV(BB_Writer *bw, i64 value); void BB_WriteIV(BB_Writer *bbw, i64 value);
//- Floating point //- Floating point
void BB_WriteF32(BB_Writer *bw, f32 value); void BB_WriteF32(BB_Writer *bbw, f32 value);
void BB_WriteF64(BB_Writer *bw, f64 value); void BB_WriteF64(BB_Writer *bbw, f64 value);
//- Uid //- Uid
void BB_WriteUid(BB_Writer *bw, Uid value); void BB_WriteUid(BB_Writer *bbw, Uid value);
//- Raw data //- Raw data
void BB_WriteString(BB_Writer *bw, String s); void BB_WriteString(BB_Writer *bbw, String s);
void BB_WriteBytes(BB_Writer *bw, String bytes); void BB_WriteBytes(BB_Writer *bbw, String bytes);
void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes); void BB_WriteSeekBytes(BB_Writer *bbw, u64 num_bytes);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Writer debug //~ Writer debug
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits); void BB_WriteDebugMagic(BB_Writer *bbw, BB_DebugMagicKind magic, u8 num_bits);
void BB_WriteDebugMarker(BB_Writer *bw, String name); void BB_WriteDebugMarker(BB_Writer *bbw, String name);
#else #else
#define BB_WriteDebugMagic(bw, magic, num_bits) #define BB_WriteDebugMagic(bbw, magic, num_bits)
#define BB_WriteDebugMarker(bw, name) #define BB_WriteDebugMarker(bbw, name)
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -128,54 +130,54 @@ void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes);
BB_Reader BB_ReaderFromBuff(BB_Buff *bb); BB_Reader BB_ReaderFromBuff(BB_Buff *bb);
BB_Reader BB_ReaderFromBuffNoDebug(BB_Buff *bb); BB_Reader BB_ReaderFromBuffNoDebug(BB_Buff *bb);
u64 BB_GetCurrentReaderBit(BB_Reader *br); u64 BB_GetCurrentReaderBit(BB_Reader *bbr);
u64 BB_GetCurrentReaderByte(BB_Reader *br); u64 BB_GetCurrentReaderByte(BB_Reader *bbr);
u64 BB_NumBitsRemaining(BB_Reader *br); u64 BB_NumBitsRemaining(BB_Reader *bbr);
u64 BB_NumBytesRemaining(BB_Reader *br); u64 BB_NumBytesRemaining(BB_Reader *bbr);
b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits); b32 BB_CheckReaderOverflowBits(BB_Reader *bbr, u64 num_bits);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Reader ops //~ Reader ops
//- Align //- Align
void BB_ReadAlignToNextByte(BB_Reader *br); void BB_ReadAlignToNextByte(BB_Reader *bbr);
void BB_ReadAlignBytes(BB_Reader *br, u64 align); void BB_ReadAlignBytes(BB_Reader *bbr, u64 align);
//- Bits //- Bits
u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_bits); u64 BB_ReadUBitsNoMagic(BB_Reader *bbr, u8 num_bits);
u64 BB_ReadUBits(BB_Reader *br, u8 num_bits); u64 BB_ReadUBits(BB_Reader *bbr, u8 num_bits);
i64 BB_ReadIBits(BB_Reader *br, u8 num_bits); i64 BB_ReadIBits(BB_Reader *bbr, u8 num_bits);
u8 BB_ReadBit(BB_Reader *br); u8 BB_ReadBit(BB_Reader *bbr);
//- Variable length integers //- Variable length integers
u64 BB_ReadUV(BB_Reader *br); u64 BB_ReadUV(BB_Reader *bbr);
i64 BB_ReadIV(BB_Reader *br); i64 BB_ReadIV(BB_Reader *bbr);
//- Floating point //- Floating point
f32 BB_ReadF32(BB_Reader *br); f32 BB_ReadF32(BB_Reader *bbr);
f64 BB_ReadF64(BB_Reader *br); f64 BB_ReadF64(BB_Reader *bbr);
//- Uid //- Uid
Uid BB_ReadUid(BB_Reader *br); Uid BB_ReadUid(BB_Reader *bbr);
//- Raw data //- Raw data
String BB_ReadString(Arena *arena, BB_Reader *br); String BB_ReadString(Arena *arena, BB_Reader *bbr);
void BB_ReadBytes(BB_Reader *br, String dst); void BB_ReadBytes(BB_Reader *bbr, String dst);
u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes); u8 *BB_ReadBytesRaw(BB_Reader *bbr, u64 num_bytes);
void BB_ReadSeekBytes(BB_Reader *br, u64 num_bytes); void BB_ReadSeekBytes(BB_Reader *bbr, u64 num_bytes);
void BB_ReadSeekToByte(BB_Reader *br, u64 pos); void BB_ReadSeekToByte(BB_Reader *bbr, u64 pos);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Reader debug //~ Reader debug
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
void BB_ReadDebugMagic(BB_Reader *br, BB_DebugMagicKind expected_magic, u8 expected_num_bits); void BB_ReadDebugMagic(BB_Reader *bbr, BB_DebugMagicKind expected_magic, u8 expected_num_bits);
void BB_ReadDebugMarker(BB_Reader *br, String name); void BB_ReadDebugMarker(BB_Reader *bbr, String name);
#else #else
#define BB_ReadDebugMagic(br, expected_magic, expected_num_bits) #define BB_ReadDebugMagic(bbr, expected_magic, expected_num_bits)
#define BB_ReadDebugMarker(br, name) #define BB_ReadDebugMarker(bbr, name)
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -10,20 +10,20 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings)
if (archive.len > 0) if (archive.len > 0)
{ {
BB_Buff bb = BB_BuffFromString(archive); BB_Buff bb = BB_BuffFromString(archive);
BB_Reader br = BB_ReaderFromBuff(&bb); BB_Reader bbr = BB_ReaderFromBuff(&bb);
u64 magic = BB_ReadUBits(&br, 64); u64 magic = BB_ReadUBits(&bbr, 64);
Assert(magic == ResourceEmbeddedMagic); Assert(magic == ResourceEmbeddedMagic);
// Create & insert entries // Create & insert entries
u64 num_entries = BB_ReadUBits(&br, 64); u64 num_entries = BB_ReadUBits(&bbr, 64);
for (u64 i = 0; i < num_entries; ++i) for (u64 i = 0; i < num_entries; ++i)
{ {
u64 store_hash = BB_ReadUBits(&br, 64); u64 store_hash = BB_ReadUBits(&bbr, 64);
u64 name_start = BB_ReadUBits(&br, 64); u64 name_start = BB_ReadUBits(&bbr, 64);
u64 name_len = BB_ReadUBits(&br, 64); u64 name_len = BB_ReadUBits(&bbr, 64);
u64 data_start = BB_ReadUBits(&br, 64); u64 data_start = BB_ReadUBits(&bbr, 64);
u64 data_len = BB_ReadUBits(&br, 64); u64 data_len = BB_ReadUBits(&bbr, 64);
ResourceEntry *entry = PushStruct(perm, ResourceEntry); ResourceEntry *entry = PushStruct(perm, ResourceEntry);
entry->name = STRING(name_len, archive.text + name_start); entry->name = STRING(name_len, archive.text + name_start);

View File

@ -155,13 +155,13 @@ EmbedObj Embed(String store_name, String dir_path)
// TODO: Cache dynamic bitbuffs? // TODO: Cache dynamic bitbuffs?
BB_Buff bb = BB_AcquireDynamicBuff(Gibi(2)); BB_Buff bb = BB_AcquireDynamicBuff(Gibi(2));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bbw = BB_WriterFromBuff(&bb);
// Write magic // Write magic
BB_WriteUBits(&bw, ResourceEmbeddedMagic, 64); BB_WriteUBits(&bbw, ResourceEmbeddedMagic, 64);
// Write header // Write header
BB_WriteUBits(&bw, entries_count, 64); BB_WriteUBits(&bbw, entries_count, 64);
// Reserve entries space // Reserve entries space
u64 entry_size = 0 u64 entry_size = 0
@ -170,10 +170,10 @@ EmbedObj Embed(String store_name, String dir_path)
+ 8 // Name end + 8 // Name end
+ 8 // Data start + 8 // Data start
+ 8; // Data end + 8; // Data end
u8 *entries_start = BB_GetWrittenRaw(&bw) + BB_GetNumBytesWritten(&bw); u8 *entries_start = BB_GetWrittenRaw(&bbw) + BB_GetNumBytesWritten(&bbw);
u64 entries_size = entry_size * entries_count; u64 entries_size = entry_size * entries_count;
String entries_str = STRING(entries_size, entries_start); String entries_str = STRING(entries_size, entries_start);
BB_WriteSeekBytes(&bw, entries_size); BB_WriteSeekBytes(&bbw, entries_size);
BB_Buff entries_bb = BB_BuffFromString(entries_str); BB_Buff entries_bb = BB_BuffFromString(entries_str);
BB_Writer entries_bw = BB_WriterFromBuff(&entries_bb); BB_Writer entries_bw = BB_WriterFromBuff(&entries_bb);
@ -184,17 +184,17 @@ EmbedObj Embed(String store_name, String dir_path)
String file_data = F_DataFromFile(perm, en->file_name); String file_data = F_DataFromFile(perm, en->file_name);
// Write name // Write name
BB_WriteAlignBytes(&bw, 64); BB_WriteAlignBytes(&bbw, 64);
u64 name_start = BB_GetNumBytesWritten(&bw) + 1; u64 name_start = BB_GetNumBytesWritten(&bbw) + 1;
BB_WriteString(&bw, en->entry_name); BB_WriteString(&bbw, en->entry_name);
u64 name_len = BB_GetNumBytesWritten(&bw) - name_start; u64 name_len = BB_GetNumBytesWritten(&bbw) - name_start;
// Write data // Write data
BB_WriteAlignBytes(&bw, 64); BB_WriteAlignBytes(&bbw, 64);
// FIXME: Why no +1 here? // FIXME: Why no +1 here?
u64 data_start = BB_GetNumBytesWritten(&bw); u64 data_start = BB_GetNumBytesWritten(&bbw);
BB_WriteBytes(&bw, file_data); BB_WriteBytes(&bbw, file_data);
u64 data_len = BB_GetNumBytesWritten(&bw) - data_start; u64 data_len = BB_GetNumBytesWritten(&bbw) - data_start;
// Write entry // Write entry
BB_WriteUBits(&entries_bw, store_hash, 64); BB_WriteUBits(&entries_bw, store_hash, 64);
@ -204,8 +204,8 @@ EmbedObj Embed(String store_name, String dir_path)
BB_WriteUBits(&entries_bw, data_len, 64); BB_WriteUBits(&entries_bw, data_len, 64);
} }
arc_contents.len = BB_GetNumBytesWritten(&bw); arc_contents.len = BB_GetNumBytesWritten(&bbw);
arc_contents.text = BB_GetWrittenRaw(&bw); arc_contents.text = BB_GetWrittenRaw(&bbw);
} }
// Write archive to file // Write archive to file

View File

@ -58,6 +58,9 @@ void NET_Bootstrap(void);
//~ @hookdecl Net ops //~ @hookdecl Net ops
NET_Key NET_KeyFromString(String host, String port); NET_Key NET_KeyFromString(String host, String port);
String NET_StringFromKey(Arena *arena, NET_Key key);
b32 NET_MatchKey(NET_Key a, NET_Key b);
u64 NET_HashFromKey(NET_Key key);
NET_PipeHandle NET_AcquirePipe(void); NET_PipeHandle NET_AcquirePipe(void);

View File

@ -87,12 +87,6 @@ struct sockaddr_in6 NET_W32_AddressFromKey(NET_Key key)
return result; return result;
} }
u64 NET_W32_HashFromKey(NET_Key key)
{
u64 result = HashString(StringFromStruct(&key));
return result;
}
void NET_W32_SignalWorker(void) void NET_W32_SignalWorker(void)
{ {
i32 err = sendto( i32 err = sendto(
@ -109,7 +103,7 @@ NET_W32_Peer *NET_W32_TouchPeerFromKey(NET_W32_Pipe *pipe, NET_Key key)
{ {
// TODO: Address challenge on first receive // TODO: Address challenge on first receive
NET_W32_Peer *peer = 0; NET_W32_Peer *peer = 0;
u64 hash = NET_W32_HashFromKey(key); u64 hash = NET_HashFromKey(key);
NET_W32_PeerBin *bin = &pipe->peer_bins[hash % pipe->peer_bins_count]; NET_W32_PeerBin *bin = &pipe->peer_bins[hash % pipe->peer_bins_count];
peer = bin->first; peer = bin->first;
for (; peer; peer = peer->next_in_bin) for (; peer; peer = peer->next_in_bin)
@ -168,40 +162,71 @@ NET_Key NET_KeyFromString(String host, String port)
NET_Key result = Zi; NET_Key result = Zi;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
{ {
struct addrinfo hints = Zi;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
char *host_cstr = CstrFromString(scratch.arena, host); char *host_cstr = CstrFromString(scratch.arena, host);
char *port_cstr = CstrFromString(scratch.arena, port); i64 port_i64 = CR_IntFromString(port);
if (port_i64 < 0 || port_i64 >= Kibi(64))
{
port_i64 = 0;
}
struct sockaddr_in6 addr = Zi; struct sockaddr_in6 addr = Zi;
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port_i64);
if (InetPtonA(AF_INET6, host_cstr, &addr.sin6_addr) != 1)
{ {
struct addrinfo *first_ai = 0; IN_ADDR v4 = Zi;
if (getaddrinfo(host_cstr, port_cstr, &hints, &first_ai) == 0) if (InetPtonA(AF_INET, host_cstr, &v4) == 1)
{ {
for (struct addrinfo *ai = first_ai; ai; ai = ai->ai_next) ZeroStruct(&addr.sin6_addr);
{ addr.sin6_addr.u.Byte[10] = 0xFF;
if (ai->ai_family == AF_INET6 && ai->ai_addrlen >= sizeof(addr)) addr.sin6_addr.u.Byte[11] = 0xFF;
{ CopyBytes(&addr.sin6_addr.u.Byte[12], &v4, 4);
CopyBytes(&addr, ai->ai_addr, sizeof(addr));
break;
}
}
}
if (first_ai)
{
freeaddrinfo(first_ai);
} }
} }
result = NET_W32_KeyFromAddress(addr); result = NET_W32_KeyFromAddress(addr);
} }
EndScratch(scratch); EndScratch(scratch);
return result; return result;
} }
String NET_StringFromKey(Arena *arena, NET_Key key)
{
String result = Zi;
struct sockaddr_in6 sin6 = NET_W32_AddressFromKey(key);
char addr_chars[INET6_ADDRSTRLEN];
u32 port = ntohs(sin6.sin6_port);
if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr))
{
struct in_addr v4 = Zi;
CopyBytes(&v4, &sin6.sin6_addr.s6_addr[12], sizeof(v4));
if (InetNtopA(AF_INET, &v4, addr_chars, (DWORD)sizeof(addr_chars)))
{
result = StringF(arena, "%F:%F", FmtString(StringFromCstr(addr_chars, countof(addr_chars))), FmtUint(port));
}
}
else
{
if (InetNtopA(AF_INET6, &sin6.sin6_addr, addr_chars, (DWORD)sizeof(addr_chars)))
{
result = StringF(arena, "[%F]:%F", FmtString(StringFromCstr(addr_chars, countof(addr_chars))), FmtUint(port));
}
}
return result;
}
b32 NET_MatchKey(NET_Key a, NET_Key b)
{
return MatchStruct(&a, &b);
}
u64 NET_HashFromKey(NET_Key key)
{
u64 result = HashString(StringFromStruct(&key));
return result;
}
NET_PipeHandle NET_AcquirePipe(void) NET_PipeHandle NET_AcquirePipe(void)
{ {
Arena *perm = PermArena(); Arena *perm = PermArena();
@ -432,7 +457,7 @@ void NET_W32_TickForever(WaveLaneCtx *lane)
hints.ai_family = AF_INET6; hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol= IPPROTO_UDP; hints.ai_protocol= IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
struct addrinfo *ai = 0; struct addrinfo *ai = 0;
if (ok) if (ok)
{ {
@ -772,11 +797,11 @@ void NET_W32_TickForever(WaveLaneCtx *lane)
msg_data.text = ArenaNext(msg_buff->arena, u8); msg_data.text = ArenaNext(msg_buff->arena, u8);
msg_data.len = 0; msg_data.len = 0;
LogSuccessF( // LogSuccessF(
"Assembled msg with msg seq: %F, data (%F bytes)", // "Assembled msg with msg seq: %F, data (%F bytes)",
FmtSint(packet->msg_seq), // FmtSint(packet->msg_seq),
FmtUint(msg->data.len) // FmtUint(msg->data.len)
); // );
} }
} }
else else

View File

@ -178,7 +178,6 @@ NET_W32_DummySocket NET_W32_CreateDummySocket(void);
NET_W32_Pipe *NET_W32_PipeFromHandle(NET_PipeHandle pipe_handle); NET_W32_Pipe *NET_W32_PipeFromHandle(NET_PipeHandle pipe_handle);
NET_Key NET_W32_KeyFromAddress(struct sockaddr_in6 addr); NET_Key NET_W32_KeyFromAddress(struct sockaddr_in6 addr);
struct sockaddr_in6 NET_W32_AddressFromKey(NET_Key key); struct sockaddr_in6 NET_W32_AddressFromKey(NET_Key key);
u64 NET_W32_HashFromKey(NET_Key key);
void NET_W32_SignalWorker(void); void NET_W32_SignalWorker(void);
NET_W32_Peer *NET_W32_TouchPeerFromKey(NET_W32_Pipe *pipe, NET_Key key); NET_W32_Peer *NET_W32_TouchPeerFromKey(NET_W32_Pipe *pipe, NET_Key key);
u32 NET_W32_ChecksumFromString(String str); u32 NET_W32_ChecksumFromString(String str);

File diff suppressed because it is too large Load Diff

View File

@ -1,318 +0,0 @@
////////////////////////////////////////////////////////////
//~ Channel ID
Struct(N_ChannelId)
{
u32 gen;
u32 idx;
};
////////////////////////////////////////////////////////////
//~ Host command types
Enum(N_CmdKind)
{
N_CmdKind_None,
N_CmdKind_TryConnect,
N_CmdKind_ConnectSuccess,
N_CmdKind_Disconnect,
N_CmdKind_Heartbeat,
N_CmdKind_Write
};
Enum(N_WriteFlag)
{
N_WriteFlag_None = 0,
N_WriteFlag_Reliable = (1 << 0)
};
Struct(N_Cmd)
{
N_CmdKind kind;
N_ChannelId channel_id;
u16 heartbeat_id;
u16 heartbeat_ack_id;
b32 write_reliable;
String write_msg;
N_Cmd *next;
};
////////////////////////////////////////////////////////////
//~ Event types
Enum(N_EventKind)
{
N_EventKind_None,
N_EventKind_ChannelOpened,
N_EventKind_ChannelClosed,
N_EventKind_Msg
};
Struct(N_Event)
{
N_EventKind kind;
N_ChannelId channel_id;
String msg;
N_Event *next;
};
Struct(N_EventList)
{
N_Event *first;
N_Event *last;
};
Struct(N_ChannelLookupBin)
{
struct N_Channel *first;
struct N_Channel *last;
};
////////////////////////////////////////////////////////////
//~ Packet types
#define N_PacketMagic 0xd9e3b8b6
#define N_MaxPacketChunkLen 1024
#define N_MaxPacketLen 1280 // Give enough space for msg chunk + header
Enum(N_PacketKind)
{
N_PacketKind_None,
N_PacketKind_TryConnect,
N_PacketKind_ConnectSuccess,
N_PacketKind_Disconnect,
N_PacketKind_Heartbeat,
N_PacketKind_MsgChunk
};
Enum(N_PacketFlag)
{
N_PacketFlag_None = 0,
N_PacketFlag_Reliable = (1 << 0)
};
Struct(N_SndPacket)
{
N_SndPacket *next;
u64 seq;
u64 data_len;
u8 data[N_MaxPacketLen];
};
Struct(N_RcvPacket)
{
PLT_Sock *sock;
PLT_Address address;
String data;
N_RcvPacket *next;
};
Struct(N_RcvBuffer)
{
Arena *arena;
N_RcvPacket *first_packet;
N_RcvPacket *last_packet;
};
////////////////////////////////////////////////////////////
//~ Channel types
Struct(N_Channel)
{
N_ChannelId id;
b32 valid;
b32 connected;
struct N_Host *host;
N_Channel *next_free;
PLT_Address address;
u64 address_hash;
N_Channel *next_address_hash;
N_Channel *prev_address_hash;
// NOTE: Packets are allocated in host's `arena`
N_SndPacket *first_reliable_packet;
N_SndPacket *last_reliable_packet;
N_SndPacket *first_unreliable_packet;
N_SndPacket *last_unreliable_packet;
u64 num_reliable_packets;
u64 num_unreliable_packets;
// NOTE: Msg assemblers are allocated in host's `arena`
struct N_MsgAssembler *least_recent_msg_assembler;
struct N_MsgAssembler *most_recent_msg_assembler;
u16 last_heartbeat_received_id;
u16 last_heartbeat_acked_id;
i64 last_heartbeat_acked_ns;
i64 last_heartbeat_rtt_ns;
u64 last_sent_msg_id;
u64 their_acked_seq;
u64 our_acked_seq;
u64 last_sent_seq;
i64 last_packet_received_ns;
};
Struct(N_ChannelNode)
{
N_Channel *channel;
N_ChannelNode *next;
};
Struct(N_ChannelList)
{
N_ChannelNode *first;
N_ChannelNode *last;
};
////////////////////////////////////////////////////////////
//~ Message asssembler types
Struct(N_MsgAssembler)
{
N_Channel *channel;
b32 is_reliable;
// Free list
N_MsgAssembler *next_free;
// Bucket list
N_MsgAssembler *next_hash;
N_MsgAssembler *prev_hash;
// Channel list
N_MsgAssembler *less_recent;
N_MsgAssembler *more_recent;
u64 msg_id;
u64 hash;
u64 last_chunk_len;
u64 num_chunks_total;
u64 num_chunks_received;
i64 touched_ns;
BuddyBlock *buddy_block;
u8 *chunk_bitmap;
u8 *chunk_data;
};
Struct(N_MsgAssemblerLookupBin)
{
N_MsgAssembler *first;
N_MsgAssembler *last;
};
////////////////////////////////////////////////////////////
//~ Host types
#define N_NumChannelLookupBins 512
#define N_NumMsgAssemblerLookupBins 16384
Struct(N_Host)
{
Arena *arena;
PLT_Sock *sock;
BuddyCtx *buddy; // For storing msg assembler data
Arena *cmd_arena;
N_Cmd *first_cmd;
N_Cmd *last_cmd;
N_Cmd *first_free_cmd;
Arena *channel_arena;
N_Channel *channels;
N_Channel *first_free_channel;
u64 num_channels_reserved;
N_SndPacket *first_free_packet; // Acquired in `arena`
N_MsgAssembler *first_free_msg_assembler; // Acquired in `arena`
N_ChannelLookupBin *channel_lookup_bins; // Acquired in `arena`
u64 num_channel_lookup_bins;
N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; // Acquired in `arena`
u64 num_msg_assembler_lookup_bins;
// Double buffer for incoming data
Mutex rcv_buffer_write_mutex;
N_RcvBuffer *rcv_buffer_read;
N_RcvBuffer *rcv_buffer_write;
u64 bytes_received;
u64 bytes_sent;
};
////////////////////////////////////////////////////////////
//~ Nil constants
Readonly Global N_Channel N_nil_channel = { .valid = 0 };
////////////////////////////////////////////////////////////
//~ Host initialization
N_Host *N_AcquireHost(u16 listen_port);
void N_ReleaseHost(N_Host *host);
////////////////////////////////////////////////////////////
//~ Channel
#define N_NilChannelId (N_ChannelId) { .gen = 0, .idx = 0 }
#define N_AllChannelsId (N_ChannelId) { .gen = U32Max, .idx = U32Max }
#define N_MatchChannelId(a, b) ((a).gen == (b).gen && (a).idx == (b).idx)
#define N_IsChannelIdNil(v) ((v).gen == 0 && (v).idx == 0)
u64 N_HashFromAddress(PLT_Address address);
N_Channel *N_ChannelFromAddress(N_Host *host, PLT_Address address);
N_Channel *N_ChannelFromId(N_Host *host, N_ChannelId channel_id);
N_ChannelList N_ChannelsFromId(Arena *arena, N_Host *host, N_ChannelId channel_id);
N_Channel *N_AcquireChannel(N_Host *host, PLT_Address address);
void N_ReleaseChannel(N_Channel *channel);
////////////////////////////////////////////////////////////
//~ Message assembler
u64 N_HashFromMsg(N_ChannelId channel_id, u64 msg_id);
N_MsgAssembler *N_MsgAssemblerFromMsg(N_Host *host, N_ChannelId channel_id, u64 msg_id);
N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_count, u64 now_ns, b32 is_reliable);
void N_ReleaseMessageAssembler(N_MsgAssembler *ma);
void N_TouchMessageAssembler(N_MsgAssembler *ma, i64 now_ns);
b32 N_IsChunkFilled(N_MsgAssembler *ma, u64 chunk_id);
void N_MarkChunkReceived(N_MsgAssembler *ma, u64 chunk_id);
////////////////////////////////////////////////////////////
//~ Packet
N_SndPacket *N_PushSndPacket(N_Channel *channel, b32 is_reliable);
////////////////////////////////////////////////////////////
//~ Host command
N_Cmd *N_PushCmd(N_Host *host);
void N_Connect(N_Host *host, PLT_Address connect_address);
void N_Disconnect(N_Host *host, N_ChannelId channel_id);
void N_Write(N_Host *host, N_ChannelId channel_id, String msg, N_WriteFlag flags);
////////////////////////////////////////////////////////////
//~ Channel info
i64 N_GetChannelLastRttNs(N_Host *host, N_ChannelId channel_id);
////////////////////////////////////////////////////////////
//~ Update
N_Event *N_PushEvent(Arena *arena, N_EventList *list);
N_EventList N_BeginUpdate(Arena *arena, N_Host *host);
void N_EndUpdate(N_Host *host);

View File

@ -1,16 +0,0 @@
@Layer net_old
//////////////////////////////
//- Dependencies
@Dep platform
//////////////////////////////
//- Api
@IncludeC net.h
//////////////////////////////
//- Impl
@IncludeC net.c

View File

@ -307,34 +307,24 @@ Enum(P_MsgKind)
P_MsgKind_None, P_MsgKind_None,
// User -> sim // User -> sim
P_MsgKind_UserSnapshot, // P_MsgKind_UserSnapshot,
P_MsgKind_SaveWorld, P_MsgKind_SaveWorld,
P_MsgKind_ResetWorld, P_MsgKind_ResetWorld,
P_MsgKind_TileEdit, P_MsgKind_TileEdit,
P_MsgKind_EntEdit, P_MsgKind_EntEdit,
// Sim -> user // Sim -> user
P_MsgKind_SimSnapshot, // P_MsgKind_SimSnapshot,
P_MsgKind_Tiles, P_MsgKind_Tiles,
}; };
Struct(P_Msg) Struct(P_Msg)
{ {
//- In
P_Key dst_user; // If dst is 0, then cmd is meant to be broadcast
b32 burst;
//- Out
P_Key src_user;
//- In / Out
P_MsgKind kind; P_MsgKind kind;
NET_Key dst;
P_UserSnapshot user_snapshot; // P_UserSnapshot user_snapshot;
P_SimSnapshot sim_snapshot; // P_SimSnapshot sim_snapshot;
P_TileKind tile_kind; P_TileKind tile_kind;
Rng2I32 tile_range; Rng2I32 tile_range;

View File

@ -1,10 +1,20 @@
S_Ctx S = Zi; S_Ctx S = Zi;
Readonly S_Client S_NilClient = {
.next = &S_NilClient,
.prev = &S_NilClient,
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Bootstrap //~ Bootstrap
void S_Bootstrap(void) void S_Bootstrap(void)
{ {
Arena *perm = PermArena();
S.client_bins_count = Kibi(4);
S.client_bins = PushStructsNoZero(perm, S_ClientBin, S.client_bins_count);
DispatchWave(Lit("Sim"), 1, S_TickForever, 0); DispatchWave(Lit("Sim"), 1, S_TickForever, 0);
OnExit(S_Shutdown); OnExit(S_Shutdown);
} }
@ -15,6 +25,30 @@ void S_Shutdown(void)
YieldOnFence(&S.shutdown_fence, 1); YieldOnFence(&S.shutdown_fence, 1);
} }
////////////////////////////////////////////////////////////
//~ Helpers
b32 S_IsClientNil(S_Client *client)
{
return client == 0 || client == &S_NilClient;
}
S_Client *S_ClientFromNetKey(NET_Key key)
{
S_Client *result = &S_NilClient;
u64 hash = NET_HashFromKey(key);
S_ClientBin *bin = &S.client_bins[hash % S.client_bins_count];
for (S_Client *client = bin->first; client; client = client->next_in_bin)
{
if (client->hash == hash)
{
result = client;
break;
}
}
return result;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Sim tick //~ Sim tick
@ -31,9 +65,8 @@ void S_TickForever(WaveLaneCtx *lane)
b32 has_sent_initial_tick = 0; b32 has_sent_initial_tick = 0;
NET_PipeHandle net_pipe = NET_AcquirePipe(); NET_PipeHandle net_pipe = NET_AcquirePipe();
BB_Buff packer_bb = BB_AcquireDynamicBuff(Gibi(64));
BB_Writer packer_bbw = BB_WriterFromBuff(&packer_bb);
@ -128,33 +161,110 @@ void S_TickForever(WaveLaneCtx *lane)
u64 port = 22121; u64 port = 22121;
NET_Bind(net_pipe, port); NET_Bind(net_pipe, port);
P_MsgList in_msgs = Zi; P_MsgList in_msgs = Zi;
{ {
NET_MsgList net_msgs = NET_Swap(frame_arena, net_pipe); NET_MsgList net_msgs = NET_Swap(frame_arena, net_pipe);
for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next) for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next)
{ {
NET_Key net_key = net_msg->sender;
String address_str = NET_StringFromKey(frame_arena, net_key);
LogDebugF("Received message from client \"%F\"", FmtString(address_str));
// Create client
S_Client *client = S_ClientFromNetKey(net_key);
if (S_IsClientNil(client))
{
u64 hash = NET_HashFromKey(net_key);
S_ClientBin *bin = &S.client_bins[hash % S.client_bins_count];
// FIXME: Freelist client
client = PushStruct(perm, S_Client);
client->hash = hash;
client->net_key = net_key;
DllQueuePushNPZ(&S_NilClient, S.first_client, S.last_client, client, next, prev);
DllQueuePushNP(bin->first, bin->last, client, next_in_bin, prev_in_bin);
}
String packed = net_msg->data; String packed = net_msg->data;
P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
P_Msg *dst_msg = &dst_msg_node->msg;
*dst_msg = P_UnpackMsg(frame_arena, packed);
// FIXME: Set src user here based on net key
// dst_msg->src_user =
DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
++in_msgs.count;
P_MsgList client_msgs = P_UnpackMessages(frame_arena, packed);
// FIXME: Set src user here based on net key (or maybe just attach net key to msg instead of user)
// { if (client_msgs.first)
// LogDebugF( {
// "Server received msg (%F bytes): \"%F\"", if (in_msgs.last)
// FmtUint(packed.len), {
// FmtString(packed) in_msgs.last->next = client_msgs.first;
// ); }
// } else
{
in_msgs.first = client_msgs.first;
}
client_msgs.first->prev = in_msgs.last;
in_msgs.last = client_msgs.last;
in_msgs.count += client_msgs.count;
}
} }
} }
// P_MsgList in_msgs = Zi;
// {
// NET_MsgList net_msgs = NET_Swap(frame_arena, net_pipe);
// for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next)
// {
// NET_Key net_key = net_msg->sender;
// String address_str = NET_StringFromKey(frame_arena, net_key);
// LogDebugF("Received message from client \"%F\"", FmtString(address_str));
// NET_Push(net_pipe, net_key, Lit("HIII"), 0);
// String packed = net_msg->data;
// P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
// P_Msg *dst_msg = &dst_msg_node->msg;
// *dst_msg = P_UnpackMsg(frame_arena, packed);
// // FIXME: Set src user here based on net key
// // dst_msg->src_user =
// DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
// ++in_msgs.count;
// // {
// // LogDebugF(
// // "Server received msg (%F bytes): \"%F\"",
// // FmtUint(packed.len),
// // FmtString(packed)
// // );
// // }
// }
// }
////////////////////////////// //////////////////////////////
//- Process connection messages //- Process connection messages
@ -238,17 +348,6 @@ void S_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Apply user snapshots //- Apply user snapshots
for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
{
P_Msg *msg = &msg_node->msg;
if (msg->kind == P_MsgKind_UserSnapshot)
{
}
}
// P_MsgList user_msgs = Zi; // P_MsgList user_msgs = Zi;
// { // {
// i64 user_msgs_min_tick = world_frame->tick + user_msg_tick_range.min; // i64 user_msgs_min_tick = world_frame->tick + user_msg_tick_range.min;
@ -323,63 +422,63 @@ void S_TickForever(WaveLaneCtx *lane)
// FIXME: Only accept edits from privileged users // FIXME: Only accept edits from privileged users
// { {
// b32 should_save = 0; b32 should_save = 0;
// for (P_MsgNode *msg_node = user_msgs.first; msg_node; msg_node = msg_node->next) for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
// { {
// P_Msg *msg = &msg_node->msg; P_Msg *msg = &msg_node->msg;
// b32 allow = 0; b32 allow = 0;
// if (msg->kind == P_MsgKind_SaveWorld) if (msg->kind == P_MsgKind_SaveWorld)
// { {
// // FIXME: Only accept save from local user // FIXME: Only accept save from local user
// should_save = 1; should_save = 1;
// } }
// if (msg->kind == P_MsgKind_ResetWorld) if (msg->kind == P_MsgKind_ResetWorld)
// { {
// // TODO: Real reset // TODO: Real reset
// for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
// { {
// ent->exists = 0; ent->exists = 0;
// } }
// } }
// if (msg->kind == P_MsgKind_EntEdit) if (msg->kind == P_MsgKind_EntEdit)
// { {
// P_EntList ents = Zi; P_EntList ents = Zi;
// P_Ent *dst = P_PushTempEnt(frame_arena, &ents); P_Ent *dst = P_PushTempEnt(frame_arena, &ents);
// *dst = msg->ent; *dst = msg->ent;
// P_SpawnEntsFromList(world_frame, ents); P_SpawnEntsFromList(world_frame, ents);
// } }
// if (msg->kind == P_MsgKind_TileEdit) if (msg->kind == P_MsgKind_TileEdit)
// { {
// P_TileKind tile = msg->tile_kind; P_TileKind tile = msg->tile_kind;
// Rng2I32 range = msg->tile_range; Rng2I32 range = msg->tile_range;
// for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y) for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
// { {
// for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x) for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
// { {
// Vec2 tile_pos = VEC2(tile_x, tile_y); Vec2 tile_pos = VEC2(tile_x, tile_y);
// i32 tile_idx = P_TileIdxFromTilePos(tile_pos); i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
// world->tiles[tile_idx] = (u8)tile; world->tiles[tile_idx] = (u8)tile;
// } }
// } }
// // Hash tiles // Hash tiles
// { {
// u64 old_tiles_hash = world->tiles_hash; u64 old_tiles_hash = world->tiles_hash;
// world->tiles_hash = HashString(STRING(P_TilesCount, world->tiles)); world->tiles_hash = HashString(STRING(P_TilesCount, world->tiles));
// if (world->tiles_hash != old_tiles_hash) if (world->tiles_hash != old_tiles_hash)
// { {
// tiles_dirty = 1; tiles_dirty = 1;
// } }
// } }
// } }
// } }
// // Save world // Save world
// if (should_save) if (should_save)
// { {
// String path = Lit("..."); String path = Lit("...");
// LogInfoF("Saving world to %F", FmtString(path)); LogInfoF("Saving world to %F", FmtString(path));
// } }
// } }
////////////////////////////// //////////////////////////////
//- Update ent controls //- Update ent controls
@ -414,22 +513,22 @@ void S_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Push tile messages //- Push tile messages
// if (tiles_dirty) {
// { // TODO: Receive remote tile hashes via user snapshots
// P_Msg *msg = 0; for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next)
// { {
// P_MsgNode *msg_node = PushStruct(frame_arena, P_MsgNode); if (tiles_dirty || client->remote_tiles_hash != world->tiles_hash)
// DllQueuePush(output->msgs.first, output->msgs.last, msg_node); {
// ++output->msgs.count; P_Msg *msg = P_PushMsg(P_MsgKind_Tiles, Zstr);
// msg = &msg_node->msg; msg->kind = P_MsgKind_Tiles;
// } msg->tiles_hash = world->tiles_hash;
// msg->kind = P_MsgKind_Tiles; msg->tile_range = RNG2I32(VEC2I32(0, 0), VEC2I32(P_TilesPitch, P_TilesPitch));
// msg->tiles_hash = world->tiles_hash; msg->dst = client->net_key;
// msg->raw_tiles = PushStructsNoZero(frame_arena, u8, P_TilesCount); msg->data = STRING(P_TilesCount, world->tiles);
// msg->tile_range = RNG2I32(VEC2I32(0, 0), VEC2I32(P_TilesPitch, P_TilesPitch)); client->remote_tiles_hash = world->tiles_hash;
// CopyBytes(msg->raw_tiles, world->tiles, P_TilesCount); }
// has_sent_initial_tick = 1; }
// } }
////////////////////////////// //////////////////////////////
//- Push snapshot messages //- Push snapshot messages
@ -486,35 +585,151 @@ void S_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Send messages //- Send messages
for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
{ {
P_Msg *msg = &msg_node->msg; // Group messages by client
if (P_IsKeyNil(msg->dst_user)) for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
{ {
// Broadcast P_Msg *msg = &msg_node->msg;
String packed = P_PackMessage(frame_arena, msg); if (NET_IsKeyNil(msg->dst))
for (P_Ent *user = P_FirstEnt(world_frame); !P_IsEntNil(user); user = P_NextEnt(user))
{ {
if (user->is_user) // Broadcast msg
for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next)
{ {
NET_Push(net_pipe, user->net, packed, msg->burst); P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
*dst_msg_node = *msg_node;
DllQueuePush(client->out_msgs.first, client->out_msgs.last, dst_msg_node);
++client->out_msgs.count;
}
}
else
{
// Targeted msg
S_Client *client = S_ClientFromNetKey(msg->dst);
if (!S_IsClientNil(client))
{
P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
*dst_msg_node = *msg_node;
DllQueuePush(client->out_msgs.first, client->out_msgs.last, dst_msg_node);
++client->out_msgs.count;
} }
} }
} }
else
// Send messages to clients
for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next)
{ {
P_Ent *user = P_EntFromKey(world_frame, msg->dst_user); P_MsgList msgs = client->out_msgs;
if (!NET_IsKeyNil(user->net)) if (msgs.count > 0)
{ {
String packed = P_PackMessage(frame_arena, msg); String packed = P_PackMessages(&packer_bbw, msgs);
NET_Push(net_pipe, user->net, packed, msg->burst); NET_Push(net_pipe, client->net_key, packed, 0);
ZeroStruct(&client->out_msgs);
} }
} }
ResetArena(P_tl.out_msgs_arena);
ZeroStruct(&P_tl.out_msgs);
} }
// {
// // Group messages by client
// for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// if (NET_IsKeyNil(msg->dst))
// {
// // Broadcast msg
// for (S_Client *client = S.first_client; client; client = client->next)
// {
// P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
// *dst_msg_node = *msg_node;
// DllQueuePush(client->out_msgs.first, client->out_msgs.last, dst_msg_node);
// ++client->out_msgs.count;
// }
// }
// else
// {
// // Targeted msg
// S_Client client = S_ClientFromNetKey(msg->dst);
// if (!S_IsClientNil(client))
// {
// }
// }
// }
// for (S_Client *client = first_client; client; client = client->next)
// {
// }
// }
// for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// if (P_IsKeyNil(msg->dst_user))
// {
// // Broadcast
// String packed = P_PackMessage(frame_arena, msg);
// for (P_Ent *user = P_FirstEnt(world_frame); !P_IsEntNil(user); user = P_NextEnt(user))
// {
// if (user->is_user)
// {
// NET_Push(net_pipe, user->net, packed, msg->burst);
// }
// }
// }
// else
// {
// P_Ent *user = P_EntFromKey(world_frame, msg->dst_user);
// if (!NET_IsKeyNil(user->net))
// {
// String packed = P_PackMessage(frame_arena, msg);
// NET_Push(net_pipe, user->net, packed, msg->burst);
// }
// }
// }
// for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// if (P_IsKeyNil(msg->dst_user))
// {
// // Broadcast
// String packed = P_PackMessage(frame_arena, msg);
// for (P_Ent *user = P_FirstEnt(world_frame); !P_IsEntNil(user); user = P_NextEnt(user))
// {
// if (user->is_user)
// {
// NET_Push(net_pipe, user->net, packed, msg->burst);
// }
// }
// }
// else
// {
// P_Ent *user = P_EntFromKey(world_frame, msg->dst_user);
// if (!NET_IsKeyNil(user->net))
// {
// String packed = P_PackMessage(frame_arena, msg);
// NET_Push(net_pipe, user->net, packed, msg->burst);
// }
// }
// }
// // TODO: Only copy active entities // // TODO: Only copy active entities
// LockTicketMutex(&P.sim_output_back_tm); // LockTicketMutex(&P.sim_output_back_tm);
// { // {

View File

@ -1,3 +1,26 @@
////////////////////////////////////////////////////////////
//~ Client types
Struct(S_Client)
{
S_Client *next;
S_Client *prev;
S_Client *next_in_bin;
S_Client *prev_in_bin;
u64 hash;
NET_Key net_key;
P_MsgList out_msgs;
u64 remote_tiles_hash;
};
Struct(S_ClientBin)
{
S_Client *first;
S_Client *last;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ State types //~ State types
@ -5,9 +28,16 @@ Struct(S_Ctx)
{ {
Atomic32 shutdown; Atomic32 shutdown;
Fence shutdown_fence; Fence shutdown_fence;
S_Client *first_client;
S_Client *last_client;
i64 client_bins_count;
S_ClientBin *client_bins;
}; };
extern S_Ctx S; extern S_Ctx S;
extern Readonly S_Client S_NilClient;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Bootstrap //~ Bootstrap
@ -15,6 +45,13 @@ extern S_Ctx S;
void S_Bootstrap(void); void S_Bootstrap(void);
void S_Shutdown(void); void S_Shutdown(void);
////////////////////////////////////////////////////////////
//~ Helpers
b32 S_IsClientNil(S_Client *client);
S_Client *S_ClientFromNetKey(NET_Key key);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Sim tick //~ Sim tick

View File

@ -198,16 +198,49 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Message //~ Message
String P_PackMessage(Arena *arena, P_Msg *msg) String P_PackMessages(BB_Writer *bbw, P_MsgList msgs)
{ {
u64 pos_start = BB_GetNumBytesWritten(bbw);
{
for (P_MsgNode *msg_node = msgs.first; msg_node; msg_node = msg_node->next)
{
// TODO: Compress
P_Msg *msg = &msg_node->msg;
BB_WriteBytes(bbw, StringFromStruct(msg));
BB_WriteString(bbw, msg->data);
}
}
u64 pos_end = BB_GetNumBytesWritten(bbw);
String result = Zi; String result = Zi;
// TODO result.text = BB_GetWrittenRaw(bbw) + pos_start;
result.len = pos_end - pos_start;
return result; return result;
} }
P_Msg P_UnpackMsg(Arena *arena, String packed) P_MsgList P_UnpackMessages(Arena *arena, String packed)
{ {
P_Msg result = Zi; P_MsgList result = Zi;
// TODO BB_Buff bb = BB_BuffFromString(packed);
BB_Reader bbr = BB_ReaderFromBuff(&bb);
b32 done = 0;
while (!done)
{
u8 *msg_raw = BB_ReadBytesRaw(&bbr, sizeof(P_Msg));
if (msg_raw != 0)
{
// Read msg header
P_MsgNode *dst_msg_node = PushStruct(arena, P_MsgNode);
CopyStruct(&dst_msg_node->msg, msg_raw);
DllQueuePush(result.first, result.last, dst_msg_node);
result.count += 1;
// Read msg data string
String data_str = BB_ReadString(arena, &bbr);
dst_msg_node->msg.data = data_str;
}
else
{
done = 1;
}
}
return result; return result;
} }

View File

@ -32,5 +32,5 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Message //~ Message
String P_PackMessage(Arena *arena, P_Msg *msg); String P_PackMessages(BB_Writer *bbw, P_MsgList msgs);
P_Msg P_UnpackMsg(Arena *arena, String packed); P_MsgList P_UnpackMessages(Arena *arena, String packed);

View File

@ -346,6 +346,8 @@ void V_TickForever(WaveLaneCtx *lane)
const f32 meters_per_draw_width = 18; const f32 meters_per_draw_width = 18;
NET_PipeHandle net_pipe = NET_AcquirePipe(); NET_PipeHandle net_pipe = NET_AcquirePipe();
BB_Buff packer_bb = BB_AcquireDynamicBuff(Gibi(64));
BB_Writer packer_bbw = BB_WriterFromBuff(&packer_bb);
////////////////////////////// //////////////////////////////
//- Init vis state //- Init vis state
@ -563,46 +565,46 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
//- Init bitbuff //- Init bitbuff
BB_Buff bb = Zi; BB_Buff bb = Zi;
BB_Writer bw = Zi; BB_Writer bbw = Zi;
BB_Reader br = Zi; BB_Reader bbr = Zi;
if (swapout) if (swapout)
{ {
u64 max_size = Mebi(64); u64 max_size = Mebi(64);
u8 *bytes = PushStructsNoZero(frame->arena, u8, max_size); u8 *bytes = PushStructsNoZero(frame->arena, u8, max_size);
bb = BB_BuffFromString(STRING(max_size, bytes)); bb = BB_BuffFromString(STRING(max_size, bytes));
bw = BB_WriterFromBuff(&bb); bbw = BB_WriterFromBuff(&bb);
} }
else else
{ {
String swap_encoded = SwappedStateFromName(frame->arena, Lit("pp_vis.swp")); String swap_encoded = SwappedStateFromName(frame->arena, Lit("pp_vis.swp"));
bb = BB_BuffFromString(swap_encoded); bb = BB_BuffFromString(swap_encoded);
br = BB_ReaderFromBuff(&bb); bbr = BB_ReaderFromBuff(&bb);
} }
//- Transcode swap state //- Transcode swap state
if (swapout) if (swapout)
{ {
BB_WriteUBits(&bw, V.user_key.v, 64); BB_WriteUBits(&bbw, V.user_key.v, 64);
BB_WriteBit(&bw, prev_frame->is_editing); BB_WriteBit(&bbw, prev_frame->is_editing);
BB_WriteF32(&bw, prev_frame->edit_camera_pos.x); BB_WriteF32(&bbw, prev_frame->edit_camera_pos.x);
BB_WriteF32(&bw, prev_frame->edit_camera_pos.y); BB_WriteF32(&bbw, prev_frame->edit_camera_pos.y);
BB_WriteF32(&bw, prev_frame->edit_camera_zoom); BB_WriteF32(&bbw, prev_frame->edit_camera_zoom);
BB_WriteString(&bw, prev_frame->window_restore); BB_WriteString(&bbw, prev_frame->window_restore);
} }
else else
{ {
V.user_key.v = BB_ReadUBits(&br, 64); V.user_key.v = BB_ReadUBits(&bbr, 64);
frame->is_editing = BB_ReadBit(&br); frame->is_editing = BB_ReadBit(&bbr);
frame->edit_camera_pos.x = BB_ReadF32(&br); frame->edit_camera_pos.x = BB_ReadF32(&bbr);
frame->edit_camera_pos.y = BB_ReadF32(&br); frame->edit_camera_pos.y = BB_ReadF32(&bbr);
frame->edit_camera_zoom = BB_ReadF32(&br); frame->edit_camera_zoom = BB_ReadF32(&bbr);
frame->window_restore = BB_ReadString(frame->arena, &br); frame->window_restore = BB_ReadString(frame->arena, &bbr);
} }
//- Write swapout //- Write swapout
if (swapout) if (swapout)
{ {
WriteSwappedState(Lit("pp_vis.swp"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw))); WriteSwappedState(Lit("pp_vis.swp"), STRING(BB_GetNumBytesWritten(&bbw), BB_GetWrittenRaw(&bbw)));
} }
} }
} }
@ -2655,25 +2657,84 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Pop messages from sim //- Pop messages from sim
// FIXME: Reject messages if not from currently connected sim // FIXME: Reject messages if not from currently connected sim
P_MsgList in_msgs = Zi; P_MsgList in_msgs = Zi;
{ {
NET_Bind(net_pipe, 0); NET_Bind(net_pipe, 0);
NET_MsgList net_msgs = NET_Swap(frame->arena, net_pipe); NET_MsgList net_msgs = NET_Swap(frame->arena, net_pipe);
for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next) for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next)
{ {
NET_Key net_key = net_msg->sender;
String address_str = NET_StringFromKey(frame->arena, net_key);
LogDebugF("Received message from server \"%F\"", FmtString(address_str));
String packed = net_msg->data; String packed = net_msg->data;
P_MsgNode *dst_msg_node = PushStruct(frame->arena, P_MsgNode);
P_Msg *dst_msg = &dst_msg_node->msg; P_MsgList server_msgs = P_UnpackMessages(frame->arena, packed);
*dst_msg = P_UnpackMsg(frame->arena, packed); if (server_msgs.first)
// FIXME: Set src user here based on net key {
// dst_msg->src_user = if (in_msgs.last)
DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node); {
++in_msgs.count; in_msgs.last->next = server_msgs.first;
}
else
{
in_msgs.first = server_msgs.first;
}
server_msgs.first->prev = in_msgs.last;
in_msgs.last = server_msgs.last;
in_msgs.count += server_msgs.count;
}
} }
} }
// P_MsgList in_msgs = Zi;
// {
// NET_Bind(net_pipe, 0);
// NET_MsgList net_msgs = NET_Swap(frame->arena, net_pipe);
// for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next)
// {
// NET_Key net_key = net_msg->sender;
// String address_str = NET_StringFromKey(frame->arena, net_key);
// LogDebugF("Received message from server \"%F\"", FmtString(address_str));
// String packed = net_msg->data;
// P_MsgNode *dst_msg_node = PushStruct(frame->arena, P_MsgNode);
// P_Msg *dst_msg = &dst_msg_node->msg;
// *dst_msg = P_UnpackMsg(frame->arena, packed);
// // FIXME: Set src user here based on net key
// // dst_msg->src_user =
// DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
// ++in_msgs.count;
// }
// }
// { // {
// LockTicketMutex(&P.s2u_snapshot_mutex); // LockTicketMutex(&P.s2u_snapshot_mutex);
// P_SimSnapshot *src_snapshot = &P.s2u_snapshot; // P_SimSnapshot *src_snapshot = &P.s2u_snapshot;
@ -2724,13 +2785,13 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
P_Msg *msg = &msg_node->msg; P_Msg *msg = &msg_node->msg;
if (msg->kind == P_MsgKind_SimSnapshot && msg->sim_snapshot.tick > sim_world->last_frame->tick) // if (msg->kind == P_MsgKind_SimSnapshot && msg->sim_snapshot.tick > sim_world->last_frame->tick)
{ // {
if (!newest_snapshot_msg || msg->sim_snapshot.tick > newest_snapshot_msg->sim_snapshot.tick) // if (!newest_snapshot_msg || msg->sim_snapshot.tick > newest_snapshot_msg->sim_snapshot.tick)
{ // {
newest_snapshot_msg = msg; // newest_snapshot_msg = msg;
} // }
} // }
//- Chat //- Chat
// if (msg->kind == P_MsgKind_Chat) // if (msg->kind == P_MsgKind_Chat)
@ -2769,50 +2830,50 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Apply sim snapshot //- Apply sim snapshot
if (newest_snapshot_msg) // if (newest_snapshot_msg)
{ // {
P_SimSnapshot *snapshot = &newest_snapshot_msg->sim_snapshot; // P_SimSnapshot *snapshot = &newest_snapshot_msg->sim_snapshot;
P_Frame *src_frame = P_FrameFromTick(sim_world, snapshot->src_tick); // P_Frame *src_frame = P_FrameFromTick(sim_world, snapshot->src_tick);
P_Frame *dst_frame = P_PushFrame(sim_world, src_frame, snapshot->tick); // P_Frame *dst_frame = P_PushFrame(sim_world, src_frame, snapshot->tick);
sim_world->seed = snapshot->world_seed; // sim_world->seed = snapshot->world_seed;
dst_frame->time_ns = snapshot->time_ns; // dst_frame->time_ns = snapshot->time_ns;
//- Apply deltas // //- Apply deltas
for (P_SimDeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next) // for (P_SimDeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
{ // {
P_SimDelta *delta = &dn->delta; // P_SimDelta *delta = &dn->delta;
//- Raw ent // //- Raw ent
if (delta->kind == P_SimDeltaKind_RawEnt) // if (delta->kind == P_SimDeltaKind_RawEnt)
{ // {
P_Ent tmp_ent = delta->ent; // P_Ent tmp_ent = delta->ent;
P_EntListNode tmp_ent_node = Zi; // P_EntListNode tmp_ent_node = Zi;
tmp_ent_node.ent = tmp_ent; // tmp_ent_node.ent = tmp_ent;
P_EntList ent_list = Zi; // P_EntList ent_list = Zi;
ent_list.first = &tmp_ent_node; // ent_list.first = &tmp_ent_node;
ent_list.last = &tmp_ent_node; // ent_list.last = &tmp_ent_node;
P_SpawnEntsFromList(dst_frame, ent_list); // P_SpawnEntsFromList(dst_frame, ent_list);
} // }
} // }
//- Update sim debug info // //- Update sim debug info
// { // // {
// ResetArena(sim_debug_arena); // // ResetArena(sim_debug_arena);
// first_sim_debug_draw_node = 0; // // first_sim_debug_draw_node = 0;
// last_sim_debug_draw_node = 0; // // last_sim_debug_draw_node = 0;
// { // // {
// i64 dst_idx = 0; // // i64 dst_idx = 0;
// P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count); // // P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count);
// for (P_DebugDrawNode *src = snapshot->first_debug_draw_node; src; src = src->next) // // for (P_DebugDrawNode *src = snapshot->first_debug_draw_node; src; src = src->next)
// { // // {
// P_DebugDrawNode *dst = &dst_nodes[dst_idx]; // // P_DebugDrawNode *dst = &dst_nodes[dst_idx];
// *dst = *src; // // *dst = *src;
// dst_idx += 1; // // dst_idx += 1;
// SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst); // // SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
// } // // }
// } // // }
// } // // }
} // }
// TODO: Remove this // TODO: Remove this
P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1); P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1);
@ -3790,12 +3851,23 @@ void V_TickForever(WaveLaneCtx *lane)
for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next) // for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// String packed = P_PackMessage(frame->arena, msg);
// NET_Push(net_pipe, server_key, packed, msg->burst);
// }
{ {
P_Msg *msg = &msg_node->msg; if (P_tl.out_msgs.count > 0)
String packed = P_PackMessage(frame->arena, msg); {
NET_Push(net_pipe, server_key, packed, msg->burst); BB_ResetWriter(&packer_bbw);
String packed = P_PackMessages(&packer_bbw, P_tl.out_msgs);
NET_Push(net_pipe, server_key, packed, 0);
}
} }
ResetArena(P_tl.out_msgs_arena); ResetArena(P_tl.out_msgs_arena);
ZeroStruct(&P_tl.out_msgs); ZeroStruct(&P_tl.out_msgs);

View File

@ -1,139 +0,0 @@
Readonly TAR_Entry TAR_nil_entry = Zi;
////////////////////////////////////////////////////////////
//~ Helpers
u64 TAR_U64FromOctString(String str)
{
u64 n = 0;
for (u64 i = 0; i < str.len; ++i)
{
n *= 8;
n += (u64)(str.text[i]) - '0';
}
return n;
}
////////////////////////////////////////////////////////////
//~ Archive
// `prefix` will be prepended to all file names in the archive
//
// NOTE: The resulting archive merely points into the supplied tar data, no
// copying is done. Accessing the archive assumes that the data string is still valid.
TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
{
TAR_Archive archive = ZI;
BB_Buff bb = BitbuffFromString(data);
BB_Reader br = BB_ReaderFromBuffNoDebug(&bb);
u64 num_files = 0;
while (BB_NumBytesRemaining(&br) > 1024)
{
TAR_Header header = ZI;
BB_ReadBytes(&br, StringFromStruct(&header));
if (!MatchString(StringFromFixedArray(header.ustar_indicator), Lit("ustar\0")))
{
// Invalid header
Assert(0);
continue;
}
if (header.file_name_prefix[0] != 0)
{
// Header file name prefix not supported
Assert(0);
continue;
}
String file_size_oct_str = { .len = 11, .text = header.file_size };
u64 file_size = TAR_U64FromOctString(file_size_oct_str);
u8 *file_data_ptr = BB_ReadBytesRaw(&br, file_size);
if (!file_data_ptr)
{
file_size = 0;
}
String file_data = STRING(file_size, file_data_ptr);
// Skip sector padding
u64 remaining = (512 - (file_size % 512)) % 512;
BB_SeekBytes(&br, remaining);
b32 is_dir = header.file_type == TAR_FileKind_Directory;
if (!is_dir && header.file_type != TAR_FileKind_File)
{
// Unsupported type
Assert(header.file_type == TAR_FileKind_PaxHeaderX || header.file_type == TAR_FileKind_PaxHeaderG);
continue;
}
String file_name_cstr = StringFromCstrNoLimit((char *)header.file_name);
if (file_name_cstr.len >= 2)
{
// Chop off './' prefix
file_name_cstr.len -= 2;
file_name_cstr.text += 2;
}
String file_name = CatString(arena, prefix, file_name_cstr);
TAR_Entry *entry = PushStruct(arena, TAR_Entry);
entry->valid = 1;
entry->is_dir = is_dir;
entry->file_name = file_name;
entry->data = file_data;
entry->next = archive.head;
archive.head = entry;
++num_files;
}
// Build lookup table
archive.lookup = InitDict(arena, (u64)((f64)num_files * TAR_ArchiveLookupTableCapacityFactor));
for (TAR_Entry *entry = archive.head; entry; entry = entry->next)
{
u64 hash = HashString(entry->file_name);
SetDictValue(arena, archive.lookup, hash, (u64)entry);
}
// Build hierarchy
//
// NOTE: This is a separate pass because tar entry order is not guaranteed
// (IE file entries may be encountered before their parent directory entry)
for (TAR_Entry *entry = archive.head; entry; entry = entry->next)
{
// Enter into hierarchy
if (!entry->is_dir)
{
// Find parent entry
TAR_Entry *parent_entry = 0;
for (String parent_dir_name = entry->file_name; parent_dir_name.len > 0; --parent_dir_name.len)
{
if (parent_dir_name.text[parent_dir_name.len - 1] == '/')
{
u64 hash = HashString(parent_dir_name);
parent_entry = (TAR_Entry *)DictValueFromHash(archive.lookup, hash);
break;
}
}
// Insert child into parent's list
if (parent_entry)
{
entry->next_child = parent_entry->next_child;
parent_entry->next_child = entry;
}
}
}
return archive;
}
Readonly Global TAR_Entry g_nil_tar_entry = ZI;
TAR_Entry *TAR_EntryFromName(TAR_Archive *archive, String name)
{
u64 hash = HashString(name);
TAR_Entry *lookup = (TAR_Entry *)DictValueFromHash(archive->lookup, hash);
return lookup ? lookup : &g_nil_tar_entry;
}

View File

@ -1,80 +0,0 @@
////////////////////////////////////////////////////////////
//~ Archive types
#define TAR_ArchiveLookupTableCapacityFactor 2.0
Struct(TAR_Entry)
{
b32 valid;
String file_name;
String data;
b32 is_dir;
TAR_Entry *next;
TAR_Entry *next_child; // If entry is dir, points to first child. Otherwise points to next sibling.
};
Struct(TAR_Archive)
{
Dict *lookup;
TAR_Entry *head;
};
////////////////////////////////////////////////////////////
//~ Header types
Enum(TAR_FileKind)
{
TAR_FileKind_File = '0',
TAR_FileKind_HardLink = '1',
TAR_FileKind_SymLink = '2',
TAR_FileKind_CharacterSpecial = '3',
TAR_FileKind_BlockSpecial = '4',
TAR_FileKind_Directory = '5',
TAR_FileKind_Fifo = '6',
TAR_FileKind_ContiguousFile = '7',
TAR_FileKind_PaxHeaderG = 'g',
TAR_FileKind_PaxHeaderX = 'x'
};
Packed(Struct(TAR_Header)
{
// Pre-posix
u8 file_name[100];
u8 file_mode[8];
u8 owner_id[8];
u8 group_id[8];
u8 file_size[12];
u8 last_modified[12];
u8 checksum[8];
// Both
u8 file_type;
u8 linked_file_name[100];
// UStar
u8 ustar_indicator[6];
u8 ustar_version[2];
u8 owner_user_name[32];
u8 owner_group_name[32];
u8 device_major_number[8];
u8 device_minor_number[8];
u8 file_name_prefix[155];
u8 padding[12];
});
////////////////////////////////////////////////////////////
//~ State types
extern Readonly TAR_nil_entry;
////////////////////////////////////////////////////////////
//~ Helpers
u64 TAR_U64FromOctString(String str);
////////////////////////////////////////////////////////////
//~ Archive
TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix);
TAR_Entry *TAR_EntryFromName(TAR_Archive *archive, String name);

View File

@ -1,17 +0,0 @@
@Layer tar
//////////////////////////////
//- Dependencies
@Dep platform
@Dep bitbuff
//////////////////////////////
//- Api
@IncludeC tar.h
//////////////////////////////
//- Impl
@IncludeC tar.c