@@ -16,6 +16,8 @@ public class JSONFormat implements IFormatCodec {
1616 private static final char JSON_CONTINUE = ',' ;
1717 private static final char JSON_STRING_LINE = '"' ;
1818 private static final char JSON_ENTRY_SPLIT = ':' ;
19+ private static final char JSON_ARRAY_START = '[' ;
20+ private static final char JSON_ARRAY_END = ']' ;
1921 private static final char JSON_ESCAPED = '\\' ;
2022
2123 @ Override public String id () { return OmegaConfig .FORMAT_JSON ; }
@@ -24,14 +26,218 @@ public class JSONFormat implements IFormatCodec {
2426
2527 @ Override
2628 public IFormatReader createReader (Path filePath ) throws IOException {
27- return new FormatReader (filePath );
29+ return new AnotherFormatReader (filePath );
2830 }
2931
3032 @ Override
3133 public IFormatWriter createWritter (Path filePath ) throws IOException {
3234 return null ;
3335 }
3436
37+ private record NextChar (char [] expected , char [] allowed ) {
38+
39+ public boolean isExpected (char c ) {
40+ return Tools .contains (c , expected );
41+ }
42+
43+ public boolean isAllowed (char c ) {
44+ if (allowed == null ) return false ;
45+ return Tools .contains (c , allowed );
46+ }
47+ }
48+
49+ public enum CapturingMode {
50+ NONE ,
51+ KEY ,
52+ PRIMITIVE_VALUE ,
53+ STRING_VALUE ,
54+ ARRAY ,
55+ ARRAY_PRIMITIVE_VALUE ,
56+ ARRAY_STRING_VALUE ;
57+
58+ public boolean value () {
59+ return this == PRIMITIVE_VALUE || this == STRING_VALUE ;
60+ }
61+
62+ public boolean string () {
63+ return this == STRING_VALUE || this == KEY ;
64+ }
65+ }
66+
67+ public static class AnotherFormatReader implements IFormatReader {
68+ public final LinkedHashMap <String , String > values = new LinkedHashMap <>();
69+
70+ @ Override
71+ public String read (String fieldName ) {
72+ return "" ;
73+ }
74+
75+ @ Override
76+ public void push (String group ) {
77+
78+ }
79+
80+ @ Override
81+ public void pop () {
82+
83+ }
84+
85+ @ Override
86+ public void close () throws IOException {
87+
88+ }
89+
90+ public AnotherFormatReader (Path path ) throws IOException {
91+ // READ JSON STRING
92+ var in = new FileInputStream (path .toFile ());
93+ char [] data = new String (in .readAllBytes ()).toCharArray ();
94+ in .close ();
95+
96+ NextChar nextChars = new NextChar (new char [] { JSON_OBJECT_START }, null );
97+ CapturingMode capturing = CapturingMode .NONE ;
98+ final LinkedHashSet <String > group = new LinkedHashSet <>();
99+ StringBuilder key = new StringBuilder ();
100+ StringBuilder value = new StringBuilder ();
101+ List <String > valueArray = new ArrayList <>();
102+ boolean escaped = false ;
103+ boolean finished = false ;
104+
105+ for (char c : data ) {
106+ // SKIP WHITESPACE PROCESING WHEN IS NOT CAPTURING NON-STRING-VALUES
107+ if (Character .isWhitespace (c ) && (capturing != CapturingMode .STRING_VALUE )) continue ;
108+
109+ // THROW WHEN JSON SPEC IS FINISHED BUT STILL CONTAINS DATA (WTF)
110+ if (finished ) {
111+ throw new EOFException ("Reached end of JSON spec but file still contains data" );
112+ }
113+
114+ // VALIDATE CHARS
115+ if (nextChars != null && !nextChars .isExpected (c )) {
116+ if (nextChars .isAllowed (c )) {
117+ // TODO: handle permisive chars
118+ }
119+
120+ throw new IllegalStateException ("Expected char(s) " + Arrays .toString (nextChars .expected ) + " but received " + c );
121+ }
122+
123+ // CHAR DETECTION
124+ switch (c ) {
125+ case JSON_OBJECT_START -> {
126+ if (capturing == CapturingMode .PRIMITIVE_VALUE ) {
127+ group .add (key .toString ());
128+ key = new StringBuilder ();
129+ capturing = CapturingMode .NONE ;
130+ }
131+
132+ nextChars = new NextChar (new char [] { JSON_STRING_LINE , JSON_OBJECT_END }, null );
133+ continue ;
134+ }
135+
136+ case JSON_ARRAY_START -> {
137+ if (capturing .string ()) {
138+ break ;
139+ }
140+ capturing = CapturingMode .ARRAY_PRIMITIVE_VALUE ;
141+ continue ;
142+ }
143+
144+ case JSON_STRING_LINE -> {
145+ // IF IS CAPTURING AND KEY IS ESCAPED THEN SKIP PROCESING
146+ if (escaped && (capturing == CapturingMode .KEY || capturing == CapturingMode .STRING_VALUE )) {
147+ break ;
148+ }
149+
150+ if (capturing == CapturingMode .ARRAY_PRIMITIVE_VALUE ) {
151+ capturing = CapturingMode .ARRAY_STRING_VALUE ;
152+ continue ;
153+ }
154+
155+ // FINISHED CAPTURING
156+ if (capturing == CapturingMode .STRING_VALUE ) {
157+ capturing = CapturingMode .NONE ;
158+ values .put (Tools .concat ("" , key .toString (), '.' , group ), value .toString ());
159+ key = new StringBuilder ();
160+ value = new StringBuilder ();
161+
162+ nextChars = new NextChar (new char [] { JSON_CONTINUE , JSON_OBJECT_END }, null );
163+ continue ;
164+ }
165+
166+ // IS NOT A STRING VALUE
167+ if (capturing == CapturingMode .PRIMITIVE_VALUE ) {
168+ capturing = CapturingMode .STRING_VALUE ;
169+ nextChars = null ;
170+ continue ;
171+ }
172+
173+ // KEY CAPTURING FINISHED
174+ if (capturing == CapturingMode .KEY ) {
175+ capturing = CapturingMode .NONE ;
176+ nextChars = new NextChar (new char [] { JSON_ENTRY_SPLIT }, null );
177+ continue ;
178+ }
179+
180+ capturing = CapturingMode .KEY ;
181+ nextChars = null ;
182+ continue ;
183+ }
184+
185+ case JSON_ESCAPED -> {
186+ escaped = true ;
187+ continue ;
188+ }
189+
190+ case JSON_ENTRY_SPLIT -> {
191+ if (capturing .string ()) {
192+ break ;
193+ }
194+ capturing = CapturingMode .PRIMITIVE_VALUE ;
195+ nextChars = null ;
196+ continue ;
197+ }
198+
199+ case JSON_CONTINUE -> {
200+ // DO NOT CAPTURE WHEN IS CAPTURING A KEY
201+ if (capturing .string ()) {
202+ break ;
203+ }
204+ if (capturing == CapturingMode .PRIMITIVE_VALUE ) {
205+ values .put (Tools .concat ("" , key .toString (), '.' , group ), value .toString ());
206+ capturing = CapturingMode .NONE ;
207+ key = new StringBuilder ();
208+ value = new StringBuilder ();
209+ }
210+
211+ nextChars = new NextChar (new char [] { JSON_STRING_LINE , JSON_OBJECT_END }, null );
212+ continue ;
213+ }
214+
215+ case JSON_OBJECT_END -> {
216+ if (group .isEmpty ()) {
217+ finished = true ;
218+ capturing = CapturingMode .NONE ;
219+ nextChars = null ;
220+ continue ;
221+ }
222+ group .removeLast ();
223+ nextChars = new NextChar (new char []{ JSON_CONTINUE , JSON_OBJECT_END }, null );
224+ continue ;
225+ }
226+ }
227+
228+ // OR BY DEFAULT, CAPTURE
229+ switch (capturing ) {
230+ case KEY -> key .append (c );
231+ case STRING_VALUE , PRIMITIVE_VALUE -> value .append (c );
232+ case NONE -> throw new IllegalStateException ("Not capturing values" );
233+ }
234+
235+ escaped = false ;
236+ }
237+ }
238+ }
239+
240+
35241 public static class FormatReader implements IFormatReader {
36242 public final LinkedHashMap <String , String > values = new LinkedHashMap <>();
37243
0 commit comments