Skip to content

Commit

Permalink
C client: Implement skipping in PortionStream. Reduces I/O reads of d…
Browse files Browse the repository at this point in the history
…efault.zip by 150
  • Loading branch information
UnknownShadow200 committed Oct 11, 2018
1 parent 0567fec commit 3a4b10d
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 62 deletions.
2 changes: 1 addition & 1 deletion src/Audio.c
Expand Up @@ -96,7 +96,7 @@ static ReturnCode Sound_ReadWaveData(struct Stream* stream, struct Sound* snd) {
}

/* Skip over unhandled data */
if (size && (res = Stream_Skip(stream, size))) return res;
if (size && (res = stream->Skip(stream, size))) return res;
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/Bitmap.c
Expand Up @@ -484,11 +484,11 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) {
} break;

default:
if ((res = Stream_Skip(stream, dataSize))) return res;
if ((res = stream->Skip(stream, dataSize))) return res;
break;
}

if ((res = Stream_Read(stream, tmp, 4))) return res; /* Skip CRC32 */
if ((res = stream->Skip(stream, 4))) return res; /* Skip CRC32 */
}

if (transparentCol <= PNG_RGB_MASK) {
Expand Down Expand Up @@ -671,8 +671,8 @@ ReturnCode Png_Encode(Bitmap* bmp, struct Stream* stream, Png_RowSelector select

/* Come back to write size of data chunk */
uint32_t stream_len;
if ((res = stream->Length(stream, &stream_len))) return res;
if ((res = stream->Seek(stream, 33, STREAM_SEEKFROM_BEGIN))) return res;
if ((res = stream->Length(stream, &stream_len))) return res;
if ((res = stream->Seek(stream, 33))) return res;

Stream_SetU32_BE(&tmp[0], stream_len - 57);
return Stream_Write(stream, tmp, 4);
Expand Down
16 changes: 8 additions & 8 deletions src/Formats.c
Expand Up @@ -156,7 +156,7 @@ static ReturnCode Fcm_ReadString(struct Stream* stream) {
if ((res = Stream_Read(stream, data, sizeof(data)))) return res;

int len = Stream_GetU16_LE(data);
return Stream_Skip(stream, len);
return stream->Skip(stream, len);
}

ReturnCode Fcm_Load(struct Stream* stream) {
Expand Down Expand Up @@ -305,7 +305,7 @@ static ReturnCode Nbt_ReadTag(uint8_t typeId, bool readTagName, struct Stream* s
break;
case NBT_I64:
case NBT_R64:
res = Stream_Skip(stream, 8);
res = stream->Skip(stream, 8);
break; /* (8) data */

case NBT_I8S:
Expand Down Expand Up @@ -639,7 +639,7 @@ static ReturnCode Dat_ReadFieldDesc(struct Stream* stream, struct JFieldDesc* de
char className1[JNAME_SIZE];
return Dat_ReadString(stream, className1);
} else if (typeCode == TC_REFERENCE) {
return Stream_Skip(stream, 4); /* (4) handle */
return stream->Skip(stream, 4); /* (4) handle */
} else {
return DAT_ERR_JFIELD_CLASS_NAME;
}
Expand All @@ -657,7 +657,7 @@ static ReturnCode Dat_ReadClassDesc(struct Stream* stream, struct JClassDesc* de
if (typeCode != TC_CLASSDESC) return DAT_ERR_JCLASS_TYPE;

if ((res = Dat_ReadString(stream, desc->ClassName))) return res;
if ((res = Stream_Skip(stream, 9))) return res; /* (8) serial version UID, (1) flags */
if ((res = stream->Skip(stream, 9))) return res; /* (8) serial version UID, (1) flags */

if ((res = Stream_Read(stream, tmp, 2))) return res;
desc->FieldsCount = Stream_GetU16_BE(tmp);
Expand Down Expand Up @@ -688,7 +688,7 @@ static ReturnCode Dat_ReadFieldData(struct Stream* stream, struct JFieldDesc* fi
case JFIELD_I32:
return Stream_ReadU32_BE(stream, &field->Value_I32);
case JFIELD_I64:
return Stream_Skip(stream, 8); /* (8) data */
return stream->Skip(stream, 8); /* (8) data */

case JFIELD_OBJECT: {
/* Luckily for us, we only have to account for blockMap object */
Expand All @@ -700,11 +700,11 @@ static ReturnCode Dat_ReadFieldData(struct Stream* stream, struct JFieldDesc* fi
/* Skip all blockMap data with awful hacks */
/* These offsets were based on server_level.dat map from original minecraft classic server */
if (typeCode == TC_OBJECT) {
if ((res = Stream_Skip(stream, 315))) return res;
if ((res = stream->Skip(stream, 315))) return res;
if ((res = Stream_ReadU32_BE(stream, &count))) return res;

if ((res = Stream_Skip(stream, 17 * count))) return res;
if ((res = Stream_Skip(stream, 152))) return res;
if ((res = stream->Skip(stream, 17 * count))) return res;
if ((res = stream->Skip(stream, 152))) return res;
} else if (typeCode != TC_NULL) {
/* WoM maps have this field as null, which makes things easier for us */
return DAT_ERR_JOBJECT_TYPE;
Expand Down
4 changes: 2 additions & 2 deletions src/Platform.c
Expand Up @@ -381,7 +381,7 @@ ReturnCode File_Create(void** file, const String* path) {
ReturnCode File_Append(void** file, const String* path) {
ReturnCode result = File_Do(file, path, GENERIC_WRITE, OPEN_ALWAYS);
if (result) return result;
return File_Seek(*file, 0, STREAM_SEEKFROM_END);
return File_Seek(*file, 0, FILE_SEEKFROM_END);
}

ReturnCode File_Read(void* file, uint8_t* buffer, uint32_t count, uint32_t* bytesRead) {
Expand Down Expand Up @@ -498,7 +498,7 @@ ReturnCode File_Create(void** file, const String* path) {
ReturnCode File_Append(void** file, const String* path) {
ReturnCode result = File_Do(file, path, O_WRONLY | O_CREAT);
if (result) return result;
return File_Seek(*file, 0, STREAM_SEEKFROM_END);
return File_Seek(*file, 0, FILE_SEEKFROM_END);
}

ReturnCode File_Read(void* file, uint8_t* buffer, uint32_t count, uint32_t* bytesRead) {
Expand Down
3 changes: 3 additions & 0 deletions src/Platform.h
Expand Up @@ -15,6 +15,9 @@ typedef uintptr_t SocketPtr;
typedef int SocketPtr;
#endif

/* Origin points for when seeking in a file. */
enum FILE_SEEKFROM { FILE_SEEKFROM_BEGIN, FILE_SEEKFROM_CURRENT, FILE_SEEKFROM_END };

/* Newline for console and text files. */
extern char* Platform_NewLine;
/* Character in a path that distinguishes directories. (usually / or \) */
Expand Down
83 changes: 47 additions & 36 deletions src/Stream.c
Expand Up @@ -33,47 +33,47 @@ ReturnCode Stream_Write(struct Stream* stream, uint8_t* buffer, uint32_t count)
return 0;
}

ReturnCode Stream_Skip(struct Stream* stream, uint32_t count) {
ReturnCode res = stream->Seek(stream, count, STREAM_SEEKFROM_CURRENT);
if (!res) return 0;
static ReturnCode Stream_DefaultIO(struct Stream* stream, uint8_t* data, uint32_t count, uint32_t* modified) {
*modified = 0; return ReturnCode_NotSupported;
}
ReturnCode Stream_DefaultReadU8(struct Stream* stream, uint8_t* data) {
uint32_t modified = 0;
ReturnCode res = stream->Read(stream, data, 1, &modified);
return res ? res : (modified ? 0 : ERR_END_OF_STREAM);
}

static ReturnCode Stream_DefaultSkip(struct Stream* stream, uint32_t count) {
uint8_t tmp[3584]; /* not quite 4 KB to avoid chkstk call */
ReturnCode res;

while (count) {
uint32_t toRead = min(count, sizeof(tmp)), read;
res = stream->Read(stream, tmp, toRead, &read);
if (res) return res;
if (!read) return ERR_END_OF_STREAM;
if ((res = stream->Read(stream, tmp, toRead, &read))) return res;

if (!read) return ERR_END_OF_STREAM;
count -= read;
}
return 0;
}

static ReturnCode Stream_DefaultIO(struct Stream* stream, uint8_t* data, uint32_t count, uint32_t* modified) {
*modified = 0; return ReturnCode_NotSupported;
}
ReturnCode Stream_DefaultReadU8(struct Stream* stream, uint8_t* data) {
uint32_t modified = 0;
ReturnCode res = stream->Read(stream, data, 1, &modified);
return res ? res : (modified ? 0 : ERR_END_OF_STREAM);
}

static ReturnCode Stream_DefaultClose(struct Stream* stream) { return 0; }
static ReturnCode Stream_DefaultSeek(struct Stream* stream, int offset, int seekType) {
static ReturnCode Stream_DefaultSeek(struct Stream* stream, uint32_t pos) {
return ReturnCode_NotSupported;
}
static ReturnCode Stream_DefaultGet(struct Stream* stream, uint32_t* value) {
*value = 0; return ReturnCode_NotSupported;
}
static ReturnCode Stream_DefaultClose(struct Stream* stream) { return 0; }

void Stream_Init(struct Stream* stream) {
stream->Read = Stream_DefaultIO;
stream->ReadU8 = Stream_DefaultReadU8;
stream->Write = Stream_DefaultIO;
stream->Close = Stream_DefaultClose;
stream->Skip = Stream_DefaultSkip;

stream->Seek = Stream_DefaultSeek;
stream->Position = Stream_DefaultGet;
stream->Length = Stream_DefaultGet;
stream->Length = Stream_DefaultGet;
stream->Close = Stream_DefaultClose;
}


Expand All @@ -91,8 +91,11 @@ static ReturnCode Stream_FileClose(struct Stream* stream) {
stream->Meta.File = NULL;
return res;
}
static ReturnCode Stream_FileSeek(struct Stream* stream, int offset, int seekType) {
return File_Seek(stream->Meta.File, offset, seekType);
static ReturnCode Stream_FileSkip(struct Stream* stream, uint32_t count) {
return File_Seek(stream->Meta.File, count, FILE_SEEKFROM_CURRENT);
}
static ReturnCode Stream_FileSeek(struct Stream* stream, uint32_t pos) {
return File_Seek(stream->Meta.File, pos, FILE_SEEKFROM_BEGIN);
}
static ReturnCode Stream_FilePosition(struct Stream* stream, uint32_t* position) {
return File_Position(stream->Meta.File, position);
Expand All @@ -108,6 +111,7 @@ void Stream_FromFile(struct Stream* stream, void* file) {
stream->Read = Stream_FileRead;
stream->Write = Stream_FileWrite;
stream->Close = Stream_FileClose;
stream->Skip = Stream_FileSkip;
stream->Seek = Stream_FileSeek;
stream->Position = Stream_FilePosition;
stream->Length = Stream_FileLength;
Expand All @@ -120,9 +124,9 @@ void Stream_FromFile(struct Stream* stream, void* file) {
static ReturnCode Stream_PortionRead(struct Stream* stream, uint8_t* data, uint32_t count, uint32_t* modified) {
count = min(count, stream->Meta.Mem.Left);
struct Stream* source = stream->Meta.Portion.Source;
ReturnCode code = source->Read(source, data, count, modified);
ReturnCode res = source->Read(source, data, count, modified);
stream->Meta.Mem.Left -= *modified;
return code;
return res;
}

static ReturnCode Stream_PortionReadU8(struct Stream* stream, uint8_t* data) {
Expand All @@ -132,6 +136,15 @@ static ReturnCode Stream_PortionReadU8(struct Stream* stream, uint8_t* data) {
return source->ReadU8(source, data);
}

static ReturnCode Stream_PortionSkip(struct Stream* stream, uint32_t count) {
if (count > stream->Meta.Mem.Left) return ReturnCode_InvalidArg;
struct Stream* source = stream->Meta.Portion.Source;

ReturnCode res = source->Skip(source, count);
if (!res) stream->Meta.Mem.Left -= count;
return res;
}

static ReturnCode Stream_PortionPosition(struct Stream* stream, uint32_t* position) {
*position = stream->Meta.Portion.Length - stream->Meta.Portion.Left; return 0;
}
Expand All @@ -143,6 +156,7 @@ void Stream_ReadonlyPortion(struct Stream* stream, struct Stream* source, uint32
Stream_Init(stream);
stream->Read = Stream_PortionRead;
stream->ReadU8 = Stream_PortionReadU8;
stream->Skip = Stream_PortionSkip;
stream->Position = Stream_PortionPosition;
stream->Length = Stream_PortionLength;

Expand Down Expand Up @@ -182,28 +196,25 @@ static ReturnCode Stream_MemoryWrite(struct Stream* stream, uint8_t* data, uint3
return 0;
}

static ReturnCode Stream_MemorySeek(struct Stream* stream, int offset, int seekType) {
int pos;
uint32_t curOffset = (uint32_t)(stream->Meta.Mem.Cur - stream->Meta.Mem.Base);
static ReturnCode Stream_MemorySkip(struct Stream* stream, uint32_t count) {
if (count > stream->Meta.Mem.Left) return ReturnCode_InvalidArg;

switch (seekType) {
case STREAM_SEEKFROM_BEGIN:
pos = offset; break;
case STREAM_SEEKFROM_CURRENT:
pos = (int)curOffset + offset; break;
case STREAM_SEEKFROM_END:
pos = (int)stream->Meta.Mem.Length + offset; break;
default: return ReturnCode_InvalidArg;
}
stream->Meta.Mem.Cur += count;
stream->Meta.Mem.Left -= count;
return 0;
}

static ReturnCode Stream_MemorySeek(struct Stream* stream, uint32_t pos) {
if (pos >= stream->Meta.Mem.Length) return ReturnCode_InvalidArg;

if (pos < 0 || pos >= stream->Meta.Mem.Length) return ReturnCode_InvalidArg;
stream->Meta.Mem.Cur = stream->Meta.Mem.Base + pos;
stream->Meta.Mem.Left = stream->Meta.Mem.Length - pos;
return 0;
}

static void Stream_CommonMemory(struct Stream* stream, void* data, uint32_t len) {
Stream_Init(stream);
stream->Skip = Stream_MemorySkip;
stream->Seek = Stream_MemorySeek;
/* TODO: Should we use separate Stream_MemoryPosition functions? */
stream->Position = Stream_PortionPosition;
Expand Down
9 changes: 5 additions & 4 deletions src/Stream.h
Expand Up @@ -7,8 +7,6 @@
Copyright 2017 ClassicalSharp | Licensed under BSD-3
*/

/* Origin points for when seeking in a stream. */
enum STREAM_SEEKFROM { STREAM_SEEKFROM_BEGIN, STREAM_SEEKFROM_CURRENT, STREAM_SEEKFROM_END };
struct Stream;
/* Represents a stream that can be written to and/or read from. */
struct Stream {
Expand All @@ -18,8 +16,11 @@ struct Stream {
ReturnCode (*ReadU8)(struct Stream* stream, uint8_t* data);
/* Attempts to write some bytes to this stream. */
ReturnCode (*Write)(struct Stream* stream, uint8_t* data, uint32_t count, uint32_t* modified);
/* Attempts to seek to a position in this stream. */
ReturnCode (*Seek)(struct Stream* stream, int offset, int seekType);
/* Attempts to quickly advance the position in this stream. (falls back to reading then discarding) */
ReturnCode (*Skip)(struct Stream* stream, uint32_t count);

/* Attempts to seek to the given position in this stream. (may not be supported) */
ReturnCode (*Seek)(struct Stream* stream, uint32_t pos);
/* Attempts to find current position this stream. (may not be supported) */
ReturnCode (*Position)(struct Stream* stream, uint32_t* pos);
/* Attempts to find total length of this stream. (may not be supported) */
Expand Down
10 changes: 5 additions & 5 deletions src/TexturePack.c
Expand Up @@ -48,7 +48,7 @@ static ReturnCode Zip_ReadLocalFileHeader(struct ZipState* state, struct ZipEntr
pathBuffer[pathLen] = '\0';

if (!state->SelectEntry(&path)) return 0;
if ((res = Stream_Skip(stream, extraLen))) return res;
if ((res = stream->Skip(stream, extraLen))) return res;
struct Stream portion, compStream;

if (method == 0) {
Expand Down Expand Up @@ -89,7 +89,7 @@ static ReturnCode Zip_ReadCentralDirectory(struct ZipState* state, struct ZipEnt
entry->LocalHeaderOffset = Stream_GetU32_LE(&contents[38]);

uint32_t extraDataLen = pathLen + extraLen + commentLen;
return Stream_Skip(stream, extraDataLen);
return stream->Skip(stream, extraDataLen);
}

static ReturnCode Zip_ReadEndOfCentralDirectory(struct ZipState* state, uint32_t* centralDirectoryOffset) {
Expand Down Expand Up @@ -134,7 +134,7 @@ ReturnCode Zip_Extract(struct ZipState* state) {
/* At -22 for nearly all zips, but try a bit further back in case of comment */
int i, len = min(257, stream_len);
for (i = 22; i < len; i++) {
res = stream->Seek(stream, -i, STREAM_SEEKFROM_END);
res = stream->Seek(stream, stream_len - i);
if (res) return ZIP_ERR_SEEK_END_OF_CENTRAL_DIR;

if ((res = Stream_ReadU32_LE(stream, &sig))) return res;
Expand All @@ -146,7 +146,7 @@ ReturnCode Zip_Extract(struct ZipState* state) {
res = Zip_ReadEndOfCentralDirectory(state, &centralDirOffset);
if (res) return res;

res = stream->Seek(stream, centralDirOffset, STREAM_SEEKFROM_BEGIN);
res = stream->Seek(stream, centralDirOffset);
if (res) return ZIP_ERR_SEEK_CENTRAL_DIR;
if (state->EntriesCount > ZIP_MAX_ENTRIES) return ZIP_ERR_TOO_MANY_ENTRIES;

Expand All @@ -169,7 +169,7 @@ ReturnCode Zip_Extract(struct ZipState* state) {
/* Now read the local file header entries */
for (i = 0; i < count; i++) {
struct ZipEntry* entry = &state->Entries[i];
res = stream->Seek(stream, entry->LocalHeaderOffset, STREAM_SEEKFROM_BEGIN);
res = stream->Seek(stream, entry->LocalHeaderOffset);
if (res) return ZIP_ERR_SEEK_LOCAL_DIR;

if ((res = Stream_ReadU32_LE(stream, &sig))) return res;
Expand Down
4 changes: 2 additions & 2 deletions src/Vorbis.c
Expand Up @@ -1029,13 +1029,13 @@ static ReturnCode Vorbis_DecodeComments(struct VorbisState* ctx) {

/* vendor name, followed by comments */
if ((res = Stream_ReadU32_LE(stream, &len))) return res;
if ((res = Stream_Skip(stream, len))) return res;
if ((res = stream->Skip(stream, len))) return res;
if ((res = Stream_ReadU32_LE(stream, &comments))) return res;

for (i = 0; i < comments; i++) {
/* comments such as artist, year, etc */
if ((res = Stream_ReadU32_LE(stream, &len))) return res;
if ((res = Stream_Skip(stream, len))) return res;
if ((res = stream->Skip(stream, len))) return res;
}

/* check framing flag */
Expand Down

0 comments on commit 3a4b10d

Please sign in to comment.