@@ -11,6 +11,10 @@ namespace Datamodel.Codecs
1111 [ CodecFormat ( "keyvalues2" , 2 ) ]
1212 [ CodecFormat ( "keyvalues2" , 3 ) ]
1313 [ CodecFormat ( "keyvalues2" , 4 ) ]
14+ [ CodecFormat ( "keyvalues2_noids" , 1 ) ]
15+ [ CodecFormat ( "keyvalues2_noids" , 2 ) ]
16+ [ CodecFormat ( "keyvalues2_noids" , 3 ) ]
17+ [ CodecFormat ( "keyvalues2_noids" , 4 ) ]
1418 class KeyValues2 : ICodec , IDisposable
1519 {
1620 TextReader Reader ;
@@ -59,7 +63,7 @@ public int Indent
5963 set
6064 {
6165 indent_count = value ;
62- indent_string = "\n " + String . Concat ( Enumerable . Repeat ( "\t " , value ) ) ;
66+ indent_string = "\n " + string . Concat ( Enumerable . Repeat ( " " , value ) ) ;
6367 }
6468 }
6569 int indent_count = 0 ;
@@ -91,7 +95,7 @@ public void Write(string value)
9195
9296 public void WriteTokens ( params string [ ] values )
9397 {
94- Output . Write ( " \" {0} \" " , String . Join ( "\" \" " , values . Select ( s => Sanitise ( s ) ) ) ) ;
98+ Output . Write ( '"' + string . Join ( "\" \" " , values . Select ( s => Sanitise ( s ) ) ) + '"' ) ;
9599 }
96100
97101 public void WriteLine ( )
@@ -129,12 +133,16 @@ public void Flush()
129133 Output . Flush ( ) ;
130134 }
131135 }
136+
137+ string Encoding ;
132138 int EncodingVersion ;
133139
134140 // Multi-referenced elements are written out as a separate block at the end of the file.
135141 // In-line only the id is written.
136142 Dictionary < Element , int > ReferenceCount ;
137143
144+ bool SupportsReferenceIds ;
145+
138146 void CountReferences ( Element elem )
139147 {
140148 if ( ReferenceCount . ContainsKey ( elem ) )
@@ -210,24 +218,29 @@ void WriteAttribute(string name, Type type, object value, bool in_array)
210218
211219 if ( in_array )
212220 {
213- if ( elem != null && ReferenceCount [ elem ] == 1 )
221+ if ( ShouldBeReferenced ( elem ) )
222+ {
223+ Writer . WriteTokenLine ( "element" , id ) ;
224+ }
225+ else
214226 {
215227 Writer . WriteLine ( ) ;
216228 WriteElement ( elem ) ;
217229 }
218- else
219- Writer . WriteTokenLine ( "element" , id ) ;
230+
220231 Writer . Write ( "," ) ;
221232 }
222233 else
223234 {
224- if ( elem != null && ReferenceCount . ContainsKey ( elem ) && ReferenceCount [ elem ] == 1 )
235+ if ( ShouldBeReferenced ( elem ) )
225236 {
226- Writer . WriteLine ( String . Format ( "\" {0}\" " , name ) ) ;
227- WriteElement ( elem ) ;
237+ Writer . WriteTokenLine ( name , "element" , id ) ;
228238 }
229239 else
230- Writer . WriteTokenLine ( name , "element" , id ) ;
240+ {
241+ Writer . WriteLine ( $ "\" { name } \" ") ;
242+ WriteElement ( elem ) ;
243+ }
231244 }
232245 }
233246 else
@@ -237,13 +250,13 @@ void WriteAttribute(string name, Type type, object value, bool in_array)
237250 else if ( type == typeof ( float ) )
238251 value = ( float ) value ;
239252 else if ( type == typeof ( byte [ ] ) )
240- value = BitConverter . ToString ( ( byte [ ] ) value ) . Replace ( "-" , String . Empty ) ;
253+ value = BitConverter . ToString ( ( byte [ ] ) value ) . Replace ( "-" , string . Empty ) ;
241254 else if ( type == typeof ( TimeSpan ) )
242255 value = ( ( TimeSpan ) value ) . TotalSeconds ;
243256 else if ( type == typeof ( Color ) )
244257 {
245258 var c = ( Color ) value ;
246- value = String . Join ( " " , new int [ ] { c . R , c . G , c . B , c . A } ) ;
259+ value = string . Join ( " " , new int [ ] { c . R , c . G , c . B , c . A } ) ;
247260 }
248261 else if ( value is ulong ulong_value )
249262 value = $ "0x{ ulong_value : X} ";
@@ -267,13 +280,11 @@ void WriteAttribute(string name, Type type, object value, bool in_array)
267280 }
268281 else if ( type == typeof ( Quaternion ) )
269282 {
270- var arr = new float [ 4 ] ;
271283 var q = ( Quaternion ) value ;
272284 value = string . Join ( " " , q . X , q . Y , q . Z , q . W ) ;
273285 }
274286 else if ( type == typeof ( Matrix4x4 ) )
275287 {
276- var arr = new float [ 4 * 4 ] ;
277288 var m = ( Matrix4x4 ) value ;
278289 value = string . Join ( " " , m . M11 , m . M12 , m . M13 , m . M14 , m . M21 , m . M22 , m . M23 , m . M24 , m . M31 , m . M32 , m . M33 , m . M34 , m . M41 , m . M42 , m . M43 , m . M44 ) ;
279290 }
@@ -290,14 +301,21 @@ void WriteAttribute(string name, Type type, object value, bool in_array)
290301
291302 }
292303
304+ private bool ShouldBeReferenced ( Element elem )
305+ {
306+ return SupportsReferenceIds && ( elem == null || ReferenceCount . TryGetValue ( elem , out var refCount ) && refCount > 1 ) ;
307+ }
308+
293309 void WriteElement ( Element element )
294310 {
295311 if ( TypeNames . ContainsValue ( element . ClassName ) )
296- throw new CodecException ( String . Format ( "Element {0 } uses reserved type name \" {1 }\" ." , element . ID , element . ClassName ) ) ;
312+ throw new CodecException ( $ "Element { element . ID } uses reserved type name \" { element . ClassName } \" " ) ;
297313 Writer . WriteTokens ( element . ClassName ) ;
298314 Writer . WriteLine ( "{" ) ;
299315 Writer . Indent ++ ;
300- Writer . WriteTokenLine ( "id" , "elementid" , element . ID . ToString ( ) ) ;
316+
317+ if ( SupportsReferenceIds )
318+ Writer . WriteTokenLine ( "id" , "elementid" , element . ID . ToString ( ) ) ;
301319
302320 // Skip empty names right now.
303321 if ( ! string . IsNullOrEmpty ( element . Name ) )
@@ -317,12 +335,15 @@ void WriteElement(Element element)
317335 Writer . WriteLine ( "}" ) ;
318336 }
319337
320- public void Encode ( Datamodel dm , int encoding_version , Stream stream )
338+ public void Encode ( Datamodel dm , string encoding , int encoding_version , Stream stream )
321339 {
322340 Writer = new KV2Writer ( stream ) ;
341+ Encoding = encoding ;
323342 EncodingVersion = encoding_version ;
324343
325- Writer . Write ( String . Format ( CodecUtilities . HeaderPattern , "keyvalues2" , encoding_version , dm . Format , dm . FormatVersion ) ) ;
344+ SupportsReferenceIds = Encoding != "keyvalues2_noids" ;
345+
346+ Writer . Write ( String . Format ( CodecUtilities . HeaderPattern , encoding , encoding_version , dm . Format , dm . FormatVersion ) ) ;
326347 Writer . WriteLine ( ) ;
327348
328349 ReferenceCount = new Dictionary < Element , int > ( ) ;
@@ -340,17 +361,22 @@ public void Encode(Datamodel dm, int encoding_version, Stream stream)
340361 Writer . WriteLine ( ) ;
341362 }
342363
343- CountReferences ( dm . Root ) ;
364+ if ( SupportsReferenceIds )
365+ CountReferences ( dm . Root ) ;
366+
344367 WriteElement ( dm . Root ) ;
345368 Writer . WriteLine ( ) ;
346369
347- foreach ( var pair in ReferenceCount . Where ( pair => pair . Value > 1 ) )
370+ if ( SupportsReferenceIds )
348371 {
349- if ( pair . Key == dm . Root )
350- continue ;
351- Writer . WriteLine ( ) ;
352- WriteElement ( pair . Key ) ;
353- Writer . WriteLine ( ) ;
372+ foreach ( var pair in ReferenceCount . Where ( pair => pair . Value > 1 ) )
373+ {
374+ if ( pair . Key == dm . Root )
375+ continue ;
376+ Writer . WriteLine ( ) ;
377+ WriteElement ( pair . Key ) ;
378+ Writer . WriteLine ( ) ;
379+ }
354380 }
355381
356382 Writer . Flush ( ) ;
@@ -559,10 +585,13 @@ object Decode_ParseValue(Type type, string value)
559585 else throw new ArgumentException ( $ "Internal error: ParseValue passed unsupported type: { type } .") ;
560586 }
561587
562- public Datamodel Decode ( int encoding_version , string format , int format_version , Stream stream , DeferredMode defer_mode )
588+ public Datamodel Decode ( string encoding , int encoding_version , string format , int format_version , Stream stream , DeferredMode defer_mode )
563589 {
564590 DM = new Datamodel ( format , format_version ) ;
565591
592+ if ( encoding == "keyvalues2_noids" )
593+ throw new NotImplementedException ( "KeyValues2_noids decoding not implemented." ) ;
594+
566595 stream . Seek ( 0 , SeekOrigin . Begin ) ;
567596 Reader = new StreamReader ( stream , Datamodel . TextEncoding ) ;
568597 Reader . ReadLine ( ) ; // skip DMX header
0 commit comments