Permalink
Browse files

C client: Implement skipping in PortionStream. Reduces I/O reads of d…

…efault.zip by 150
  • Loading branch information...
UnknownShadow200 committed Oct 11, 2018
1 parent 0567fec commit 3a4b10d60ed188efcb7a12cd2f7f960826827a8e
Showing with 77 additions and 62 deletions.
  1. +1 −1 src/Audio.c
  2. +4 −4 src/Bitmap.c
  3. +8 −8 src/Formats.c
  4. +2 −2 src/Platform.c
  5. +3 −0 src/Platform.h
  6. +47 −36 src/Stream.c
  7. +5 −4 src/Stream.h
  8. +5 −5 src/TexturePack.c
  9. +2 −2 src/Vorbis.c
View
@@ -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;
}
}
View
@@ -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) {
@@ -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);
View
@@ -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) {
@@ -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:
@@ -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;
}
@@ -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);
@@ -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 */
@@ -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;
View
@@ -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) {
@@ -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) {
View
@@ -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 \) */
View
@@ -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;
}
@@ -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);
@@ -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;
@@ -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) {
@@ -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;
}
@@ -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;
@@ -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;
View
@@ -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 {
@@ -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) */
View
@@ -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) {
@@ -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) {
@@ -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;
@@ -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;
@@ -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;
View
@@ -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 */

0 comments on commit 3a4b10d

Please sign in to comment.