Преглед изворни кода

Fix JSON parser leaking memory when parsing huge files

Daniele Bartolini пре 12 година
родитељ
комит
4cae37ea24

+ 5 - 7
engine/core/json/JSON.cpp

@@ -26,8 +26,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "JSON.h"
 #include "List.h"
-#include "TempAllocator.h"
 #include "StringUtils.h"
+#include "DynamicString.h"
 
 namespace crown
 {
@@ -229,7 +229,7 @@ JSONType::Enum type(const char* s)
 }
 
 //-----------------------------------------------------------------------------
-void parse_string(const char* s, List<char>& str)
+void parse_string(const char* s, DynamicString& str)
 {
 	CE_ASSERT_NOT_NULL(s);
 
@@ -243,7 +243,6 @@ void parse_string(const char* s, List<char>& str)
 			if ((*ch) == '"')
 			{
 				ch = next(ch);
-				str.push_back('\0');
 				return;
 			}
 			else if ((*ch) == '\\')
@@ -256,7 +255,7 @@ void parse_string(const char* s, List<char>& str)
 				}
 				else if (is_escapee(*ch))
 				{
-					str.push_back(*ch);
+					str += (*ch);
 				}
 				else
 				{
@@ -266,7 +265,7 @@ void parse_string(const char* s, List<char>& str)
 			}
 			else
 			{
-				str.push_back(*ch);
+				str += (*ch);
 			}
 		}
 	}
@@ -281,8 +280,7 @@ double parse_number(const char* s)
 
 	const char* ch = s;
 
