Skip to content

Commit 21ed82e

Browse files
committed
Parser and serializer worksfine on a pbxproj file.
1 parent 773587d commit 21ed82e

File tree

3 files changed

+213
-12
lines changed

3 files changed

+213
-12
lines changed

PBXParser.cs

Lines changed: 195 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
using System;
33
using System.Collections;
44
using System.Collections.Generic;
5+
using System.Text;
56
using System.Text.RegularExpressions;
67

8+
79
namespace UnityEditor.XCodeEditor
810
{
911
public class PBXParser
1012
{
13+
public const string PBX_HEADER_TOKEN = "// !$*UTF8*$!\n";
1114
public const char WHITESPACE_SPACE = ' ';
1215
public const char WHITESPACE_TAB = '\t';
1316
public const char WHITESPACE_NEWLINE = '\n';
@@ -26,16 +29,18 @@ public class PBXParser
2629
public const string COMMENT_BEGIN_TOKEN = "/*";
2730
public const string COMMENT_END_TOKEN = "*/";
2831
public const string COMMENT_LINE_TOKEN = "//";
32+
private const int BUILDER_CAPACITY = 10000;
2933

3034
//
3135
private char[] data;
3236
private int index;
33-
// private bool success;
37+
// public bool success;
38+
private int indent;
3439

3540
public object Decode( string data )
3641
{
3742
// success = true;
38-
if( !data.StartsWith( "// !$*UTF8*$!" ) ) {
43+
if( !data.StartsWith( PBX_HEADER_TOKEN ) ) {
3944
Debug.Log( "Wrong file format." );
4045
return null;
4146
}
@@ -45,6 +50,16 @@ public object Decode( string data )
4550
return Parse();
4651
}
4752

53+
public string Encode( Dictionary<string, object> pbxData, bool readable = false )
54+
{
55+
indent = 0;
56+
57+
StringBuilder builder = new StringBuilder( PBX_HEADER_TOKEN, BUILDER_CAPACITY );
58+
bool success = SerializeValue( pbxData, builder, readable );
59+
60+
return ( success ? builder.ToString() : null );
61+
}
62+
4863
#region Move
4964

5065
private char NextToken()
@@ -218,7 +233,8 @@ private object ParseValue()
218233
private object ParseDictionary()
219234
{
220235
SkipWhitespaces();
221-
Hashtable dictionary = new Hashtable();
236+
// Hashtable dictionary = new Hashtable();
237+
Dictionary<string, object> dictionary = new Dictionary<string, object>();
222238
string keyString = string.Empty;
223239
object valueObject = null;
224240

@@ -345,6 +361,7 @@ private object ParseString()
345361

346362
c = StepForeward();
347363
}
364+
348365
return s;
349366

350367
// def parse_string(self):
@@ -394,6 +411,181 @@ private object ParseEntity()
394411
}
395412

396413
#endregion
414+
#region Serialize
415+
416+
private bool SerializeValue( object value, StringBuilder builder, bool readable = false )
417+
{
418+
if( value == null ) {
419+
builder.Append( "null" );
420+
}
421+
else if( value is Dictionary<string, object> ) {
422+
SerializeDictionary( (Dictionary<string, object> )value, builder, readable );
423+
}
424+
else if( value.GetType().IsArray ) {
425+
SerializeArray( new ArrayList( (ICollection)value ), builder, readable );
426+
}
427+
else if( value is ArrayList ) {
428+
SerializeArray( (ArrayList)value, builder, readable );
429+
}
430+
else if( value is string ) {
431+
SerializeString( (string)value, builder, readable );
432+
}
433+
else if( value is Char ) {
434+
SerializeString( Convert.ToString( (char)value ), builder, readable );
435+
}
436+
else if( value.GetType().IsPrimitive ) {
437+
// SerializeNumber( Convert.ToDouble( value ), builder );
438+
builder.Append( Convert.ToString( value ) );
439+
}
440+
// else if( value is Hashtable )
441+
// {
442+
// serializeObject( (Hashtable)value, builder );
443+
// }
444+
// else if( ( value is Boolean ) && ( (Boolean)value == true ) )
445+
// {
446+
// builder.Append( "true" );
447+
// }
448+
// else if( ( value is Boolean ) && ( (Boolean)value == false ) )
449+
// {
450+
// builder.Append( "false" );
451+
// }
452+
else {
453+
return false;
454+
}
455+
456+
return true;
457+
}
458+
459+
private bool SerializeDictionary( Dictionary<string, object> dictionary, StringBuilder builder, bool readable = false )
460+
{
461+
462+
builder.Append( DICTIONARY_BEGIN_TOKEN );
463+
464+
// bool first = true;
465+
foreach( KeyValuePair<string, object> pair in dictionary ) {
466+
// if( !first )
467+
// builder.Append( DICTIONARY_ITEM_DELIMITER_TOKEN );
468+
469+
SerializeString( pair.Key, builder );
470+
builder.Append( DICTIONARY_ASSIGN_TOKEN );
471+
SerializeValue( pair.Value, builder );
472+
builder.Append( DICTIONARY_ITEM_DELIMITER_TOKEN );
473+
// first = false;
474+
}
475+
476+
builder.Append( DICTIONARY_END_TOKEN );
477+
return true;
478+
}
479+
480+
private bool SerializeArray( ArrayList anArray, StringBuilder builder, bool readable = false )
481+
{
482+
builder.Append( ARRAY_BEGIN_TOKEN );
483+
484+
// bool first = true;
485+
for( int i = 0; i < anArray.Count; i++ )
486+
{
487+
object value = anArray[i];
488+
489+
// if( !first )
490+
// {
491+
// builder.Append( ARRAY_ITEM_DELIMITER_TOKEN );
492+
// }
493+
494+
if( !SerializeValue( value, builder ) )
495+
{
496+
return false;
497+
}
498+
499+
builder.Append( ARRAY_ITEM_DELIMITER_TOKEN );
500+
// first = false;
501+
}
502+
503+
builder.Append( ARRAY_END_TOKEN );
504+
return true;
505+
}
397506

507+
private bool SerializeString( string aString, StringBuilder builder, bool useQuotes = false, bool readable = false )
508+
{
509+
// Is a GUID?
510+
if( Regex.IsMatch( aString, @"^[A-F0-9]{24}$" ) ) {
511+
builder.Append( aString );
512+
return true;
513+
}
514+
515+
// Is an empty string?
516+
if( string.IsNullOrEmpty( aString ) ) {
517+
builder.Append( QUOTEDSTRING_BEGIN_TOKEN );
518+
builder.Append( QUOTEDSTRING_END_TOKEN );
519+
return true;
520+
}
521+
522+
if( !Regex.IsMatch( aString, @"^[A-Za-z0-9_.]+$" ) ) {
523+
useQuotes = true;
524+
}
525+
526+
if( useQuotes )
527+
builder.Append( QUOTEDSTRING_BEGIN_TOKEN );
528+
529+
builder.Append( aString );
530+
531+
// char[] charArray = aString.ToCharArray();
532+
// for( int i = 0; i < charArray.Length; i++ )
533+
// {
534+
// char c = charArray[i];
535+
// if( c == '"' )
536+
// {
537+
// builder.Append( "\"" );
538+
// }
539+
// else if( c == '\\' )
540+
// {
541+
// builder.Append( "\\\\" );
542+
// }
543+
// else if( c == '\b' )
544+
// {
545+
// builder.Append( "\\b" );
546+
// }
547+
// else if( c == '\f' )
548+
// {
549+
// builder.Append( "\\f" );
550+
// }
551+
// else if( c == '\n' )
552+
// {
553+
// builder.Append( "\\n" );
554+
// }
555+
// else if( c == '\r' )
556+
// {
557+
// builder.Append( "\\r" );
558+
// }
559+
// else if( c == '\t' )
560+
// {
561+
// builder.Append( "\\t" );
562+
// }
563+
// else
564+
// {
565+
// int codepoint = Convert.ToInt32( c );
566+
// if( ( codepoint >= 32 ) && ( codepoint <= 126 ) )
567+
// {
568+
// builder.Append( c );
569+
// }
570+
// else
571+
// {
572+
// builder.Append( "\\u" + Convert.ToString( codepoint, 16 ).PadLeft( 4, '0' ) );
573+
// }
574+
// }
575+
// }
576+
577+
if( useQuotes )
578+
builder.Append( QUOTEDSTRING_END_TOKEN );
579+
580+
return true;
581+
}
582+
583+
// private bool SerializeNumber( int number, StringBuilder builder )
584+
// {
585+
// builder.Append( Convert.ToString( number ) ); // , CultureInfo.InvariantCulture));
586+
// return true;
587+
// }
588+
589+
#endregion
398590
}
399591
}

