CodeSOD: An Unreal Json Parser |
As we've discussed in the past, video game code probably shouldn't be held to the standards of your average WTF: they're operating under wildly different constraints. So, for example, when a popular indie game open sources itself, and people find all sorts of horrors in the codebase: hey, the game shipped and made money. This isn't life or death stuff.
It's a little different when you're building the engine. You're not just hacking together whatever you need to make your product work, but putting together a reusable platform to make other people's products work.
Rich D, who previously shared some horrors he found in the Unreal engine, recently discovered that UnrealScript has a useful sounding JsonObject
. Since Rich is thinking in terms of mods, being able to read/write JSON to handle mod configuration is useful, but anyone designing a game might have many good reasons to want JSON documents.
The file starts promisingly with:
class JsonObject extends Object
native;
/// COMMENT!!
…
It's good that someone put that comment there, because I assume it was meant as a reminder: comment this code. And the comments start giving us hints of some weird things:
/**
* Looks up a value with the given key in the ObjectMap. If it was a number
* in the Json string, this will be prepended with \# (see below helpers)
*
* @param Key The key to search for
*
* @return A string value
*/
native function string GetStringValue(const string Key);
The method GetStringValue
returns a string from JSON, but if the string is a number, it… puts a \#
in front of it? Why?
function int GetIntValue(const string Key)
{
local string Value;
// look up the key, and skip the \#
Value = Mid(GetStringValue(Key), 2);
return int(Value);
}
Oh… that's why. So that we can ignore it. There's a similar version of this method for GetFloatValue
, and GetBoolValue
.
So, how do those \#
s get prepended? Well, as it turns out, there are also set methods:
function SetIntValue(const string Key, int Value)
{
SetStringValue(Key, "\\#" $ Value);
}
In addition to these methods, there are also native
methods (e.g., methods which bind to native code, and thus don't have an UnrealScript body) to encode/decode JSON:
/**
* Encodes an object hierarchy to a string suitable for sending over the web
*
* @param Root The toplevel object in the hierarchy
*
* @return A well-formatted Json string
*/
static native function string EncodeJson(JsonObject Root);
/**
* Decodes a Json string into an object hierarchy (all needed objects will be created)
*
* @param Str A Json string (probably received from the web)
*
* @return The root object of the resulting hierarchy
*/
static native function JsonObject DecodeJson(const string Str);
Guided by this code, Rich went on to do a few tests:
SetStringValue
with a string that happens to start with \#
causes EncodeJson
to produce malformed output.SetStringValue
with any string that might require escape characters (newlines, backslashes, etc.) will not escape those characters, producing malformed output.EncodeJson
cannot reliably be parsed by DecodeJson
, as sometimes the output is invalidDecodeJson
receives an invalid document, instead of throwing an error, it just crashes the entire gameRich has wisely decided not to leverage this object, for now.
Комментировать | « Пред. запись — К дневнику — След. запись » | Страницы: [1] [Новые] |