From 75927641cf919ee17f3820176b6fa05f503e5983 Mon Sep 17 00:00:00 2001 From: dcariola Date: Sat, 22 Sep 2012 00:10:26 +0200 Subject: [PATCH] Complete PBX structure. TODO: convert pbxlist to generic --- PBXBuildFile.cs | 102 ++++++++++ XCGroup.cs.meta => PBXBuildFile.cs.meta | 2 +- PBXBuildPhase.cs | 100 ++++++++++ PBXBuildPhase.cs.meta | 7 + PBXDictionary.cs | 11 ++ PBXDictionary.cs.meta | 7 + PBXFileReference.cs | 118 +++++++++++ PBXFileReference.cs.meta | 7 + PBXGroup.cs | 137 +++++++++++++ PBXGroup.cs.meta | 7 + PBXList.cs | 19 ++ PBXList.cs.meta | 7 + PBXParser.cs | 247 ++---------------------- PBXType.cs | 89 +++++++++ PBXType.cs.meta | 7 + XCBuildConfigurationList.cs | 138 ++++++++++++- XCConfigurationList.cs | 13 ++ XCConfigurationList.cs.meta | 7 + XCGroup.cs | 15 -- XCProject.cs | 58 +++--- XCodeEditorMenu.cs | 25 ++- 21 files changed, 840 insertions(+), 283 deletions(-) create mode 100644 PBXBuildFile.cs rename XCGroup.cs.meta => PBXBuildFile.cs.meta (76%) create mode 100644 PBXBuildPhase.cs create mode 100644 PBXBuildPhase.cs.meta create mode 100644 PBXDictionary.cs create mode 100644 PBXDictionary.cs.meta create mode 100644 PBXFileReference.cs create mode 100644 PBXFileReference.cs.meta create mode 100644 PBXGroup.cs create mode 100644 PBXGroup.cs.meta create mode 100644 PBXList.cs create mode 100644 PBXList.cs.meta create mode 100644 PBXType.cs create mode 100644 PBXType.cs.meta create mode 100644 XCConfigurationList.cs create mode 100644 XCConfigurationList.cs.meta delete mode 100644 XCGroup.cs diff --git a/PBXBuildFile.cs b/PBXBuildFile.cs new file mode 100644 index 0000000..711e335 --- /dev/null +++ b/PBXBuildFile.cs @@ -0,0 +1,102 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEditor.XCodeEditor +{ + public class PBXBuildFile : PBXType + { + const string SETTINGS_KEY = "settings"; + const string ATTRIBUTES_KEY = "ATTRIBUTES"; + const string WEAK_VALUE = "Weak"; + const string COMPILER_FLAGS_KEY = "COMPILER_FLAGS"; + + public PBXBuildFile( string fileRef, bool weak = false ) : base() + { + +// def Create(cls, file_ref, weak=False): +// if isinstance(file_ref, PBXFileReference): +// file_ref = file_ref.id +// +// bf = cls() +// bf.id = cls.GenerateId() +// bf['fileRef'] = file_ref +// +// if weak: +// bf.set_weak_link(True) +// +// return bf + } + + + public bool SetWeakLink( bool weak = false ) + { + PBXDictionary settings = this[SETTINGS_KEY] as PBXDictionary; + PBXList attributes = null; + + if( settings == null ) { + if( weak ) { + attributes = new PBXList(); + attributes.Add( WEAK_VALUE ); + + settings = new PBXDictionary(); + settings.Add( ATTRIBUTES_KEY, attributes ); + } + return true; + } + + attributes = settings[ ATTRIBUTES_KEY ] as PBXList; + if( attributes == null ) { + if( weak ) { + attributes = new PBXList(); + } + else { + return false; + } + } + + if( weak ) { + attributes.Add( WEAK_VALUE ); + } + else { + attributes.Remove( WEAK_VALUE ); + } + + settings.Add( ATTRIBUTES_KEY, attributes ); + this.Add( SETTINGS_KEY, settings ); + + return true; + } + + public bool AddCompilerFlag( string flag ) + { +// if( !this.ContainsKey( SETTINGS_KEY ) ) +// this[ SETTINGS_KEY ] = new PBXDictionary(); +// +// if( !(PBXDictionary)this[ SETTINGS_KEY ] + + return false; + +// def add_compiler_flag(self, flag): +// k_settings = 'settings' +// k_attributes = 'COMPILER_FLAGS' +// +// if not self.has_key(k_settings): +// self[k_settings] = PBXDict() +// +// if not self[k_settings].has_key(k_attributes): +// self[k_settings][k_attributes] = flag +// return True +// +// flags = self[k_settings][k_attributes].split(' ') +// +// if flag in flags: +// return False +// +// flags.append(flag) +// +// self[k_settings][k_attributes] = ' '.join(flags) + } + + } +} diff --git a/XCGroup.cs.meta b/PBXBuildFile.cs.meta similarity index 76% rename from XCGroup.cs.meta rename to PBXBuildFile.cs.meta index 71ea43e..4b5171b 100644 --- a/XCGroup.cs.meta +++ b/PBXBuildFile.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a3726dc4a1bec439fa2e9b40556bfadc +guid: ffd51577e814940a8a93200cde422eb0 MonoImporter: serializedVersion: 2 defaultReferences: [] diff --git a/PBXBuildPhase.cs b/PBXBuildPhase.cs new file mode 100644 index 0000000..2487559 --- /dev/null +++ b/PBXBuildPhase.cs @@ -0,0 +1,100 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEditor.XCodeEditor +{ + public class PBXBuildPhase : PBXType + { + protected const string FILES_KEY = "files"; + + public bool AddBuildFile( PBXBuildFile file ) + { + if( ((string)file[ ISA_KEY ]).CompareTo( "PBXBuildFile" ) != 0 ) + return false; + + if( !ContainsKey( FILES_KEY ) ) + this.Add( FILES_KEY, new PBXList() ); + + ((PBXList)this[ FILES_KEY ]).Add( file.id ); + return true; + } + + public void RemoveBuildFile( string id ) + { + if( !ContainsKey( FILES_KEY ) ) { + this.Add( FILES_KEY, new PBXList() ); + return; + } + + ((PBXList)this[ FILES_KEY ]).Remove( id ); + } + + public bool HasBuildFile( string id ) + { + if( !ContainsKey( FILES_KEY ) ) { + this.Add( FILES_KEY, new PBXList() ); + return false; + } + + if( !IsGuid( id ) ) + return false; + + return ((PBXList)this[ FILES_KEY ]).Contains( id ); + } + +// class PBXBuildPhase(PBXType): +// def add_build_file(self, bf): +// if bf.get('isa') != 'PBXBuildFile': +// return False +// +// if not self.has_key('files'): +// self['files'] = PBXList() +// +// self['files'].add(bf.id) +// +// return True +// +// def remove_build_file(self, id): +// if not self.has_key('files'): +// self['files'] = PBXList() +// return +// +// self['files'].remove(id) +// +// def has_build_file(self, id): +// if not self.has_key('files'): +// self['files'] = PBXList() +// return False +// +// if not PBXType.IsGuid(id): +// id = id.id +// +// return id in self['files'] + } + + public class PBXFrameworksBuildPhase : PBXBuildPhase + { + + } + + public class PBXResourcesBuildPhase : PBXBuildPhase + { + + } + + public class PBXShellScriptBuildPhase : PBXBuildPhase + { + + } + + public class PBXSourcesBuildPhase : PBXBuildPhase + { + + } + + public class PBXCopyFilesBuildPhase : PBXBuildPhase + { + + } +} diff --git a/PBXBuildPhase.cs.meta b/PBXBuildPhase.cs.meta new file mode 100644 index 0000000..e20c630 --- /dev/null +++ b/PBXBuildPhase.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 45e20ea7193b74e02b784077e774b23f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/PBXDictionary.cs b/PBXDictionary.cs new file mode 100644 index 0000000..6b6f590 --- /dev/null +++ b/PBXDictionary.cs @@ -0,0 +1,11 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEditor.XCodeEditor +{ + public class PBXDictionary : Dictionary + { + + } +} diff --git a/PBXDictionary.cs.meta b/PBXDictionary.cs.meta new file mode 100644 index 0000000..041587d --- /dev/null +++ b/PBXDictionary.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e2d23f084277542dbbe7a017cb9799ce +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/PBXFileReference.cs b/PBXFileReference.cs new file mode 100644 index 0000000..2610312 --- /dev/null +++ b/PBXFileReference.cs @@ -0,0 +1,118 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEditor.XCodeEditor +{ + public class PBXFileReference : PBXType + { + public string buildPhase; + public readonly Dictionary types = new Dictionary { + {"a", "archive.ar" } +// {".a", {"archive.ar", "PBXFrameworksBuildPhase"}}, +// {".app", {"wrapper.application", null }} + }; +// '.a':('archive.ar', 'PBXFrameworksBuildPhase'), +// '.app': ('wrapper.application', None), +// '.s': ('sourcecode.asm', 'PBXSourcesBuildPhase'), +// '.c': ('sourcecode.c.c', 'PBXSourcesBuildPhase'), +// '.cpp': ('sourcecode.cpp.cpp', 'PBXSourcesBuildPhase'), +// '.framework': ('wrapper.framework','PBXFrameworksBuildPhase'), +// '.h': ('sourcecode.c.h', None), +// '.icns': ('image.icns','PBXResourcesBuildPhase'), +// '.m': ('sourcecode.c.objc', 'PBXSourcesBuildPhase'), +// '.mm': ('sourcecode.cpp.objcpp', 'PBXSourcesBuildPhase'), +// '.nib': ('wrapper.nib', 'PBXResourcesBuildPhase'), +// '.plist': ('text.plist.xml', 'PBXResourcesBuildPhase'), +// '.png': ('image.png', 'PBXResourcesBuildPhase'), +// '.rtf': ('text.rtf', 'PBXResourcesBuildPhase'), +// '.tiff': ('image.tiff', 'PBXResourcesBuildPhase'), +// '.txt': ('text', 'PBXResourcesBuildPhase'), +// '.xcodeproj': ('wrapper.pb-project', None), +// '.xib': ('file.xib', 'PBXResourcesBuildPhase'), +// '.strings': ('text.plist.strings', 'PBXResourcesBuildPhase'), +// '.bundle': ('wrapper.plug-in', 'PBXResourcesBuildPhase'), +// '.dylib': ('compiled.mach-o.dylib', 'PBXFrameworksBuildPhase') +// } + + public PBXFileReference() : base() + { + + } + +// class PBXFileReference(PBXType): +// def __init__(self, d=None): +// PBXType.__init__(self, d) +// self.build_phase = None +// +// types = { +// '.a':('archive.ar', 'PBXFrameworksBuildPhase'), +// '.app': ('wrapper.application', None), +// '.s': ('sourcecode.asm', 'PBXSourcesBuildPhase'), +// '.c': ('sourcecode.c.c', 'PBXSourcesBuildPhase'), +// '.cpp': ('sourcecode.cpp.cpp', 'PBXSourcesBuildPhase'), +// '.framework': ('wrapper.framework','PBXFrameworksBuildPhase'), +// '.h': ('sourcecode.c.h', None), +// '.icns': ('image.icns','PBXResourcesBuildPhase'), +// '.m': ('sourcecode.c.objc', 'PBXSourcesBuildPhase'), +// '.mm': ('sourcecode.cpp.objcpp', 'PBXSourcesBuildPhase'), +// '.nib': ('wrapper.nib', 'PBXResourcesBuildPhase'), +// '.plist': ('text.plist.xml', 'PBXResourcesBuildPhase'), +// '.png': ('image.png', 'PBXResourcesBuildPhase'), +// '.rtf': ('text.rtf', 'PBXResourcesBuildPhase'), +// '.tiff': ('image.tiff', 'PBXResourcesBuildPhase'), +// '.txt': ('text', 'PBXResourcesBuildPhase'), +// '.xcodeproj': ('wrapper.pb-project', None), +// '.xib': ('file.xib', 'PBXResourcesBuildPhase'), +// '.strings': ('text.plist.strings', 'PBXResourcesBuildPhase'), +// '.bundle': ('wrapper.plug-in', 'PBXResourcesBuildPhase'), +// '.dylib': ('compiled.mach-o.dylib', 'PBXFrameworksBuildPhase') +// } +// +// trees = [ +// '', +// '', +// 'BUILT_PRODUCTS_DIR', +// 'DEVELOPER_DIR', +// 'SDKROOT', +// 'SOURCE_ROOT', +// ] +// +// def guess_file_type(self): +// self.remove('explicitFileType') +// self.remove('lastKnownFileType') +// ext = os.path.splitext(self.get('name', ''))[1] +// +// f_type, build_phase = PBXFileReference.types.get(ext, ('?', None)) +// +// self['lastKnownFileType'] = f_type +// self.build_phase = build_phase +// +// if f_type == '?': +// print 'unknown file extension: %s' % ext +// print 'please add extension and Xcode type to PBXFileReference.types' +// +// return f_type +// +// def set_file_type(self, ft): +// self.remove('explicitFileType') +// self.remove('lastKnownFileType') +// +// self['explicitFileType'] = ft +// +// @classmethod +// def Create(cls, os_path, tree='SOURCE_ROOT'): +// if tree not in cls.trees: +// print 'Not a valid sourceTree type: %s' % tree +// return None +// +// fr = cls() +// fr.id = cls.GenerateId() +// fr['path'] = os_path +// fr['name'] = os.path.split(os_path)[1] +// fr['sourceTree'] = '' if os.path.isabs(os_path) else tree +// fr.guess_file_type() +// +// return fr + } +} diff --git a/PBXFileReference.cs.meta b/PBXFileReference.cs.meta new file mode 100644 index 0000000..2f0ef40 --- /dev/null +++ b/PBXFileReference.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2792ed7b2a30d40c199e8e27ebf39ccf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/PBXGroup.cs b/PBXGroup.cs new file mode 100644 index 0000000..c2493d5 --- /dev/null +++ b/PBXGroup.cs @@ -0,0 +1,137 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEditor.XCodeEditor +{ + public class PBXGroup : PBXType + { + protected const string NAME_KEY = "name"; + protected const string CHILDREN_KEY = "children"; + protected const string PATH_KEY = "path"; + protected const string SOURCETREE_KEY = "sourceTree"; + + public PBXGroup( string name, string path = null, string tree = "SOURCE_ROOT" ) : base() + { + this.id = GenerateId(); + this.Add( NAME_KEY, name ); + this.Add( CHILDREN_KEY, new PBXList() ); + + if( path != null ) { + this.Add( PATH_KEY, path ); + this.Add( SOURCETREE_KEY, tree ); + } + else { + this.Add( SOURCETREE_KEY, "" ); + } + } + + public string AddChild( PBXType child ) + { + if( !( child is PBXDictionary ) ) + return null; + return ""; + + string isa = (string)child[ ISA_KEY ]; + if( string.Compare( isa, "PBXFileReference" ) != 0 || string.Compare( isa, "PBXGroup" ) != 0 ) + return null; + + PBXList children; + if( !ContainsKey( CHILDREN_KEY ) ) { + children = new PBXList(); + this.Add( CHILDREN_KEY, children ); + } + +// ((PBXList)this["children"]).Add( child.id ); + children.Add( child.id ); + return child.id; + } + + public void RemoveChild( string id ) + { + if( !ContainsKey( CHILDREN_KEY ) ) { + this.Add( CHILDREN_KEY, new PBXList() ); + return; + } + + if( !IsGuid( id ) ) + return; + + ((PBXList)this[ CHILDREN_KEY ]).Remove( id ); + } + + public bool HasChild( string id ) + { + if( !ContainsKey( CHILDREN_KEY ) ) { + this.Add( CHILDREN_KEY, new PBXList() ); + return false; + } + + if( !IsGuid( id ) ) + return false; + + return ((PBXList)this[ CHILDREN_KEY ]).Contains( id ); + } + + public string GetName() + { + return (string)this[ NAME_KEY ]; + } + +// class PBXGroup(PBXType): +// def add_child(self, ref): +// if not isinstance(ref, PBXDict): +// return None +// +// isa = ref.get('isa') +// +// if isa != 'PBXFileReference' and isa != 'PBXGroup': +// return None +// +// if not self.has_key('children'): +// self['children'] = PBXList() +// +// self['children'].add(ref.id) +// +// return ref.id +// +// def remove_child(self, id): +// if not self.has_key('children'): +// self['children'] = PBXList() +// return +// +// if not PBXType.IsGuid(id): +// id = id.id +// +// self['children'].remove(id) +// +// def has_child(self, id): +// if not self.has_key('children'): +// self['children'] = PBXList() +// return False +// +// if not PBXType.IsGuid(id): +// id = id.id +// +// return id in self['children'] +// +// def get_name(self): +// path_name = os.path.split(self.get('path',''))[1] +// return self.get('name', path_name) +// +// @classmethod +// def Create(cls, name, path=None, tree='SOURCE_ROOT'): +// grp = cls() +// grp.id = cls.GenerateId() +// grp['name'] = name +// grp['children'] = PBXList() +// +// if path: +// grp['path'] = path +// grp['sourceTree'] = tree +// else: +// grp['sourceTree'] = '' +// +// return grp + } +} diff --git a/PBXGroup.cs.meta b/PBXGroup.cs.meta new file mode 100644 index 0000000..2a3114a --- /dev/null +++ b/PBXGroup.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1af26133e9aa04b77bd12d21d94f118e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/PBXList.cs b/PBXList.cs new file mode 100644 index 0000000..ed71165 --- /dev/null +++ b/PBXList.cs @@ -0,0 +1,19 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEditor.XCodeEditor +{ + public class PBXList : ArrayList + { + + } + +// public class PBXList : ArrayList +// { +// public int Add( T value ) +// { +// return (ArrayList)this.Add( value ); +// } +// } +} diff --git a/PBXList.cs.meta b/PBXList.cs.meta new file mode 100644 index 0000000..7e9a949 --- /dev/null +++ b/PBXList.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5dab64c67c818480d9451129a0e67e80 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/PBXParser.cs b/PBXParser.cs index 45b5ccd..621b4c0 100644 --- a/PBXParser.cs +++ b/PBXParser.cs @@ -29,15 +29,15 @@ public class PBXParser public const string COMMENT_BEGIN_TOKEN = "/*"; public const string COMMENT_END_TOKEN = "*/"; public const string COMMENT_LINE_TOKEN = "//"; - private const int BUILDER_CAPACITY = 10000; + private const int BUILDER_CAPACITY = 20000; // private char[] data; private int index; // public bool success; - private int indent; +// private int indent; - public object Decode( string data ) + public PBXDictionary Decode( string data ) { // success = true; if( !data.StartsWith( PBX_HEADER_TOKEN ) ) { @@ -47,12 +47,14 @@ public object Decode( string data ) data = data.Substring( 13 ); this.data = data.ToCharArray(); - return Parse(); + index = 0; + + return (PBXDictionary)ParseValue(); } - public string Encode( Dictionary pbxData, bool readable = false ) + public string Encode( PBXDictionary pbxData, bool readable = false ) { - indent = 0; +// indent = 0; StringBuilder builder = new StringBuilder( PBX_HEADER_TOKEN, BUILDER_CAPACITY ); bool success = SerializeValue( pbxData, builder, readable ); @@ -66,11 +68,6 @@ private char NextToken() { SkipWhitespaces(); return StepForeward(); - -// def next_token(self): -// self.eat_whitespace() -// -// return self.fh.read(1) } private string Peek( int step = 1 ) @@ -80,11 +77,6 @@ private string Peek( int step = 1 ) sneak += data[ index + i ]; } return sneak; - -// def peek(self, chars=1): -// c = self.fh.read(chars) -// self.backup(chars) -// return c } private bool SkipWhitespaces() @@ -101,21 +93,6 @@ private bool SkipWhitespaces() } return whitespace; - -// def eat_whitespace(self): -// whitespace = False -// regexp = re.compile('[\s]') -// -// while re.match(regexp, self.fh.read(1)): -// whitespace = True -// -// self.backup() -// -// if self.eat_comments(): -// whitespace = True -// self.eat_whitespace() -// -// return whitespace } private bool SkipComments() @@ -128,7 +105,6 @@ private bool SkipComments() s += StepForeward(); } s += StepForeward( 2 ); -// Debug.Log( "Skipped comment: \"" + s + "\"" ); break; } case COMMENT_LINE_TOKEN: { @@ -141,59 +117,23 @@ private bool SkipComments() return false; } return true; - -// def eat_comments(self): -// comment = self.peek(2) -// -// if comment == '/*': -// while self.peek(2) != '*/': -// self.fh.read(1) -// self.fh.read(2) -// elif comment == '//': -// while not re.match('\n', self.fh.read(1)): -// pass -// else: -// return False -// -// return True } private char StepForeward( int step = 1 ) { -// index = Math.Min( data.lenght, index + step ); - index += step; + index = Math.Min( data.Length + 1, index + step ); return data[ index ]; - -// def backup(self, chars=1): -// self.fh.seek(-chars, 1) } private char StepBackward( int step = 1 ) { index = Math.Max( 0, index - step ); return data[ index ]; - -// def backup(self, chars=1): -// self.fh.seek(-chars, 1) } #endregion #region Parse - public object Parse() - { - index = 0; - try { - return ParseValue(); - } - catch( System.Exception ex ) { -// Debug.Log( "[Index " + data[ index ] + "] " + ex.Message ); - Debug.LogWarning( ex.Message ); - return null; -// throw new System.Exception( "Reached end of input unexpectedly at index " + index ); - } - } - private object ParseValue() { switch( NextToken() ) { @@ -210,31 +150,12 @@ private object ParseValue() StepBackward(); return ParseEntity(); } - -// def parse_value(self): -// # move through file until a token is hit -// -// token = self.next_token() -// -// if token is None: -// print 'end of file' -// return None -// if token == '{': -// return self.parse_dictionary() -// elif token == '(': -// return self.parse_list() -// elif token == '"': -// return self.parse_string() -// else: -// self.backup() -// return self.parse_entity() } - private object ParseDictionary() + private PBXDictionary ParseDictionary() { SkipWhitespaces(); -// Hashtable dictionary = new Hashtable(); - Dictionary dictionary = new Dictionary(); + PBXDictionary dictionary = new PBXDictionary(); string keyString = string.Empty; object valueObject = null; @@ -277,35 +198,6 @@ private object ParseDictionary() } } return dictionary; - -// def parse_dictionary(self): -// self.eat_whitespace() -// d = {} -// -// while True: -// token = self.next_token() -// -// if token is None: -// print 'error: reached end of file inside a dictionary: %s' % str(d) -// return d -// elif token == ';': -// pass -// elif token == '}': -// return d -// else: -// self.backup() -// key = self.parse_value() -// -// if not key: -// return d -// -// token = self.next_token() -// -// if token != '=': -// print 'error: could not find value of key %s of dictionary %s' % (key, d) -// return None -// -// d[key] = self.parse_value() } private ArrayList ParseArray() @@ -330,23 +222,6 @@ private ArrayList ParseArray() } } return list; - -// def parse_list(self): -// l = [] -// -// while True: -// token = self.next_token() -// -// if token is None: -// print 'error: reached end of file inside a list: %s' % l -// return l -// elif token == ',': -// pass -// elif token == ')': -// return l -// else: -// self.backup() -// l.append(self.parse_value()) } private object ParseString() @@ -363,20 +238,6 @@ private object ParseString() } return s; - -// def parse_string(self): -// chars = [] -// -// c = self.fh.read(1) -// while c != '"': -// chars.append(c) -// -// if c == '\\': -// chars.append(self.fh.read(1)) -// -// c = self.fh.read(1) -// -// return ''.join(chars) } private object ParseEntity() @@ -393,21 +254,6 @@ private object ParseEntity() return Int32.Parse( word ); return word; - -// def parse_entity(self): -// chars = [] -// regexp = re.compile('[;,\s=]') -// -// c = self.fh.read(1) -// while not re.match(regexp, c): -// chars.append(c) -// c = self.fh.read(1) -// -// word = ''.join(chars) -// if len(word) != 24 and re.match('^[0-9]+$', word): -// return int(word) -// -// return word } #endregion @@ -433,8 +279,10 @@ private bool SerializeValue( object value, StringBuilder builder, bool readable else if( value is Char ) { SerializeString( Convert.ToString( (char)value ), builder, readable ); } + else if( value is bool ) { + builder.Append( Convert.ToInt32( value ).ToString() ); + } else if( value.GetType().IsPrimitive ) { -// SerializeNumber( Convert.ToDouble( value ), builder ); builder.Append( Convert.ToString( value ) ); } // else if( value is Hashtable ) @@ -458,19 +306,13 @@ private bool SerializeValue( object value, StringBuilder builder, bool readable private bool SerializeDictionary( Dictionary dictionary, StringBuilder builder, bool readable = false ) { - builder.Append( DICTIONARY_BEGIN_TOKEN ); -// bool first = true; foreach( KeyValuePair pair in dictionary ) { -// if( !first ) -// builder.Append( DICTIONARY_ITEM_DELIMITER_TOKEN ); - SerializeString( pair.Key, builder ); builder.Append( DICTIONARY_ASSIGN_TOKEN ); SerializeValue( pair.Value, builder ); builder.Append( DICTIONARY_ITEM_DELIMITER_TOKEN ); -// first = false; } builder.Append( DICTIONARY_END_TOKEN ); @@ -480,24 +322,17 @@ private bool SerializeDictionary( Dictionary dictionary, StringB private bool SerializeArray( ArrayList anArray, StringBuilder builder, bool readable = false ) { builder.Append( ARRAY_BEGIN_TOKEN ); - -// bool first = true; + for( int i = 0; i < anArray.Count; i++ ) { object value = anArray[i]; -// if( !first ) -// { -// builder.Append( ARRAY_ITEM_DELIMITER_TOKEN ); -// } - if( !SerializeValue( value, builder ) ) { return false; } builder.Append( ARRAY_ITEM_DELIMITER_TOKEN ); -// first = false; } builder.Append( ARRAY_END_TOKEN ); @@ -528,64 +363,12 @@ private bool SerializeString( string aString, StringBuilder builder, bool useQuo builder.Append( aString ); -// char[] charArray = aString.ToCharArray(); -// for( int i = 0; i < charArray.Length; i++ ) -// { -// char c = charArray[i]; -// if( c == '"' ) -// { -// builder.Append( "\"" ); -// } -// else if( c == '\\' ) -// { -// builder.Append( "\\\\" ); -// } -// else if( c == '\b' ) -// { -// builder.Append( "\\b" ); -// } -// else if( c == '\f' ) -// { -// builder.Append( "\\f" ); -// } -// else if( c == '\n' ) -// { -// builder.Append( "\\n" ); -// } -// else if( c == '\r' ) -// { -// builder.Append( "\\r" ); -// } -// else if( c == '\t' ) -// { -// builder.Append( "\\t" ); -// } -// else -// { -// int codepoint = Convert.ToInt32( c ); -// if( ( codepoint >= 32 ) && ( codepoint <= 126 ) ) -// { -// builder.Append( c ); -// } -// else -// { -// builder.Append( "\\u" + Convert.ToString( codepoint, 16 ).PadLeft( 4, '0' ) ); -// } -// } -// } - if( useQuotes ) builder.Append( QUOTEDSTRING_END_TOKEN ); return true; } -// private bool SerializeNumber( int number, StringBuilder builder ) -// { -// builder.Append( Convert.ToString( number ) ); // , CultureInfo.InvariantCulture)); -// return true; -// } - #endregion } } \ No newline at end of file diff --git a/PBXType.cs b/PBXType.cs new file mode 100644 index 0000000..c080e83 --- /dev/null +++ b/PBXType.cs @@ -0,0 +1,89 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEditor.XCodeEditor +{ + public class PBXType : PBXDictionary + { + protected const string ISA_KEY = "isa"; + public string id; + + public PBXType() + { + if( !this.ContainsKey( ISA_KEY ) ) + this[ ISA_KEY ] = this.GetType().Name; + + this.id = null; + Debug.Log( "chiamato" ); + } + + public static bool IsGuid( string aString ) + { + return System.Text.RegularExpressions.Regex.IsMatch( aString, @"^[A-F0-9]{24}$" ); + } + + public static string GenerateId() + { + return System.Guid.NewGuid().ToString("N").Substring( 8 ).ToUpper(); + } + +// class PBXType(PBXDict): +// def __init__(self, d=None): +// PBXDict.__init__(self, d) +// +// if not self.has_key('isa'): +// self['isa'] = self.__class__.__name__ +// self.id = None +// +// @staticmethod +// def Convert(o): +// if isinstance(o, list): +// return PBXList(o) +// elif isinstance(o, dict): +// isa = o.get('isa') +// +// if not isa: +// return PBXDict(o) +// +// cls = globals().get(isa) +// +// if cls and issubclass(cls, PBXType): +// return cls(o) +// +// print 'warning: unknown PBX type: %s' % isa +// return PBXDict(o) +// else: +// return o + } + + public class PBXNativeTarget : PBXType + { + public PBXNativeTarget() : base() { + } + } + + public class PBXProject : PBXType + { + public PBXProject() : base() { + } + } + + public class PBXContainerItemProxy : PBXType + { + public PBXContainerItemProxy() : base() { + } + } + + public class PBXReferenceProxy : PBXType + { + public PBXReferenceProxy() : base() { + } + } + + public class PBXVariantGroup : PBXType + { + public PBXVariantGroup() : base() { + } + } +} diff --git a/PBXType.cs.meta b/PBXType.cs.meta new file mode 100644 index 0000000..9a36d90 --- /dev/null +++ b/PBXType.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 32f133b9e55274ea89cb600dce102228 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/XCBuildConfigurationList.cs b/XCBuildConfigurationList.cs index f440d5b..f2f4d78 100644 --- a/XCBuildConfigurationList.cs +++ b/XCBuildConfigurationList.cs @@ -3,13 +3,145 @@ namespace UnityEditor.XCodeEditor { - public class XCBuildConfigurationList : System.IDisposable + public class XCBuildConfigurationList : PBXType { - - public void Dispose() + protected const string BUILDSETTINGS_KEY = "buildSettings"; + protected const string HEADER_SEARCH_PATH_KEY = "HEADER_SEARCH_PATH"; + protected const string LIBRARY_SEARCH_PATH_KEY = "LIBRARY_SEARCH_PATH"; + protected const string OTHER_C_FLAGS_KEY = "OTHER_CFLAGS"; + + public bool AddSearchPaths( string path, string basePath, string key, bool recursive = true ) + { + PBXList paths = new PBXList(); + paths.Add( path ); + return AddSearchPaths( paths, basePath, key, recursive ); + } + + public bool AddSearchPaths( PBXList paths, string basePath, string key, bool recursive = true ) + { + bool modified = false; + + if( !ContainsKey( basePath ) ) + this.Add( basePath, new PBXDictionary() ); + + foreach( string path in paths ) { + string currentPath = path; + if( recursive && !path.EndsWith( "/**" ) ) + currentPath += "**"; + + if( !((PBXDictionary)this[basePath]).ContainsKey( key ) ) { + ((PBXDictionary)this[basePath]).Add( key, new PBXList() ); + } + else if( ((PBXDictionary)this[basePath])[key] is string ) { + PBXList list = new PBXList(); + list.Add( ((PBXDictionary)this[basePath])[key] ); + ((PBXDictionary)this[basePath])[key] = list; + } + + if( ((PBXList)((PBXDictionary)this[basePath])[key]).Add( "\"" + currentPath + "\"" ) >= 0 ) { + modified = true; + } + } + + return modified; + } + + public bool AddHeaderSearchPaths( PBXList paths, bool recursive = true ) { + return this.AddSearchPaths( paths, "buildSettings", "HEADER_SEARCH_PATHS", recursive ); + } + + public bool AddLibrarySearchPath( PBXList paths, bool recursive = true ) + { + return this.AddSearchPaths( paths, "buildSettings", "LIBRARY_SEARCH_PATHS", recursive ); + } + + public bool AddOtherCFlags( string flag ) + { + PBXList flags = new PBXList(); + flags.Add( flag ); + return AddOtherCFlags( flags ); + } + + public bool AddOtherCFlags( PBXList flags ) + { + bool modified = false; + + if( !ContainsKey( BUILDSETTINGS_KEY ) ) + this.Add( BUILDSETTINGS_KEY, new PBXDictionary() ); + + foreach( string flag in flags ) { + + if( !((PBXDictionary)this[BUILDSETTINGS_KEY]).ContainsKey( OTHER_C_FLAGS_KEY ) ) { + ((PBXDictionary)this[BUILDSETTINGS_KEY]).Add( OTHER_C_FLAGS_KEY, new PBXList() ); + } + else if ( ((PBXDictionary)this[BUILDSETTINGS_KEY])[ OTHER_C_FLAGS_KEY ] is string ) { + string tempString = (string)((PBXDictionary)this[BUILDSETTINGS_KEY])[OTHER_C_FLAGS_KEY]; + ((PBXDictionary)this[BUILDSETTINGS_KEY])[ OTHER_C_FLAGS_KEY ] = new PBXList(); + ((PBXList)((PBXDictionary)this[BUILDSETTINGS_KEY])[OTHER_C_FLAGS_KEY]).Add( tempString ); + } + + if( ((PBXList)((PBXDictionary)this[BUILDSETTINGS_KEY])[OTHER_C_FLAGS_KEY]).Add( flag ) >= 0 ) { + modified = true; + } + } + return modified; } +// class XCBuildConfiguration(PBXType): +// def add_search_paths(self, paths, base, key, recursive=True): +// modified = False +// +// if not isinstance(paths, list): +// paths = [paths] +// +// if not self.has_key(base): +// self[base] = PBXDict() +// +// for path in paths: +// if recursive and not path.endswith('/**'): +// path = os.path.join(path, '**') +// +// if not self[base].has_key(key): +// self[base][key] = PBXList() +// elif isinstance(self[base][key], basestring): +// self[base][key] = PBXList(self[base][key]) +// +// if self[base][key].add('\\"%s\\"' % path): +// modified = True +// +// return modified +// +// def add_header_search_paths(self, paths, recursive=True): +// return self.add_search_paths(paths, 'buildSettings', 'HEADER_SEARCH_PATHS', recursive=recursive) +// +// def add_library_search_paths(self, paths, recursive=True): +// return self.add_search_paths(paths, 'buildSettings', 'LIBRARY_SEARCH_PATHS', recursive=recursive) +// +// def add_other_cflags(self, flags): +// modified = False +// +// base = 'buildSettings' +// key = 'OTHER_CFLAGS' +// +// if isinstance(flags, basestring): +// flags = PBXList(flags) +// +// if not self.has_key(base): +// self[base] = PBXDict() +// +// for flag in flags: +// +// if not self[base].has_key(key): +// self[base][key] = PBXList() +// elif isinstance(self[base][key], basestring): +// self[base][key] = PBXList(self[base][key]) +// +// if self[base][key].add(flag): +// self[base][key] = [e for e in self[base][key] if e] +// modified = True +// +// return modified } } \ No newline at end of file diff --git a/XCConfigurationList.cs b/XCConfigurationList.cs new file mode 100644 index 0000000..2e6b7df --- /dev/null +++ b/XCConfigurationList.cs @@ -0,0 +1,13 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEditor.XCodeEditor +{ + public class XCConfigurationList : PBXType + { +// XCBuildConfigurationList buildConfigurations; +// bool defaultConfigurationIsVisible = false; +// string defaultConfigurationName; + } +} diff --git a/XCConfigurationList.cs.meta b/XCConfigurationList.cs.meta new file mode 100644 index 0000000..e9ffa56 --- /dev/null +++ b/XCConfigurationList.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 186b7292bd62b4867bff9c84f77ba73e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/XCGroup.cs b/XCGroup.cs deleted file mode 100644 index 7bdf444..0000000 --- a/XCGroup.cs +++ /dev/null @@ -1,15 +0,0 @@ -using UnityEngine; -using System.Collections; - -namespace UnityEditor.XCodeEditor -{ - public class XCGroup : System.IDisposable - { - - public void Dispose() - { - - } - - } -} \ No newline at end of file diff --git a/XCProject.cs b/XCProject.cs index c6635b0..14df9f3 100644 --- a/XCProject.cs +++ b/XCProject.cs @@ -10,13 +10,18 @@ public class XCProject : System.IDisposable private XCFileOperationQueue _fileOperrationQueue; // private string _filePath; - private Dictionary _datastore; - private Dictionary _groups; - private Dictionary _configurations; + private PBXDictionary _datastore; + private PBXDictionary _objects; + private PBXDictionary _groups; + private PBXDictionary _configurations; + private PBXDictionary _rootObject; + private PBXDictionary _rootGroup; private string _defaultConfigurationName; private string _rootObjectKey; public string filePath { get; private set; } + private string sourcePathRoot; + private bool modified = false; #region Constructor @@ -47,32 +52,29 @@ public XCProject( string filePath ) : this() string projPath = System.IO.Path.Combine( this.filePath, "project.pbxproj" ); string contents = System.IO.File.OpenText( projPath ).ReadToEnd(); -// Debug.Log( System.IO.File.OpenText( projPath ).ReadToEnd ); PBXParser parser = new PBXParser(); - _datastore = (Dictionary)parser.Decode( contents ); + _datastore = parser.Decode( contents ); if( _datastore == null ) { throw new System.Exception( "Project file not found at file path " + filePath ); } _fileOperrationQueue = new XCFileOperationQueue(); - _groups = new Dictionary(); +// _groups = new Dictionary(); + _objects = (PBXDictionary)_datastore["objects"]; + modified = false; -// if ((self = [super init])) { -// _filePath = [filePath copy]; -// _dataStore = [[NSMutableDictionary alloc] -// initWithContentsOfFile:[_filePath stringByAppendingPathComponent:@"project.pbxproj"]]; -// -// if (!_dataStore) { -// [NSException raise:NSInvalidArgumentException format:@"Project file not found at file path %@", _filePath]; -// } -// -// _fileOperationQueue = -// [[XCFileOperationQueue alloc] initWithBaseDirectory:[_filePath stringByDeletingLastPathComponent]]; -// -// _groups = [[NSMutableDictionary alloc] init]; -// } -// return self; + _rootObjectKey = (string)_datastore["rootObject"]; + if( !string.IsNullOrEmpty( _rootObjectKey ) ) { + _rootObject = (PBXDictionary)_objects[ _rootObjectKey ]; + _rootGroup = (PBXDictionary)_objects[ (string)_rootObject[ "mainGroup" ] ]; + } + else { + Debug.LogWarning( "error: project has no root object" ); + _rootObject = null; + _rootGroup = null; + } + } #endregion @@ -163,9 +165,9 @@ public ArrayList getImagePNGFiles() #endregion #region Groups /** - * Lists the groups in an xcode project, returning an array of `XCGroup` objects. + * Lists the groups in an xcode project, returning an array of `PBXGroup` objects. */ - public ArrayList groups { + public PBXList groups { get { return null; } @@ -174,7 +176,7 @@ public ArrayList getImagePNGFiles() /** * Returns the root (top-level) group. */ - public XCGroup rootGroup { + public PBXGroup rootGroup { get { return null; } @@ -192,7 +194,7 @@ public ArrayList getImagePNGFiles() /** * Returns the group with the given key, or nil. */ - public XCGroup GetGroupWithKey( string key ) + public PBXGroup GetGroupWithKey( string key ) { return null; } @@ -200,7 +202,7 @@ public XCGroup GetGroupWithKey( string key ) /** * Returns the group with the specified display name path - the directory relative to the root group. Eg Source/Main */ - public XCGroup GetGroupWithPathFromRoot( string path ) + public PBXGroup GetGroupWithPathFromRoot( string path ) { return null; } @@ -208,7 +210,7 @@ public XCGroup GetGroupWithPathFromRoot( string path ) /** * Returns the parent group for the group or file with the given key; */ - public XCGroup GetGroupForGroupMemberWithKey( string key ) + public PBXGroup GetGroupForGroupMemberWithKey( string key ) { return null; } @@ -216,7 +218,7 @@ public XCGroup GetGroupForGroupMemberWithKey( string key ) /** * Returns the parent group for the group or file with the source file */ - public XCGroup GetGroupWithSourceFile( XCSourceFile sourceFile ) + public PBXGroup GetGroupWithSourceFile( XCSourceFile sourceFile ) { return null; } diff --git a/XCodeEditorMenu.cs b/XCodeEditorMenu.cs index e434796..88aeb67 100644 --- a/XCodeEditorMenu.cs +++ b/XCodeEditorMenu.cs @@ -12,10 +12,27 @@ public class XCodeEditorMenu [MenuItem ("Build Tools/XCode Editor/DebugTest %t")] static void DebugTest() { - string projectPath = Path.Combine( Directory.GetParent( Application.dataPath ).ToString(), "XCode" ); - Debug.Log( "XcodePath: " + projectPath ); +// string projectPath = Path.Combine( Directory.GetParent( Application.dataPath ).ToString(), "XCode" ); +// Debug.Log( "XcodePath: " + projectPath ); +// +// XCProject currentProject = new XCProject( projectPath ); + //Debug.Log( +// PBXDictionary test = new PBXDictionary(); +// bool result = false; +// if( test is Dictionary ) +// result = true; +// +// Debug.Log( result ); + +// PBXType type = new PBXType(); +// Debug.Log( "TYPE: " + type["isa"] ); +// +// PBXBuildFile build = new PBXBuildFile( "" ); +// Debug.Log( "BUILDFILE: " + build["isa"] ); + + Debug.Log( PBXType.GenerateId().ToUpper() ); + XCBuildConfigurationList test = new XCBuildConfigurationList(); - XCProject currentProject = new XCProject( projectPath ); } @@ -34,7 +51,7 @@ static void DebugTest2() PBXParser parser = new PBXParser(); // Hashtable test = (Hashtable)parser.Decode( contents ); - Dictionary test = (Dictionary)parser.Decode( contents ); + PBXDictionary test = parser.Decode( contents ); Debug.Log( MiniJSON.jsonEncode( test ) ); Debug.Log( test + " - " + test.Count ); Debug.Log( parser.Encode( test ) );