XCProject.cs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ namespace UnityEditor.XCodeEditor
77
{
88
public class XCProject : System.IDisposable
99
{
10-
//private XCFileOperationQueue _fileOperrationQueue;
10+
private XCFileOperationQueue _fileOperrationQueue;
1111

1212
// private string _filePath;
13-
private Dictionary<string, string> _datastore;
14-
private Dictionary<string, string> _groups;
15-
private Dictionary<string, string> _configurations;
13+
private Dictionary<string, object> _datastore;
14+
private Dictionary<string, object> _groups;
15+
private Dictionary<string, object> _configurations;
1616
private string _defaultConfigurationName;
1717
private string _rootObjectKey;
1818

@@ -48,10 +48,15 @@ public XCProject( string filePath ) : this()
4848
string projPath = System.IO.Path.Combine( this.filePath, "project.pbxproj" );
4949
string contents = System.IO.File.OpenText( projPath ).ReadToEnd();
5050
// Debug.Log( System.IO.File.OpenText( projPath ).ReadToEnd );
51-
52-
IDictionary dictionary = (Hashtable)MiniJSON.jsonDecode( contents );
53-
54-
Debug.Log( dictionary );
51+
52+
PBXParser parser = new PBXParser();
53+
_datastore = (Dictionary<string, object>)parser.Decode( contents );
54+
if( _datastore == null ) {
55+
throw new System.Exception( "Project file not found at file path " + filePath );
56+
}
57+
58+
_fileOperrationQueue = new XCFileOperationQueue();
59+
_groups = new Dictionary<string, object>();
5560

5661
// if ((self = [super init])) {
5762
// _filePath = [filePath copy];

XCodeEditorMenu.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using UnityEngine;
22
using UnityEditor;
33
using System.Collections;
4+
using System.Collections.Generic;
45
using System.IO;
56

67
namespace UnityEditor.XCodeEditor
@@ -32,8 +33,11 @@ static void DebugTest2()
3233
// Debug.Log( System.IO.File.OpenText( projPath ).ReadToEnd );
3334

3435
PBXParser parser = new PBXParser();
35-
Hashtable test = (Hashtable)parser.Decode( contents );
36+
// Hashtable test = (Hashtable)parser.Decode( contents );
37+
Dictionary<string, object> test = (Dictionary<string, object>)parser.Decode( contents );
3638
Debug.Log( MiniJSON.jsonEncode( test ) );
39+
Debug.Log( test + " - " + test.Count );
40+
Debug.Log( parser.Encode( test ) );
3741
}
3842

3943
}

0 commit comments

Comments
 (0)