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
47 int quote = pos;
48
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
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
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
113 int quote = pos;
114
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
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
262
263
264
265
266
267
268
269
270
271
272
273
274
275 }