diff --git a/src/Entity.c b/src/Entity.c index 04986dcee..a5b099cdc 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -125,14 +125,10 @@ void Entity_SetModel(struct Entity* entity, STRING_PURE String* model) { entity->ModelScale = Vector3_Create1(1.0f); entity->ModelBlock = BLOCK_AIR; - Int32 sep = String_IndexOf(model, '|', 0); String name, scale; - if (sep == -1) { + if (!String_UNSAFE_Split_KV(model, '|', &name, &scale)) { name = *model; scale = String_MakeNull(); - } else { - name = String_UNSAFE_Substring(model, 0, sep); - scale = String_UNSAFE_SubstringAt(model, sep + 1); } /* 'giant' model kept for backwards compatibility */ diff --git a/src/Input.c b/src/Input.c index 3360919e8..aa0a364f8 100644 --- a/src/Input.c +++ b/src/Input.c @@ -305,26 +305,21 @@ void Hotkeys_Init(void) { for (i = 0; i < Options_Keys.Count; i++) { String key = StringsBuffer_UNSAFE_Get(&Options_Keys, i); if (!String_CaselessStarts(&key, &prefix)) continue; - Int32 keySplit = String_IndexOf(&key, '&', prefix.length); - if (keySplit < 0) continue; /* invalid key */ - - String strKey = String_UNSAFE_Substring(&key, prefix.length, keySplit - prefix.length); - String strFlags = String_UNSAFE_SubstringAt(&key, keySplit + 1); + /* key&modifiers = more-input&text */ + key.length -= prefix.length; key.buffer += prefix.length; String value = StringsBuffer_UNSAFE_Get(&Options_Values, i); - Int32 valueSplit = String_IndexOf(&value, '&', 0); - if (valueSplit < 0) continue; /* invalid value */ - String strMoreInput = String_UNSAFE_Substring(&value, 0, valueSplit - 0); - String strText = String_UNSAFE_SubstringAt(&value, valueSplit + 1); + String strKey, strFlags, strMore, strText; + if (!String_UNSAFE_Split_KV(&key, '&', &strKey, &strFlags)) continue; + if (!String_UNSAFE_Split_KV(&value, '&', &strMore, &strText)) continue; - /* Then try to parse the key and value */ Key hotkey = Utils_ParseEnum(&strKey, Key_None, Key_Names, Array_Elems(Key_Names)); - UInt8 flags; bool moreInput; - if (hotkey == Key_None || !strText.length || !Convert_TryParseUInt8(&strFlags, &flags) - || !Convert_TryParseBool(&strMoreInput, &moreInput)) { continue; } + UInt8 flags; bool more; + if (hotkey == Key_None || !Convert_TryParseUInt8(&strFlags, &flags) + || !Convert_TryParseBool(&strMore, &more)) { continue; } - Hotkeys_Add(hotkey, flags, &strText, moreInput); + Hotkeys_Add(hotkey, flags, &strText, more); } } diff --git a/src/Menus.c b/src/Menus.c index 7a605f453..e0233d642 100644 --- a/src/Menus.c +++ b/src/Menus.c @@ -1548,14 +1548,10 @@ static void HotkeyListScreen_EntryClick(struct GuiElem* elem, struct GuiElem* w) Gui_ReplaceActive(EditHotkeyScreen_MakeInstance(original)); return; } - Int32 sepIndex = String_IndexOf(&text, '+', 0); String key = text, value; UInt8 flags = 0; - if (sepIndex >= 0) { - key = String_UNSAFE_Substring(&text, 0, sepIndex - 1); - value = String_UNSAFE_SubstringAt(&text, sepIndex + 1); - + if (String_UNSAFE_Split_KV(&text, '+', &key, &value)) { String ctrl = String_FromConst("Ctrl"); String shift = String_FromConst("Shift"); String alt = String_FromConst("Alt"); diff --git a/src/Options.c b/src/Options.c index d9a4bcb88..b31967096 100644 --- a/src/Options.c +++ b/src/Options.c @@ -173,6 +173,7 @@ void Options_Load(void) { /* ReadLine reads single byte at a time */ UInt8 buffer[2048]; struct Stream buffered; Stream_ReadonlyBuffered(&buffered, &stream, buffer, sizeof(buffer)); + String key, value; for (;;) { res = Stream_ReadLine(&buffered, &line); @@ -180,13 +181,7 @@ void Options_Load(void) { if (res) { Chat_LogError(res, "reading from", &path); break; } if (!line.length || line.buffer[0] == '#') continue; - Int32 sepIndex = String_IndexOf(&line, '=', 0); - if (sepIndex <= 0) continue; - String key = String_UNSAFE_Substring(&line, 0, sepIndex); - - sepIndex++; - if (sepIndex == line.length) continue; - String value = String_UNSAFE_SubstringAt(&line, sepIndex); + if (!String_UNSAFE_Split_KV(&line, '=', &key, &value)) continue; if (!Options_HasChanged(&key)) { Options_Insert(&key, &value); diff --git a/src/PacketHandlers.c b/src/PacketHandlers.c index 39e6b080f..8afac1cd3 100644 --- a/src/PacketHandlers.c +++ b/src/PacketHandlers.c @@ -240,18 +240,12 @@ static bool WoM_ReadLine(STRING_REF String* page, Int32* start, STRING_TRANSIENT } static void WoM_ParseConfig(STRING_PURE String* page) { - String line; + String line, key, value; Int32 start = 0; while (WoM_ReadLine(page, &start, &line)) { Platform_Log(&line); - Int32 sepIndex = String_IndexOf(&line, '=', 0); - if (sepIndex == -1) continue; - - String key = String_UNSAFE_Substring(&line, 0, sepIndex); - String_UNSAFE_TrimEnd(&key); - String value = String_UNSAFE_SubstringAt(&line, sepIndex + 1); - String_UNSAFE_TrimStart(&value); + if (!String_UNSAFE_Split_KV(&line, '=', &key, &value)) continue; if (String_CaselessEqualsConst(&key, "environment.cloud")) { PackedCol col = WoM_ParseCol(&value, WorldEnv_DefaultCloudsCol); diff --git a/src/Program.c b/src/Program.c index e45d3a57b..9dc3b0a1d 100644 --- a/src/Program.c +++ b/src/Program.c @@ -115,7 +115,7 @@ int main(void) { } UInt16 port; - if (!Convert_TryParseUInt16(&args[3], &Game_Port)) { + if (!Convert_TryParseUInt16(&args[3], &port)) { Platform_LogConst("Invalid port"); return 1; } Game_Port = port; diff --git a/src/ServerConnection.c b/src/ServerConnection.c index 8d827f9e5..12195ab74 100644 --- a/src/ServerConnection.c +++ b/src/ServerConnection.c @@ -154,7 +154,7 @@ static void SPConnection_BeginConnect(void) { } Event_RaiseVoid(&BlockEvents_PermissionsChanged); - /* For when user drops a map file onto ClassicalSharp.exe */ + /* For when user drops a map file onto ClassiCube.exe */ String path = Game_Username; if (String_IndexOf(&path, Directory_Separator, 0) >= 0 && File_Exists(&path)) { LoadLevelScreen_LoadMap(&path); diff --git a/src/String.c b/src/String.c index 85fb687b1..58faca7a8 100644 --- a/src/String.c +++ b/src/String.c @@ -82,6 +82,20 @@ void String_UNSAFE_Split(STRING_REF String* str, char c, STRING_TRANSIENT String for (; i < maxSubs; i++) { subs[i] = String_MakeNull(); } } +bool String_UNSAFE_Split_KV(STRING_REF String* str, char c, STRING_TRANSIENT String* key, STRING_TRANSIENT String* value) { + /* key [c] value or key[c]value */ + Int32 idx = String_IndexOf(str, c, 0); + if (idx <= 0) return false; /* missing [c] or no key */ + if ((idx + 1) >= str->length) return false; /* missing value */ + + *key = String_UNSAFE_Substring(str, 0, idx); idx++; + *value = String_UNSAFE_SubstringAt(str, idx); + + String_UNSAFE_TrimEnd(key); + String_UNSAFE_TrimStart(value); + return true; +} + bool String_Equals(STRING_PURE String* a, STRING_PURE String* b) { if (a->length != b->length) return false; diff --git a/src/String.h b/src/String.h index dac831ad8..5c948d57e 100644 --- a/src/String.h +++ b/src/String.h @@ -43,13 +43,10 @@ String String_FromReadonly(STRING_REF const char* buffer); void String_StripCols(STRING_TRANSIENT String* str); void String_Copy(STRING_TRANSIENT String* dst, STRING_PURE String* src); -/* Returns a string that points directly to a substring of the given string. -NOTE: THIS IS UNSAFE - IT MAINTAINS A REFERENCE TO THE ORIGINAL BUFFER, AND THE SUBSTRING IS NOT NULL TERMINATED */ String String_UNSAFE_Substring(STRING_REF String* str, Int32 offset, Int32 length); #define String_UNSAFE_SubstringAt(str, offset) (String_UNSAFE_Substring(str, offset, (str)->length - (offset))) -/* Splits a string into a sequence of substrings -NOTE: THIS IS UNSAFE - IT MAINTAINS A REFERENCE TO THE ORIGINAL BUFFER, AND THE SUBSTRING IS NOT NULL TERMINATED */ void String_UNSAFE_Split(STRING_REF String* str, char c, STRING_TRANSIENT String* subs, Int32* subsCount); +bool String_UNSAFE_Split_KV(STRING_REF String* str, char c, STRING_TRANSIENT String* key, STRING_TRANSIENT String* value); bool String_Equals(STRING_PURE String* a, STRING_PURE String* b); bool String_CaselessEquals(STRING_PURE String* a, STRING_PURE String* b); diff --git a/src/TexturePack.c b/src/TexturePack.c index ced84538d..ada2ec30b 100644 --- a/src/TexturePack.c +++ b/src/TexturePack.c @@ -323,14 +323,13 @@ bool TextureCache_GetStream(STRING_PURE String* url, struct Stream* stream) { void TexturePack_GetFromTags(STRING_PURE String* url, STRING_TRANSIENT String* result, struct EntryList* list) { TexCache_Crc32(url); Int32 i; - for (i = 0; i < list->Entries.Count; i++) { - String entry = StringsBuffer_UNSAFE_Get(&list->Entries, i); - if (!String_CaselessStarts(&entry, &crc32)) continue; + String line, key, value; - Int32 sepIndex = String_IndexOf(&entry, ' ', 0); - if (sepIndex == -1) continue; - - String value = String_UNSAFE_SubstringAt(&entry, sepIndex + 1); + for (i = 0; i < list->Entries.Count; i++) { + line = StringsBuffer_UNSAFE_Get(&list->Entries, i); + if (!String_UNSAFE_Split_KV(&line, ' ', &key, &value)) continue; + + if (!String_CaselessEquals(&key, &crc32)) continue; String_AppendString(result, &value); } }