forked from SoylentGraham/PopUnityCommon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
JsonSanitiser.cs
202 lines (167 loc) · 5.66 KB
/
JsonSanitiser.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Text.RegularExpressions;
namespace PopX
{
public class JsonSanitiser
{
/*
This function looks through json for anonymous double arrays that unity can't handle, and lets you inject an object with a name in
front of it so you can use JsonUtility and unity's serialising in the same way
problem:
"points": [ [0,0,0], [1,1,1], [2,2,2] ],
goal:
"points": [ { "myvector":[0,0,0] }, { "myvector":[1,1,1] }, { "myvector":[2,2,2] } ],
// can then deserialise as normal
class TVector
{
public float[] myvector;
};
class TPoints
{
public TVector[] points;
}
// to do the above
JsonSanitiser.DoubleArrayToMember( Json, (ParentName) => { return ParentName == "points" ? "myvector" : null; } );
*/
public static string DoubleArrayToMember(string Json,System.Func<string,string> ReplaceHeriachyDoubleArrayWithMemberName)
{
// find all double arrays
// match (with whitepspace)
// name semicolon [ [
var NamePattern = "([\"]{1}[A-Za-z0-9]+[\"]{1})";
var SemiColonPattern = "([\\s]*):([\\s]*)";
var ParenthesisPattern = "\\[([\\s]*)\\[";
var DoubleArrayPattern = NamePattern + SemiColonPattern + ParenthesisPattern;
var RegExpression = new Regex(DoubleArrayPattern);
int Iterations = 0; // stop infinite loops
int StringIndex = 0;
do {
var match = RegExpression.Match (Json, StringIndex);
if ( match == null )
break;
if ( match.Groups.Count < 2 )
break;
var WholeMatch = match.Groups[0].Captures[0];
var Name = match.Groups[1].Captures[0];
try
{
// if we don't parse anything, step over. if we do, re-parse from here so we can do recursive sub anonymous arrays
if ( !ParseCapture( Name, ref Json, ReplaceHeriachyDoubleArrayWithMemberName ) )
StringIndex = match.Index + match.Length;
}
catch (System.Exception e)
{
Debug.LogException(e);
break;
}
}
while(Iterations++ < 5000);
return Json;
}
static string ExtractNextChunk(char StartChar,char EndChar,string Haystack,ref int NeedleStart,ref int NeedleEnd)
{
// now grab the entire next section by balancing square brackets.
var BracketCount = 1;
// todo: count when we're inside sections where we need to ignore opening and closing brackets... eg. /* hello :] */ and "Bye :[ "
//var BraceCount = 0;
//var QuoteCount = 0;
//var CommentCount = 0;
var SearchStart = Haystack.IndexOf(StartChar,NeedleStart);
if (SearchStart == -1)
return null;
NeedleStart = SearchStart;
var StringIndex = NeedleStart+1;
while (BracketCount > 0)
{
if (StringIndex >= Haystack.Length)
throw new System.Exception ("Unbalanced array" + StartChar+EndChar + " in json");
var ThisChar = Haystack [StringIndex];
if ( ThisChar == StartChar )
BracketCount++;
if ( ThisChar == EndChar )
BracketCount--;
StringIndex++;
}
// we now have the whole double array. trim off the outer []
NeedleEnd = StringIndex;
var DoubleArrayString = Haystack.Substring (NeedleStart, NeedleEnd - NeedleStart );
return DoubleArrayString;
}
struct TChunk
{
public string Chunk;
public int Start;
public int End;
};
// return if changed
static bool ParseCapture(Capture NameMatch,ref string Json,System.Func<string,string> ReplaceHeriachyDoubleArrayWithMemberName)
{
// todo: have a full heirachy name, not just this element
var HeirachyName = NameMatch.ToString().Trim( new char[]{'"'} );
var InjectMemberName = ReplaceHeriachyDoubleArrayWithMemberName.Invoke (HeirachyName);
if (InjectMemberName == null)
return false;
// grab the whole double array string after semi colon
int NameEnd = NameMatch.Index + NameMatch.Length;
int ArrayStart = Json.IndexOf('[', NameEnd );
if (ArrayStart == -1)
throw new System.Exception ("Can't find start of array");
int DoubleArrayStart = ArrayStart;
int DoubleArrayEnd = ArrayStart;
var DoubleArray = ExtractNextChunk ('[', ']', Json, ref DoubleArrayStart, ref DoubleArrayEnd );
// get each array
var ArrayElements = new List<TChunk>();
int ChunkStart = 1;
while (true) {
var NewChunk = new TChunk ();
NewChunk.Start = ChunkStart;
NewChunk.End = ChunkStart;
NewChunk.Chunk = ExtractNextChunk ('[', ']', DoubleArray, ref NewChunk.Start, ref NewChunk.End);
if (NewChunk.Chunk == null)
break;
ChunkStart = NewChunk.End;
// correct for final usage
NewChunk.Start += ArrayStart;
NewChunk.End += ArrayStart;
ArrayElements.Add (NewChunk);
}
//Debug.Log ("Found " + ArrayElements.Count + " elements;");
//foreach (var Element in ArrayElements)
// Debug.Log (Element.Chunk);
// inject object & member name for every element
// do back to front so we don't need to correct indexes for elements
ArrayElements.Reverse ();
// { "myvector":
var InjectPrefix = " { \"" + InjectMemberName + "\" : ";
var InjectSuffix = " } ";
foreach (var Element in ArrayElements) {
Json = Json.Insert (Element.End, InjectSuffix);
Json = Json.Insert (Element.Start, InjectPrefix);
}
return true;
}
/*
public static void Test_JsonCleanDoubleArrays()
{
var Json = "{ \"points\": [ [0,0,0], [1,1,1], [2,2,2] ] }";
Json = JsonCleanDoubleArrays (Json, (Heirachy) => {
Debug.Log(Heirachy);
return null;
}
);
}
public static void Test_JsonCleanDoubleArrays2()
{
var Json = "{ \"points\": [ [0,0,0], [1,1,1], [2,2,2] ], \"morepoints\": [ [3,4,5], [6,7,8], [9,10,11] ] }";
Json = JsonCleanDoubleArrays (Json, (Heirachy) => {
Debug.Log(Heirachy);
return "float3";
}
);
Debug.Log ("Injected json: " + Json);
}
*/
}
}