diff options
Diffstat (limited to 'libs/TouchJSON/JSON/CJSONSerializer.m')
-rwxr-xr-x | libs/TouchJSON/JSON/CJSONSerializer.m | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/libs/TouchJSON/JSON/CJSONSerializer.m b/libs/TouchJSON/JSON/CJSONSerializer.m new file mode 100755 index 0000000..952b3c2 --- /dev/null +++ b/libs/TouchJSON/JSON/CJSONSerializer.m | |||
@@ -0,0 +1,342 @@ | |||
1 | // | ||
2 | // CJSONSerializer.m | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 12/07/2005. | ||
6 | // Copyright 2005 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import "CJSONSerializer.h" | ||
31 | |||
32 | #import "JSONRepresentation.h" | ||
33 | |||
34 | static NSData *kNULL = NULL; | ||
35 | static NSData *kFalse = NULL; | ||
36 | static NSData *kTrue = NULL; | ||
37 | |||
38 | @implementation CJSONSerializer | ||
39 | |||
40 | + (void)initialize | ||
41 | { | ||
42 | NSAutoreleasePool *thePool = [[NSAutoreleasePool alloc] init]; | ||
43 | |||
44 | if (self == [CJSONSerializer class]) | ||
45 | { | ||
46 | if (kNULL == NULL) | ||
47 | kNULL = [[NSData alloc] initWithBytesNoCopy:(void *)"null" length:4 freeWhenDone:NO]; | ||
48 | if (kFalse == NULL) | ||
49 | kFalse = [[NSData alloc] initWithBytesNoCopy:(void *)"false" length:5 freeWhenDone:NO]; | ||
50 | if (kTrue == NULL) | ||
51 | kTrue = [[NSData alloc] initWithBytesNoCopy:(void *)"true" length:4 freeWhenDone:NO]; | ||
52 | |||
53 | [thePool release]; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | + (id)serializer | ||
58 | { | ||
59 | return([[[self alloc] init] autorelease]); | ||
60 | } | ||
61 | |||
62 | - (BOOL)isValidJSONObject:(id)inObject | ||
63 | { | ||
64 | if ([inObject isKindOfClass:[NSNull class]]) | ||
65 | { | ||
66 | return(YES); | ||
67 | } | ||
68 | else if ([inObject isKindOfClass:[NSNumber class]]) | ||
69 | { | ||
70 | return(YES); | ||
71 | } | ||
72 | else if ([inObject isKindOfClass:[NSString class]]) | ||
73 | { | ||
74 | return(YES); | ||
75 | } | ||
76 | else if ([inObject isKindOfClass:[NSArray class]]) | ||
77 | { | ||
78 | return(YES); | ||
79 | } | ||
80 | else if ([inObject isKindOfClass:[NSDictionary class]]) | ||
81 | { | ||
82 | return(YES); | ||
83 | } | ||
84 | else if ([inObject isKindOfClass:[NSData class]]) | ||
85 | { | ||
86 | return(YES); | ||
87 | } | ||
88 | else if ([inObject respondsToSelector:@selector(JSONDataRepresentation)]) | ||
89 | { | ||
90 | return(YES); | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | return(NO); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | - (NSData *)serializeObject:(id)inObject error:(NSError **)outError | ||
99 | { | ||
100 | NSData *theResult = NULL; | ||
101 | |||
102 | if ([inObject isKindOfClass:[NSNull class]]) | ||
103 | { | ||
104 | theResult = [self serializeNull:inObject error:outError]; | ||
105 | } | ||
106 | else if ([inObject isKindOfClass:[NSNumber class]]) | ||
107 | { | ||
108 | theResult = [self serializeNumber:inObject error:outError]; | ||
109 | } | ||
110 | else if ([inObject isKindOfClass:[NSString class]]) | ||
111 | { | ||
112 | theResult = [self serializeString:inObject error:outError]; | ||
113 | } | ||
114 | else if ([inObject isKindOfClass:[NSArray class]]) | ||
115 | { | ||
116 | theResult = [self serializeArray:inObject error:outError]; | ||
117 | } | ||
118 | else if ([inObject isKindOfClass:[NSDictionary class]]) | ||
119 | { | ||
120 | theResult = [self serializeDictionary:inObject error:outError]; | ||
121 | } | ||
122 | else if ([inObject isKindOfClass:[NSData class]]) | ||
123 | { | ||
124 | NSString *theString = [[[NSString alloc] initWithData:inObject encoding:NSUTF8StringEncoding] autorelease]; | ||
125 | theResult = [self serializeString:theString error:outError]; | ||
126 | } | ||
127 | else if ([inObject respondsToSelector:@selector(JSONDataRepresentation)]) | ||
128 | { | ||
129 | theResult = [inObject JSONDataRepresentation]; | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | if (outError) | ||
134 | { | ||
135 | NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: | ||
136 | [NSString stringWithFormat:@"Cannot serialize data of type '%@'", NSStringFromClass([inObject class])], NSLocalizedDescriptionKey, | ||
137 | NULL]; | ||
138 | *outError = [NSError errorWithDomain:@"TODO_DOMAIN" code:CJSONSerializerErrorCouldNotSerializeDataType userInfo:theUserInfo]; | ||
139 | } | ||
140 | return(NULL); | ||
141 | } | ||
142 | if (theResult == NULL) | ||
143 | { | ||
144 | if (outError) | ||
145 | { | ||
146 | NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: | ||
147 | [NSString stringWithFormat:@"Could not serialize object '%@'", inObject], NSLocalizedDescriptionKey, | ||
148 | NULL]; | ||
149 | *outError = [NSError errorWithDomain:@"TODO_DOMAIN" code:CJSONSerializerErrorCouldNotSerializeObject userInfo:theUserInfo]; | ||
150 | } | ||
151 | return(NULL); | ||
152 | } | ||
153 | return(theResult); | ||
154 | } | ||
155 | |||
156 | - (NSData *)serializeNull:(NSNull *)inNull error:(NSError **)outError | ||
157 | { | ||
158 | #pragma unused (inNull, outError) | ||
159 | return(kNULL); | ||
160 | } | ||
161 | |||
162 | - (NSData *)serializeNumber:(NSNumber *)inNumber error:(NSError **)outError | ||
163 | { | ||
164 | #pragma unused (outError) | ||
165 | NSData *theResult = NULL; | ||
166 | switch (CFNumberGetType((CFNumberRef)inNumber)) | ||
167 | { | ||
168 | case kCFNumberCharType: | ||
169 | { | ||
170 | int theValue = [inNumber intValue]; | ||
171 | if (theValue == 0) | ||
172 | theResult = kFalse; | ||
173 | else if (theValue == 1) | ||
174 | theResult = kTrue; | ||
175 | else | ||
176 | theResult = [[inNumber stringValue] dataUsingEncoding:NSASCIIStringEncoding]; | ||
177 | } | ||
178 | break; | ||
179 | case kCFNumberFloat32Type: | ||
180 | case kCFNumberFloat64Type: | ||
181 | case kCFNumberFloatType: | ||
182 | case kCFNumberDoubleType: | ||
183 | case kCFNumberSInt8Type: | ||
184 | case kCFNumberSInt16Type: | ||
185 | case kCFNumberSInt32Type: | ||
186 | case kCFNumberSInt64Type: | ||
187 | case kCFNumberShortType: | ||
188 | case kCFNumberIntType: | ||
189 | case kCFNumberLongType: | ||
190 | case kCFNumberLongLongType: | ||
191 | case kCFNumberCFIndexType: | ||
192 | default: | ||
193 | theResult = [[inNumber stringValue] dataUsingEncoding:NSASCIIStringEncoding]; | ||
194 | break; | ||
195 | } | ||
196 | return(theResult); | ||
197 | } | ||
198 | |||
199 | - (NSData *)serializeString:(NSString *)inString error:(NSError **)outError | ||
200 | { | ||
201 | #pragma unused (outError) | ||
202 | |||
203 | const char *theUTF8String = [inString UTF8String]; | ||
204 | |||
205 | NSMutableData *theData = [NSMutableData dataWithLength:strlen(theUTF8String) * 2 + 2]; | ||
206 | |||
207 | char *theOutputStart = [theData mutableBytes]; | ||
208 | char *OUT = theOutputStart; | ||
209 | |||
210 | *OUT++ = '"'; | ||
211 | |||
212 | for (const char *IN = theUTF8String; IN && *IN != '\0'; ++IN) | ||
213 | { | ||
214 | switch (*IN) | ||
215 | { | ||
216 | case '\\': | ||
217 | { | ||
218 | *OUT++ = '\\'; | ||
219 | *OUT++ = '\\'; | ||
220 | } | ||
221 | break; | ||
222 | case '\"': | ||
223 | { | ||
224 | *OUT++ = '\\'; | ||
225 | *OUT++ = '\"'; | ||
226 | } | ||
227 | break; | ||
228 | case '/': | ||
229 | { | ||
230 | *OUT++ = '\\'; | ||
231 | *OUT++ = '/'; | ||
232 | } | ||
233 | break; | ||
234 | case '\b': | ||
235 | { | ||
236 | *OUT++ = '\\'; | ||
237 | *OUT++ = 'b'; | ||
238 | } | ||
239 | break; | ||
240 | case '\f': | ||
241 | { | ||
242 | *OUT++ = '\\'; | ||
243 | *OUT++ = 'f'; | ||
244 | } | ||
245 | break; | ||
246 | case '\n': | ||
247 | { | ||
248 | *OUT++ = '\\'; | ||
249 | *OUT++ = 'n'; | ||
250 | } | ||
251 | break; | ||
252 | case '\r': | ||
253 | { | ||
254 | *OUT++ = '\\'; | ||
255 | *OUT++ = 'r'; | ||
256 | } | ||
257 | break; | ||
258 | case '\t': | ||
259 | { | ||
260 | *OUT++ = '\\'; | ||
261 | *OUT++ = 't'; | ||
262 | } | ||
263 | break; | ||
264 | default: | ||
265 | { | ||
266 | *OUT++ = *IN; | ||
267 | } | ||
268 | break; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | *OUT++ = '"'; | ||
273 | |||
274 | theData.length = OUT - theOutputStart; | ||
275 | return(theData); | ||
276 | } | ||
277 | |||
278 | - (NSData *)serializeArray:(NSArray *)inArray error:(NSError **)outError | ||
279 | { | ||
280 | NSMutableData *theData = [NSMutableData data]; | ||
281 | |||
282 | [theData appendBytes:"[" length:1]; | ||
283 | |||
284 | NSEnumerator *theEnumerator = [inArray objectEnumerator]; | ||
285 | id theValue = NULL; | ||
286 | NSUInteger i = 0; | ||
287 | while ((theValue = [theEnumerator nextObject]) != NULL) | ||
288 | { | ||
289 | NSData *theValueData = [self serializeObject:theValue error:outError]; | ||
290 | if (theValueData == NULL) | ||
291 | { | ||
292 | return(NULL); | ||
293 | } | ||
294 | [theData appendData:theValueData]; | ||
295 | if (++i < [inArray count]) | ||
296 | [theData appendBytes:"," length:1]; | ||
297 | } | ||
298 | |||
299 | [theData appendBytes:"]" length:1]; | ||
300 | |||
301 | return(theData); | ||
302 | } | ||
303 | |||
304 | - (NSData *)serializeDictionary:(NSDictionary *)inDictionary error:(NSError **)outError | ||
305 | { | ||
306 | NSMutableData *theData = [NSMutableData data]; | ||
307 | |||
308 | [theData appendBytes:"{" length:1]; | ||
309 | |||
310 | NSArray *theKeys = [inDictionary allKeys]; | ||
311 | NSEnumerator *theEnumerator = [theKeys objectEnumerator]; | ||
312 | NSString *theKey = NULL; | ||
313 | while ((theKey = [theEnumerator nextObject]) != NULL) | ||
314 | { | ||
315 | id theValue = [inDictionary objectForKey:theKey]; | ||
316 | |||
317 | NSData *theKeyData = [self serializeString:theKey error:outError]; | ||
318 | if (theKeyData == NULL) | ||
319 | { | ||
320 | return(NULL); | ||
321 | } | ||
322 | NSData *theValueData = [self serializeObject:theValue error:outError]; | ||
323 | if (theValueData == NULL) | ||
324 | { | ||
325 | return(NULL); | ||
326 | } | ||
327 | |||
328 | |||
329 | [theData appendData:theKeyData]; | ||
330 | [theData appendBytes:":" length:1]; | ||
331 | [theData appendData:theValueData]; | ||
332 | |||
333 | if (theKey != [theKeys lastObject]) | ||
334 | [theData appendData:[@"," dataUsingEncoding:NSASCIIStringEncoding]]; | ||
335 | } | ||
336 | |||
337 | [theData appendBytes:"}" length:1]; | ||
338 | |||
339 | return(theData); | ||
340 | } | ||
341 | |||
342 | @end | ||