-	TempAllocator1024 allocator;
- 	List<char> str(allocator);
+ 	List<char> str(default_allocator());
 
 	if ((*ch) == '-')
 	{

+ 3 - 1
engine/core/json/JSON.h

@@ -25,6 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 */
 
 #include "Types.h"
+#include "DynamicString.h"
 
 #pragma once
 
@@ -33,6 +34,7 @@ namespace crown
 
 template<typename T>
 class List;
+class DynamicString;
 
 namespace json
 {
@@ -63,7 +65,7 @@ struct JSONPair
 JSONType::Enum type(const char* s);
 
 /// Parses the @a s JSON string a puts its C representation into @a str.
-void parse_string(const char* s, List<char>& str);
+void parse_string(const char* s, DynamicString& str);
 
 /// Returns the value of the @a s JSON number as double.
 double parse_number(const char* s);

+ 26 - 58
engine/core/json/JSONParser.cpp

@@ -59,15 +59,13 @@ JSONElement& JSONElement::operator=(const JSONElement& other)
 {
 	// Our begin is the other's at
 	m_at = other.m_at;
-
 	return *this;
 }
 
 //--------------------------------------------------------------------------
 JSONElement JSONElement::operator[](uint32_t i)
 {
-	TempAllocator1024 alloc;
-	List<const char*> array(alloc);
+	List<const char*> array(default_allocator());
 
 	json::parse_array(m_at, array);
 
@@ -87,8 +85,7 @@ JSONElement JSONElement::index_or_nil(uint32_t i)
 {
 	if (m_at != NULL)
 	{
-		TempAllocator1024 alloc;
-		List<const char*> array(alloc);
+		List<const char*> array(default_allocator());
 
 		json::parse_array(m_at, array);
 
@@ -106,8 +103,7 @@ JSONElement JSONElement::index_or_nil(uint32_t i)
 //--------------------------------------------------------------------------
 JSONElement JSONElement::key(const char* k)
 {
-	TempAllocator1024 alloc;
-	List<JSONPair> object(alloc);
+	List<JSONPair> object(default_allocator());
 
 	json::parse_object(m_at, object);
 
@@ -116,12 +112,10 @@ JSONElement JSONElement::key(const char* k)
 	const char* tmp_at = m_at;
 	for (uint32_t i = 0; i < object.size(); i++)
 	{
-		TempAllocator256 key_alloc;
-		List<char> key(key_alloc);
-
+		DynamicString key;
 		json::parse_string(object[i].key, key);
 
-		if (string::strcmp(k, key.begin()) == 0)
+		if (key == k)
 		{
 			tmp_at = object[i].val;
 			found = true;
@@ -138,8 +132,7 @@ JSONElement JSONElement::key_or_nil(const char* k)
 {
 	if (m_at != NULL)
 	{
-		TempAllocator1024 alloc;
-		List<JSONPair> object(alloc);
+		List<JSONPair> object(default_allocator());
 
 		json::parse_object(m_at, object);
 
@@ -148,12 +141,10 @@ JSONElement JSONElement::key_or_nil(const char* k)
 		const char* tmp_at = m_at;
 		for (uint32_t i = 0; i < object.size(); i++)
 		{
-			TempAllocator256 key_alloc;
-			List<char> key(key_alloc);
-
+			DynamicString key;
 			json::parse_string(object[i].key, key);
 
-			if (string::strcmp(k, key.begin()) == 0)
+			if (key == k)
 			{
 				tmp_at = object[i].val;
 				found = true;
@@ -174,18 +165,15 @@ JSONElement JSONElement::key_or_nil(const char* k)
 //--------------------------------------------------------------------------
 bool JSONElement::has_key(const char* k) const
 {
-	TempAllocator1024 alloc;
-	List<JSONPair> object(alloc);
+	List<JSONPair> object(default_allocator());
 	json::parse_object(m_at, object);
 
 	for (uint32_t i = 0; i < object.size(); i++)
 	{
-		TempAllocator256 key_alloc;
-		List<char> key(key_alloc);
-
+		DynamicString key;
 		json::parse_string(object[i].key, key);
 
-		if (string::strcmp(k, key.begin()) == 0)
+		if (key == k)
 		{
 			return true;
 		}
@@ -197,20 +185,17 @@ bool JSONElement::has_key(const char* k) const
 //--------------------------------------------------------------------------
 bool JSONElement::is_key_unique(const char* k) const
 {
-	TempAllocator1024 alloc;
-	List<JSONPair> object(alloc);
+	List<JSONPair> object(default_allocator());
 	json::parse_object(m_at, object);
 
 	bool found = false;
 
 	for (uint32_t i = 0; i < object.size(); i++)
 	{
-		TempAllocator256 key_alloc;
-		List<char> key(key_alloc);
-
+		DynamicString key;
 		json::parse_string(object[i].key, key);
 
-		if (string::strcmp(k, key.begin()) == 0)
+		if (key == k)
 		{
 			if (found == true)
 			{
@@ -246,23 +231,15 @@ float JSONElement::float_value() const
 }
 
 //--------------------------------------------------------------------------
-const char* JSONElement::string_value() const
+void JSONElement::string_value(DynamicString& str) const
 {
-	static TempAllocator1024 alloc;
-	static List<char> string(alloc);
-
-	string.clear();
-
-	json::parse_string(m_at, string);
-
-	return string.begin();
+	json::parse_string(m_at, str);
 }
 
 //--------------------------------------------------------------------------
 void JSONElement::array_value(List<bool>& array) const
 {
-	TempAllocator1024 alloc;
-	List<const char*> temp(alloc);
+	List<const char*> temp(default_allocator());
 
 	json::parse_array(m_at, temp);
 
@@ -275,8 +252,7 @@ void JSONElement::array_value(List<bool>& array) const
 //--------------------------------------------------------------------------
 void JSONElement::array_value(List<int16_t>& array) const
 {
-	TempAllocator1024 alloc;
-	List<const char*> temp(alloc);
+	List<const char*> temp(default_allocator());
 
 	json::parse_array(m_at, temp);
 
@@ -289,8 +265,7 @@ void JSONElement::array_value(List<int16_t>& array) const
 //--------------------------------------------------------------------------
 void JSONElement::array_value(List<uint16_t>& array) const
 {
-	TempAllocator1024 alloc;
-	List<const char*> temp(alloc);
+	List<const char*> temp(default_allocator());
 
 	json::parse_array(m_at, temp);
 
@@ -303,8 +278,7 @@ void JSONElement::array_value(List<uint16_t>& array) const
 //--------------------------------------------------------------------------
 void JSONElement::array_value(List<int32_t>& array) const
 {
-	TempAllocator1024 alloc;
-	List<const char*> temp(alloc);
+	List<const char*> temp(default_allocator());
 
 	json::parse_array(m_at, temp);
 
@@ -317,8 +291,7 @@ void JSONElement::array_value(List<int32_t>& array) const
 //--------------------------------------------------------------------------
 void JSONElement::array_value(List<uint32_t>& array) const
 {
-	TempAllocator1024 alloc;
-	List<const char*> temp(alloc);
+	List<const char*> temp(default_allocator());
 
 	json::parse_array(m_at, temp);
 
@@ -331,8 +304,7 @@ void JSONElement::array_value(List<uint32_t>& array) const
 //--------------------------------------------------------------------------
 void JSONElement::array_value(List<float>& array) const
 {
-	TempAllocator1024 alloc;
-	List<const char*> temp(alloc);
+	List<const char*> temp(default_allocator());
 
 	json::parse_array(m_at, temp);
 
@@ -424,27 +396,23 @@ uint32_t JSONElement::size() const
 		}
 		case JSONType::OBJECT:
 		{
-			TempAllocator1024 alloc;
-			List<JSONPair> object(alloc);
+			List<JSONPair> object(default_allocator());
 			json::parse_object(m_at, object);
 
 			return object.size();
 		}
 		case JSONType::ARRAY:
 		{
-			TempAllocator1024 alloc;
-			List<const char*> array(alloc);
+			List<const char*> array(default_allocator());
 			json::parse_array(m_at, array);
 
 			return array.size();
 		}
 		case JSONType::STRING:
 		{
-			TempAllocator1024 alloc;
-			List<char> string(alloc);
+			DynamicString string;
 			json::parse_string(m_at, string);
-
-			return string::strlen(string.begin());
+			return string.length();
 		}
 		case JSONType::NUMBER:
 		{

+ 2 - 1
engine/core/json/JSONParser.h

@@ -33,6 +33,7 @@ namespace crown
 {
 
 class JSONParser;
+class DynamicString;
 
 /// Represents a JSON element.
 /// The objects of this class are valid until the parser
@@ -118,7 +119,7 @@ public:
 	/// The returned string is kept internally until the next call to
 	/// this function, so it is highly unsafe to just keep the pointer
 	/// instead of copying its content somewhere else.
-	const char*			string_value() const;
+	void				string_value(DynamicString& str) const;
 
 	/// Returns the array value of the element.
 	/// @note

+ 3 - 2
engine/resource/MaterialResource.cpp

@@ -52,8 +52,9 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	JSONElement tl = root.key("texture_layers");
 	for (uint32_t i = 0; i < tl.size(); i++)
 	{
-		DynamicString tex; tex = tl[i].string_value(); tex += ".texture";
-		ResourceId tex_id; tex_id.id = hash::murmur2_64(tex.c_str(), string::strlen(tex.c_str()), 0);
+		DynamicString tex;
+		tl[i].string_value(tex); tex += ".texture";
+		ResourceId tex_id; tex_id.id = hash::murmur2_64(tex.c_str(), tex.length(), 0);
 		texture_layers.push_back(tex_id);
 	}
 

+ 24 - 39
engine/resource/PackageResource.cpp

@@ -67,10 +67,9 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 
 		for (uint32_t i = 0; i < texture_array_size; i++)
 		{
-			TempAllocator256 alloc;
-			DynamicString texture_name(alloc);
-			texture_name += texture_array[i].string_value();
-			texture_name += ".texture";
+			DynamicString texture_name;
+			texture_array[i].string_value(texture_name); texture_name += ".texture";
+			Log::d("texture name = %s", texture_name.c_str());
 
 			if (!fs.is_file(texture_name.c_str()))
 			{
@@ -79,7 +78,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 			}
 
 			ResourceId id;
-			id.id = hash::murmur2_64(texture_name.c_str(), string::strlen(texture_name.c_str()), 0);
+			id.id = hash::murmur2_64(texture_name.c_str(), texture_name.length(), 0);
 			m_texture.push_back(id);
 		}
 	}
@@ -93,10 +92,8 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 
 		for (uint32_t i = 0; i < lua_array_size; i++)
 		{
-			TempAllocator256 alloc;
-			DynamicString lua_name(alloc);
-			lua_name += lua_array[i].string_value();
-			lua_name += ".lua";
+			DynamicString lua_name;
+			lua_array[i].string_value(lua_name); lua_name += ".lua";
 
 			if (!fs.is_file(lua_name.c_str()))
 			{
@@ -105,7 +102,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 			}
 
 			ResourceId id;
-			id.id = hash::murmur2_64(lua_name.c_str(), string::strlen(lua_name.c_str()), 0);
+			id.id = hash::murmur2_64(lua_name.c_str(), lua_name.length(), 0);
 			m_script.push_back(id);
 		}
 	}
@@ -118,10 +115,8 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 
 		for (uint32_t i = 0; i < sound_array_size; i++)
 		{
-			TempAllocator256 alloc;
-			DynamicString sound_name(alloc);
-			sound_name += sound_array[i].string_value();
-			sound_name += ".sound";
+			DynamicString sound_name;
+			sound_array[i].string_value(sound_name); sound_name += ".sound";
 
 			if (!fs.is_file(sound_name.c_str()))
 			{
@@ -143,10 +138,8 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 
 		for (uint32_t i = 0; i < mesh_array_size; i++)
 		{
-			TempAllocator256 alloc;
-			DynamicString mesh_name(alloc);
-			mesh_name += mesh_array[i].string_value();
-			mesh_name += ".mesh";
+			DynamicString mesh_name;
+			mesh_array[i].string_value(mesh_name); mesh_name += ".mesh";
 
 			if (!fs.is_file(mesh_name.c_str()))
 			{
@@ -155,7 +148,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 			}
 
 			ResourceId id;
-			id.id = hash::murmur2_64(mesh_name.c_str(), string::strlen(mesh_name.c_str()), 0);
+			id.id = hash::murmur2_64(mesh_name.c_str(), mesh_name.length(), 0);
 			m_mesh.push_back(id);
 		}
 	}
@@ -168,10 +161,8 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 
 		for (uint32_t i = 0; i < unit_array_size; i++)
 		{
-			TempAllocator256 alloc;
-			DynamicString unit_name(alloc);
-			unit_name += unit_array[i].string_value();
-			unit_name += ".unit";
+			DynamicString unit_name;
+			unit_array[i].string_value(unit_name); unit_name += ".unit";
 
 			if (!fs.is_file(unit_name.c_str()))
 			{
@@ -179,7 +170,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 			}
 
 			ResourceId id;
-			id.id = hash::murmur2_64(unit_name.c_str(), string::strlen(unit_name.c_str()), 0);
+			id.id = hash::murmur2_64(unit_name.c_str(), unit_name.length(), 0);
 			m_unit.push_back(id);
 		}
 	}
@@ -192,10 +183,8 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 
 		for (uint32_t i = 0; i < sprite_array_size; i++)
 		{
-			TempAllocator256 alloc;
-			DynamicString sprite_name(alloc);
-			sprite_name += sprite_array[i].string_value();
-			sprite_name += ".sprite";
+			DynamicString sprite_name;
+			sprite_array[i].string_value(sprite_name); sprite_name += ".sprite";
 
 			if (!fs.is_file(sprite_name.c_str()))
 			{
@@ -204,7 +193,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 			}
 
 			ResourceId id;
-			id.id = hash::murmur2_64(sprite_name.c_str(), string::strlen(sprite_name.c_str()), 0);
+			id.id = hash::murmur2_64(sprite_name.c_str(), sprite_name.length(), 0);
 			m_sprite.push_back(id);
 		}
 	}
@@ -217,10 +206,8 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 
 		for (uint32_t i = 0; i < physics_array_size; i++)
 		{
-			TempAllocator256 alloc;
-			DynamicString physics_name(alloc);
-			physics_name += physics_array[i].string_value();
-			physics_name += ".physics";
+			DynamicString physics_name;
+			physics_array[i].string_value(physics_name); physics_name += ".physics";
 
 			if (!fs.is_file(physics_name.c_str()))
 			{
@@ -229,7 +216,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 			}
 
 			ResourceId id;
-			id.id = hash::murmur2_64(physics_name.c_str(), string::strlen(physics_name.c_str()), 0);
+			id.id = hash::murmur2_64(physics_name.c_str(), physics_name.length(), 0);
 			m_physics.push_back(id);
 		}	
 	}
@@ -242,10 +229,8 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 
 		for (uint32_t i = 0; i < materials_array_size; i++)
 		{
-			TempAllocator256 alloc;
-			DynamicString materials_name(alloc);
-			materials_name += materials_array[i].string_value();
-			materials_name += ".material";
+			DynamicString materials_name;
+			materials_array[i].string_value(materials_name); materials_name += ".material";
 
 			if (!fs.is_file(materials_name.c_str()))
 			{
@@ -254,7 +239,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 			}
 
 			ResourceId id;
-			id.id = hash::murmur2_64(materials_name.c_str(), string::strlen(materials_name.c_str()), 0);
+			id.id = hash::murmur2_64(materials_name.c_str(), materials_name.length(), 0);
 			m_materials.push_back(id);
 		}
 	}

+ 18 - 5
engine/resource/PhysicsResource.cpp

@@ -30,6 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "JSONParser.h"
 #include "PhysicsResource.h"
 #include "StringUtils.h"
+#include "DynamicString.h"
 
 namespace crown
 {
@@ -58,7 +59,9 @@ void parse_controller(JSONElement e, PhysicsController& controller)
 	JSONElement step_offset = e.key("step_offset");
 	JSONElement contact_offset = e.key("contact_offset");
 
-	controller.name = hash::murmur2_32(name.string_value(), name.size());
+	DynamicString contr_name;
+	name.string_value(contr_name);
+	controller.name = hash::murmur2_32(contr_name.c_str(), contr_name.length());
 	controller.height = height.float_value();
 	controller.radius = radius.float_value();
 	controller.slope_limit = slope_limit.float_value();
@@ -72,8 +75,13 @@ void parse_shape(JSONElement e, PhysicsShape& shape)
 	JSONElement name = e.key("name");
 	JSONElement type = e.key("type");
 
-	shape.name = hash::murmur2_32(name.string_value(), name.size());
-	shape.type = shape_type_to_enum(type.string_value());
+	DynamicString shape_name;
+	DynamicString shape_type;
+	name.string_value(shape_name);
+	type.string_value(shape_type);
+
+	shape.name = hash::murmur2_32(shape_name.c_str(), shape_name.length());
+	shape.type = shape_type_to_enum(shape_type.c_str());
 }
 
 //-----------------------------------------------------------------------------
@@ -83,8 +91,13 @@ void parse_actor(JSONElement e, PhysicsActor& actor, List<PhysicsShape>& actor_s
 	JSONElement node = e.key("node");
 	JSONElement shapes = e.key("shapes");
 
-	actor.name = hash::murmur2_32(name.string_value(), name.size());
-	actor.node = hash::murmur2_32(node.string_value(), node.size());
+	DynamicString actor_name;
+	DynamicString actor_node;
+	name.string_value(actor_name);
+	node.string_value(actor_node);
+
+	actor.name = hash::murmur2_32(actor_name.c_str(), actor_name.length());
+	actor.node = hash::murmur2_32(actor_node.c_str(), actor_node.length());
 	actor.num_shapes = shapes.size();
 
 	for (uint32_t i = 0; i < actor.num_shapes; i++)

+ 4 - 1
engine/resource/SpriteResource.cpp

@@ -57,7 +57,10 @@ void parse_frame(JSONElement frame, List<StringId32>& names, List<FrameData>& re
 	JSONElement offset = frame.key("offset");
 	JSONElement scale = frame.key("scale");
 
-	StringId32 name_hash = hash::murmur2_32(name.string_value(), name.size(), 0);
+	DynamicString frame_name;
+	name.string_value(frame_name);
+
+	StringId32 name_hash = hash::murmur2_32(frame_name.c_str(), frame_name.length(), 0);
 	FrameData fd;
 	fd.x0 = region[0].float_value();
 	fd.y0 = region[1].float_value();

+ 57 - 21
engine/resource/UnitResource.cpp

@@ -124,9 +124,23 @@ void parse_node(JSONElement e, List<GraphNode>& nodes, List<GraphNodeDepth>& nod
 	JSONElement pos = e.key("position");
 	JSONElement rot = e.key("rotation");
 
+	DynamicString node_name;
+	name.string_value(node_name);
+
 	GraphNode gn;
-	gn.name = hash::murmur2_32(name.string_value(), name.size(), 0);
-	gn.parent = parent.is_nil() ? NO_PARENT : hash::murmur2_32(parent.string_value(), parent.size(), 0);
+	gn.name = hash::murmur2_32(node_name.c_str(), node_name.length(), 0);
+
+	if (parent.is_nil())
+	{
+		gn.parent = NO_PARENT;
+	}
+	else
+	{
+		DynamicString parent_name;
+		parent.string_value(parent_name);
+		hash::murmur2_32(parent_name.c_str(), parent_name.length(), 0);
+	}
+
 	gn.position = Vector3(pos[0].float_value(), pos[1].float_value(), pos[2].float_value());
 	gn.rotation = Quaternion(Vector3(rot[0].float_value(), rot[1].float_value(), rot[2].float_value()), rot[3].float_value());
 
@@ -145,11 +159,16 @@ void parse_camera(JSONElement e, List<UnitCamera>& cameras, const List<GraphNode
 	JSONElement name = e.key("name");
 	JSONElement node = e.key("node");
 
-	StringId32 node_name = hash::murmur2_32(node.string_value(), node.size(), 0);
+	DynamicString node_name;
+	DynamicString camera_name;
+	node.string_value(node_name);
+	name.string_value(camera_name);
+
+	StringId32 node_name_hash = hash::murmur2_32(node_name.c_str(), node_name.length(), 0);
 
 	UnitCamera cn;
-	cn.name = hash::murmur2_32(name.string_value(), name.size(), 0);
-	cn.node = find_node_index(node_name, node_depths);
+	cn.name = hash::murmur2_32(camera_name.c_str(), camera_name.length(), 0);
+	cn.node = find_node_index(node_name_hash, node_depths);
 
 	cameras.push_back(cn);
 }
@@ -163,33 +182,41 @@ void parse_renderable(JSONElement e, List<UnitRenderable>& renderables, const Li
 	JSONElement res = e.key("resource");
 	JSONElement vis = e.key("visible");
 
-	StringId32 node_name = hash::murmur2_32(node.string_value(), node.size(), 0);
+	DynamicString renderable_name;
+	DynamicString node_name;
+	name.string_value(renderable_name);
+	node.string_value(node_name);
+
+	StringId32 node_name_hash = hash::murmur2_32(node_name.c_str(), node_name.length(), 0);
 
 	UnitRenderable rn;
-	rn.name = hash::murmur2_32(name.string_value(), name.size(), 0);
-	rn.node = find_node_index(node_name, node_depths);
+	rn.name = hash::murmur2_32(renderable_name.c_str(), renderable_name.length(), 0);
+	rn.node = find_node_index(node_name_hash, node_depths);
 	rn.visible = vis.bool_value();
 
-	const char* res_type = type.string_value();
+	DynamicString res_type;
+	DynamicString resource_name;
+	type.string_value(res_type);
+	res.string_value(resource_name);
 	DynamicString res_name;
 
-	if (string::strcmp(res_type, "mesh") == 0)
+	if (res_type == "mesh")
 	{
 		rn.type = UnitRenderable::MESH;
-		res_name += res.string_value();
+		res_name += resource_name;
 		res_name += ".mesh";
 	}
-	else if (string::strcmp(res_type, "sprite") == 0)
+	else if (res_type == "sprite")
 	{
 		rn.type = UnitRenderable::SPRITE;
-		res_name += res.string_value();
+		res_name += resource_name;
 		res_name += ".sprite";
 	}
 	else
 	{
-		CE_ASSERT(false, "Oops, unknown renderable type: '%s'", res_type);
+		CE_ASSERT(false, "Oops, unknown renderable type: '%s'", res_type.c_str());
 	}
-	rn.resource.id = hash::murmur2_64(res_name.c_str(), string::strlen(res_name.c_str()), 0);
+	rn.resource.id = hash::murmur2_64(res_name.c_str(), res_name.length(), 0);
 
 	renderables.push_back(rn);
 }
@@ -203,14 +230,23 @@ void parse_actor(JSONElement e, List<UnitActor>& actors, const List<GraphNodeDep
 	JSONElement shape = e.key("shape");
 	JSONElement active = e.key("active");
 
-	StringId32 node_name = hash::murmur2_32(node.string_value(), node.size(), 0);
+	DynamicString actor_name;
+	DynamicString node_name;
+	DynamicString type_name;
+	DynamicString shape_name;
+	name.string_value(actor_name);
+	node.string_value(node_name);
+	type.string_value(type_name);
+	shape.string_value(shape_name);
+
+	StringId32 node_name_hash = hash::murmur2_32(node_name.c_str(), node_name.length(), 0);
 
 	UnitActor an;
-	an.name = hash::murmur2_32(name.string_value(), name.size(), 0);
-	an.node = find_node_index(node_name, node_depths);
-	an.type = string::strcmp(type.string_value(), "STATIC") == 0 ? UnitActor::STATIC : UnitActor::DYNAMIC;
-	an.shape = string::strcmp(shape.string_value(), "SPHERE") == 0 ? UnitActor::SPHERE :
-	 			string::strcmp(shape.string_value(), "BOX") == 0 ? UnitActor::BOX : UnitActor::PLANE;
+	an.name = hash::murmur2_32(actor_name.c_str(), actor_name.length(), 0);
+	an.node = find_node_index(node_name_hash, node_depths);
+	an.type = type_name == "STATIC" ? UnitActor::STATIC : UnitActor::DYNAMIC;
+	an.shape = shape_name == "SPHERE" ? UnitActor::SPHERE :
+	 			shape_name == "BOX" ? UnitActor::BOX : UnitActor::PLANE;
 	an.active = active.bool_value();
 
 	actors.push_back(an);