Fix JSON read off-by-one error

This commit is contained in:
Matt Nadareski
2020-08-24 14:29:00 -07:00
parent 92716402d9
commit 1aca090b79

View File

@@ -71,7 +71,7 @@ namespace SabreTools.Library.DatFiles
// Machine array // Machine array
case "machines": case "machines":
ReadMachines(sr, jtr, filename, indexId); ReadMachines(jtr, filename, indexId);
jtr.Read(); jtr.Read();
break; break;
@@ -109,12 +109,10 @@ namespace SabreTools.Library.DatFiles
/// <summary> /// <summary>
/// Read machine array information /// Read machine array information
/// </summary> /// </summary>
/// <param name="sr">StreamReader to use to parse the header</param>
/// <param name="itr">JsonTextReader to use to parse the machine</param> /// <param name="itr">JsonTextReader to use to parse the machine</param>
/// <param name="filename">Name of the file to be parsed</param> /// <param name="filename">Name of the file to be parsed</param>
/// <param name="indexId">Index ID for the DAT</param> /// <param name="indexId">Index ID for the DAT</param>
private void ReadMachines( private void ReadMachines(
StreamReader sr,
JsonTextReader jtr, JsonTextReader jtr,
// Standard Dat parsing // Standard Dat parsing
@@ -125,92 +123,57 @@ namespace SabreTools.Library.DatFiles
if (jtr == null) if (jtr == null)
return; return;
// Read in the machine array
jtr.Read(); jtr.Read();
while (!sr.EndOfStream) JsonSerializer js = new JsonSerializer();
{ JArray machineArray = js.Deserialize<JArray>(jtr);
// If we hit the end of an array, we want to return
if (jtr.TokenType == JsonToken.EndArray)
return;
// We don't care about anything except start object // Loop through each machine object and process
if (jtr.TokenType != JsonToken.StartObject) foreach (JObject machineObj in machineArray)
{ {
jtr.Read(); ReadMachine(machineObj, filename, indexId);
continue;
}
ReadMachine(sr, jtr, filename, indexId);
jtr.Read();
} }
} }
/// <summary> /// <summary>
/// Read machine object information /// Read machine object information
/// </summary> /// </summary>
/// <param name="sr">StreamReader to use to parse the header</param> /// <param name="machineObj">JObject representing a single machine</param>
/// <param name="itr">JsonTextReader to use to parse the machine</param>
/// <param name="filename">Name of the file to be parsed</param> /// <param name="filename">Name of the file to be parsed</param>
/// <param name="indexId">Index ID for the DAT</param> /// <param name="indexId">Index ID for the DAT</param>
private void ReadMachine( private void ReadMachine(
StreamReader sr, JObject machineObj,
JsonTextReader jtr,
// Standard Dat parsing // Standard Dat parsing
string filename, string filename,
int indexId) int indexId)
{ {
// If we have an empty machine, skip it // If object is invalid, skip it
if (jtr == null) if (machineObj == null)
return; return;
// Prepare internal variables // Prepare internal variables
JsonSerializer js = new JsonSerializer(); JsonSerializer js = new JsonSerializer();
Machine machine = null; Machine machine = null;
jtr.Read(); // Read the machine info, if possible
while (!sr.EndOfStream) if (machineObj.ContainsKey("machine"))
{ machine = machineObj["machine"].ToObject<Machine>();
// If we hit the end of the machine, return
if (jtr.TokenType == JsonToken.EndObject)
return;
// We don't care about anything except properties // Read items, if possible
if (jtr.TokenType != JsonToken.PropertyName) if (machineObj.ContainsKey("items"))
{ ReadItems(machineObj["items"] as JArray, filename, indexId, machine);
jtr.Read();
continue;
}
switch (jtr.Value)
{
case "machine":
jtr.Read();
machine = js.Deserialize<Machine>(jtr);
break;
case "items":
ReadItems(sr, jtr, filename, indexId, machine);
break;
default:
break;
}
jtr.Read();
}
} }
/// <summary> /// <summary>
/// Read item array information /// Read item array information
/// </summary> /// </summary>
/// <param name="sr">StreamReader to use to parse the header</param> /// <param name="itemsArr">JArray representing the items list</param>
/// <param name="jtr">JsonTextReader to use to parse the machine</param>
/// <param name="filename">Name of the file to be parsed</param> /// <param name="filename">Name of the file to be parsed</param>
/// <param name="indexId">Index ID for the DAT</param> /// <param name="indexId">Index ID for the DAT</param>
/// <param name="machine">Machine information to add to the parsed items</param> /// <param name="machine">Machine information to add to the parsed items</param>
private void ReadItems( private void ReadItems(
StreamReader sr, JArray itemsArr,
JsonTextReader jtr,
// Standard Dat parsing // Standard Dat parsing
string filename, string filename,
@@ -219,40 +182,26 @@ namespace SabreTools.Library.DatFiles
// Miscellaneous // Miscellaneous
Machine machine) Machine machine)
{ {
// If the reader is invalid, skip // If the array is invalid, skip
if (jtr == null) if (itemsArr == null)
return; return;
jtr.Read(); // Loop through each datitem object and process
while (!sr.EndOfStream) foreach (JObject itemObj in itemsArr)
{ {
// If we hit the end of an array, we want to return ReadItem(itemObj, filename, indexId, machine);
if (jtr.TokenType == JsonToken.EndArray)
return;
// We don't care about anything except start object
if (jtr.TokenType != JsonToken.StartObject)
{
jtr.Read();
continue;
}
ReadItem(sr, jtr, filename, indexId, machine);
jtr.Read();
} }
} }
/// <summary> /// <summary>
/// Read item information /// Read item information
/// </summary> /// </summary>
/// <param name="sr">StreamReader to use to parse the header</param> /// <param name="machineObj">JObject representing a single datitem</param>
/// <param name="jtr">JsonTextReader to use to parse the machine</param>
/// <param name="filename">Name of the file to be parsed</param> /// <param name="filename">Name of the file to be parsed</param>
/// <param name="indexId">Index ID for the DAT</param> /// <param name="indexId">Index ID for the DAT</param>
/// <param name="machine">Machine information to add to the parsed items</param> /// <param name="machine">Machine information to add to the parsed items</param>
private void ReadItem( private void ReadItem(
StreamReader sr, JObject itemObj,
JsonTextReader jtr,
// Standard Dat parsing // Standard Dat parsing
string filename, string filename,
@@ -261,43 +210,17 @@ namespace SabreTools.Library.DatFiles
// Miscellaneous // Miscellaneous
Machine machine) Machine machine)
{ {
// If we have an empty machine, skip it // If we have an empty item, skip it
if (jtr == null) if (itemObj == null)
return; return;
// Prepare internal variables // Prepare internal variables
JsonSerializer js = new JsonSerializer();
DatItem datItem = null; DatItem datItem = null;
jtr.Read(); // Read the datitem info, if possible
while (!sr.EndOfStream) if (itemObj.ContainsKey("datitem"))
{ {
// If we hit the end of the machine - create, add, and return JToken datItemObj = itemObj["datitem"];
if (jtr.TokenType == JsonToken.EndObject)
{
// If we didn't read something valid, just return
if (datItem == null)
return;
datItem.CopyMachineInformation(machine);
datItem.Source = new Source { Index = indexId, Name = filename };
ParseAddHelper(datItem);
return;
}
// We don't care about anything except properties
if (jtr.TokenType != JsonToken.PropertyName)
{
jtr.Read();
continue;
}
switch (jtr.Value)
{
case "datitem":
jtr.Read();
JObject datItemObj = js.Deserialize<JObject>(jtr);
switch (datItemObj.Value<string>("type").AsItemType()) switch (datItemObj.Value<string>("type").AsItemType())
{ {
case ItemType.Archive: case ItemType.Archive:
@@ -322,14 +245,14 @@ namespace SabreTools.Library.DatFiles
datItem = datItemObj.ToObject<Sample>(); datItem = datItemObj.ToObject<Sample>();
break; break;
} }
break;
default:
break;
} }
jtr.Read(); // If we got a valid datitem, copy machine info and add
if (datItem != null)
{
datItem.CopyMachineInformation(machine);
datItem.Source = new Source { Index = indexId, Name = filename };
ParseAddHelper(datItem);
} }
} }