View Javadoc

1   
2   package net.wotonomy.foundation;
3   
4   public class NSPropertyListSerialization {
5   
6       public static final int PLIST_ARRAY = 0;
7       public static final int PLIST_DICTIONARY = 1;
8       public static final int PLIST_DATA = 2;
9       public static final int PLIST_STRING = 3;
10  
11      public static final char[] TOKEN_BEGIN = new char[]{
12          '(', '{', '<', '"'
13      };
14      public static final char[] TOKEN_END = new char[]{
15          ')', '}', '>', '"'
16      };
17      public static final char[] QUOTING_CHARS = new char[]{
18      	':', '/', '-', '.', '//'
19      };
20  
21      private NSPropertyListSerialization() {
22          super();
23      }
24  
25      /*** Creates a NSArray object from a string representation.
26          @s The string representation of a NSArray object. */
27      public static NSArray arrayForString(String s) {
28          s = s.trim();
29          if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_ARRAY] && s.charAt(s.length()-1) == TOKEN_END[PLIST_ARRAY]))
30              return null;
31          NSMutableArray arr = new NSMutableArray();
32          int pos = 1;
33          int valbegin = -1;
34          while (pos < s.length()) {
35              char c = s.charAt(pos);
36              int tokenCount = 0;
37              int what = 0;
38              for (int i = 0 ; i < TOKEN_BEGIN.length; i++) {
39                  if (c == TOKEN_BEGIN[i]) {
40                      tokenCount = 1;
41                      what = i;
42                      break;
43                  }
44              }
45              if (tokenCount > 0) {
46                  //mark it
47                  int quote = pos;
48                  //find the closing token
49                  do {
50                      pos++;
51  					try {
52  						c = s.charAt(pos);
53  					} catch (StringIndexOutOfBoundsException ex) {
54  						throw new IllegalArgumentException("Could not parse property list; unclosed token '" + TOKEN_BEGIN[what] + "'");
55  					}
56  					if (c == '"' && what == PLIST_STRING) {
57  						if (pos > 0 && s.charAt(pos-1) != '//') {
58  							tokenCount--;
59  						}
60  					} else if (c == TOKEN_BEGIN[what])
61                          tokenCount++;
62                      else if (c == TOKEN_END[what])
63                          tokenCount--;
64                  } while (tokenCount > 0);
65                  arr.addObject(propertyListFromString(s.substring(quote, pos+1)));
66                  valbegin = -1;
67                  //advance to the next position
68                  do {
69                      pos++;
70                      c = s.charAt(pos);
71                  } while (Character.isWhitespace(c));
72              }
73              if (c == ',' || c ==')') {
74                  if (valbegin > 0) {
75                      arr.addObject(s.substring(valbegin, pos).trim());
76                      valbegin = -1;
77                  }
78              } else if (!Character.isWhitespace(c)) {
79                  if (valbegin < 0) {
80                      valbegin = pos;
81                  }
82              }
83              pos++;
84          }
85          return arr;
86      }
87  
88      /*** Creates a NSDictionary instance from a string representation.
89          @s The string representation of a NSDictionary. */
90      public static NSDictionary dictionaryForString(String s) {
91          s = s.trim();
92          if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_DICTIONARY] && s.charAt(s.length()-1) == TOKEN_END[PLIST_DICTIONARY]))
93              return null;
94          NSMutableDictionary d = new NSMutableDictionary();
95          int pos = 1;
96          boolean parsing = true;
97          Object key = null;
98          int valbegin = -1;
99          while (pos < s.length()) {
100             //look for an opening token
101             char c = s.charAt(pos);
102             int tokenCount = 0;
103             int what = 0;
104             for (int i = 0 ; i < TOKEN_BEGIN.length; i++) {
105                 if (c == TOKEN_BEGIN[i]) {
106                     tokenCount = 1;
107                     what = i;
108                     break;
109                 }
110             }
111             if (tokenCount > 0) {
112                 //mark it
113                 int quote = pos;
114                 //find the closing token
115                 do {
116                     pos++;
117                     try {
118 						c = s.charAt(pos);
119                     } catch (StringIndexOutOfBoundsException ex) {
120                     	throw new IllegalArgumentException("Could not parse property list; unclosed token '" + TOKEN_BEGIN[what] + "'");
121                     }
122                     if (c == '"' && what == PLIST_STRING) {
123                     	if (pos > 0 && s.charAt(pos-1) != '//') {
124                     		tokenCount--;
125                     	}
126                     } else if (c == TOKEN_BEGIN[what])
127                         tokenCount++;
128                     else if (c == TOKEN_END[what])
129                         tokenCount--;
130                 } while (tokenCount > 0);
131                 if (key == null) {
132                     key = propertyListFromString(s.substring(quote, pos+1));
133                 } else {
134                     d.setObjectForKey(propertyListFromString(s.substring(quote, pos+1)), key);
135                     key = null;
136                 }
137                 valbegin = -1;
138                 //advance to the next position
139                 do {
140                     pos++;
141                     c = s.charAt(pos);
142                 } while (Character.isWhitespace(c));
143             }
144             if (c == ';' || c == '=' || c == '}') {
145                 if (valbegin > 0) {
146                     if (key == null) {
147                         key = s.substring(valbegin, pos).trim();
148                     } else {
149                         d.setObjectForKey(s.substring(valbegin, pos).trim(), key);
150                         key = null;
151                     }
152                     valbegin = -1;
153                 }
154             } else if (!Character.isWhitespace(c)) {
155                 if (valbegin < 0) {
156                     valbegin = pos;
157                 }
158             }
159             pos++;
160         }
161         return d;
162     }
163 
164     public static boolean booleanForString(String s) {
165         return s.trim().toLowerCase().equals("true");
166     }
167 
168     /*** Creates a NSData instance from a string representation.
169         @s The string representation of a NSData object. */
170     public static NSData dataFromPropertyList(String s) {
171         String hex = "0123456789ABCDEF";
172         s = s.trim();
173         if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_DATA] && s.charAt(s.length()-1) == TOKEN_END[PLIST_DATA]))
174             return null;
175         int pos = 1;
176         java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
177         while (pos < s.length()-1) {
178             char c1 = s.charAt(pos);
179             while (c1 == ' ') {
180                 pos++;
181                 if (pos == s.length()-1)
182                     return new NSData(bout.toByteArray());
183                 c1 = s.charAt(pos);
184             }
185             if (hex.indexOf(c1) < 0)
186                 throw new IllegalArgumentException("The string does not represent a NSData object (" + s + ", pos " + pos + ")");
187             pos++;
188             char c2 = s.charAt(pos);
189             if (hex.indexOf(c2) < 0)
190                 throw new IllegalArgumentException("The string does not represent a NSData object (" + s + ")");
191             int x = (hex.indexOf(c1) << 4) | hex.indexOf(c2);
192             bout.write(x);
193             pos++;
194         }
195         return new NSData(bout.toByteArray());
196     }
197 
198     public static int intForString(String s) {
199         return Integer.parseInt(s);
200     }
201 
202     /*** Returns the string representation of a property list.
203         @plist The property list. It can be a String, NSData, NSArray, NSDictionary. */
204     public static String stringForPropertyList(Object plist) {
205         if (plist == null)
206             return "";
207         if (plist instanceof NSArray || plist instanceof NSDictionary || plist instanceof NSData)
208             return plist.toString();
209         String x = plist.toString();
210         boolean quote = false;
211         for (int i = 0; i < x.length(); i++) {
212         	char c = x.charAt(i);
213         	for (int z = 0; z < TOKEN_BEGIN.length; z++) {
214         		if (c == TOKEN_BEGIN[z] || c == TOKEN_END[z])
215         			quote = true;
216         	}
217         	if (!quote) {
218         		for (int z = 0; z < QUOTING_CHARS.length; z++) {
219         			if (c == QUOTING_CHARS[z])
220         				quote = true;
221         		}
222         	}
223             if (!quote && Character.isWhitespace(c)) {
224                 quote = true;
225                 i = x.length();
226             }
227         }
228         if (quote)
229             return "\"" + x + "\"";
230         return x;
231     }
232 
233     /*** Returns an property list created from a string representation.
234         @s The string with a representation of a property list.
235         @returns A property list object; either a NSData, NSArray, NSDictionary, or a String. */
236     public static Object propertyListFromString(String s) {
237         s = s.trim();
238         int type = -1;
239         for (int i = 0; i < TOKEN_BEGIN.length; i++) {
240             if (TOKEN_BEGIN[i] == s.charAt(0)) {
241                 if (TOKEN_END[i] == s.charAt(s.length()-1))
242                     type = i;
243             }
244         }
245         switch (type) {
246             case PLIST_DATA:
247                 return dataFromPropertyList(s);
248             case PLIST_ARRAY:
249                 return arrayForString(s);
250             case PLIST_DICTIONARY:
251                 return dictionaryForString(s);
252             case PLIST_STRING:
253             	if (s.equals("\"\""))
254             		return "";
255                 return s.substring(1, s.length()-1);
256         }
257         return s;
258     }
259 
260     /*
261      * $Log$
262      * Revision 1.2  2006/02/16 13:15:00  cgruber
263      * Check in all sources in eclipse-friendly maven-enabled packages.
264      *
265      * Revision 1.5  2003/08/11 18:18:08  chochos
266      * improved encoding of strings, removed warnings
267      *
268      * Revision 1.4  2003/08/11 17:33:45  chochos
269      * Implemented detection of escaped quotes (\"). improved quoting strings when converting property lists to strings.
270      *
271      * Revision 1.3  2003/08/04 23:50:55  chochos
272      * propertyListForString() now works. dictionaryForString and arrayForString can parse complex structures with nested arrays and dictionaries.
273      *
274      */
275 }