1/*
2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27#import "ArgumentCodersMac.h"
28
29#import "ArgumentCodersCF.h"
30#import "ArgumentDecoder.h"
31#import "ArgumentEncoder.h"
32#import "WebCoreArgumentCoders.h"
33#import <WebCore/ColorMac.h>
34
35using namespace WebCore;
36
37namespace IPC {
38
39enum NSType {
40    NSAttributedStringType,
41#if USE(APPKIT)
42    NSColorType,
43#endif
44    NSDictionaryType,
45    NSArrayType,
46#if USE(APPKIT)
47    NSFontType,
48#endif
49    NSNumberType,
50    NSStringType,
51    NSDateType,
52    NSDataType,
53    Unknown,
54};
55
56static NSType typeFromObject(id object)
57{
58    ASSERT(object);
59
60    if ([object isKindOfClass:[NSAttributedString class]])
61        return NSAttributedStringType;
62#if USE(APPKIT)
63    if ([object isKindOfClass:[NSColor class]])
64        return NSColorType;
65#endif
66    if ([object isKindOfClass:[NSDictionary class]])
67        return NSDictionaryType;
68#if USE(APPKIT)
69    if ([object isKindOfClass:[NSFont class]])
70        return NSFontType;
71#endif
72    if ([object isKindOfClass:[NSNumber class]])
73        return NSNumberType;
74    if ([object isKindOfClass:[NSString class]])
75        return NSStringType;
76    if ([object isKindOfClass:[NSArray class]])
77        return NSArrayType;
78    if ([object isKindOfClass:[NSDate class]])
79        return NSDateType;
80    if ([object isKindOfClass:[NSData class]])
81        return NSDataType;
82
83    ASSERT_NOT_REACHED();
84    return Unknown;
85}
86
87void encode(ArgumentEncoder& encoder, id object)
88{
89    NSType type = typeFromObject(object);
90    encoder.encodeEnum(type);
91
92    switch (type) {
93    case NSAttributedStringType:
94        encode(encoder, static_cast<NSAttributedString *>(object));
95        return;
96#if USE(APPKIT)
97    case NSColorType:
98        encode(encoder, static_cast<NSColor *>(object));
99        return;
100#endif
101    case NSDictionaryType:
102        encode(encoder, static_cast<NSDictionary *>(object));
103        return;
104#if USE(APPKIT)
105    case NSFontType:
106        encode(encoder, static_cast<NSFont *>(object));
107        return;
108#endif
109    case NSNumberType:
110        encode(encoder, static_cast<NSNumber *>(object));
111        return;
112    case NSStringType:
113        encode(encoder, static_cast<NSString *>(object));
114        return;
115    case NSArrayType:
116        encode(encoder, static_cast<NSArray *>(object));
117        return;
118    case NSDateType:
119        encode(encoder, static_cast<NSDate *>(object));
120        return;
121    case NSDataType:
122        encode(encoder, static_cast<NSData *>(object));
123        return;
124    case Unknown:
125        break;
126    }
127
128    ASSERT_NOT_REACHED();
129}
130
131bool decode(ArgumentDecoder& decoder, RetainPtr<id>& result)
132{
133    NSType type;
134    if (!decoder.decodeEnum(type))
135        return false;
136
137    switch (type) {
138    case NSAttributedStringType: {
139        RetainPtr<NSAttributedString> string;
140        if (!decode(decoder, string))
141            return false;
142        result = string;
143        return true;
144    }
145#if USE(APPKIT)
146    case NSColorType: {
147        RetainPtr<NSColor> color;
148        if (!decode(decoder, color))
149            return false;
150        result = color;
151        return true;
152    }
153#endif
154    case NSDictionaryType: {
155        RetainPtr<NSDictionary> dictionary;
156        if (!decode(decoder, dictionary))
157            return false;
158        result = dictionary;
159        return true;
160    }
161#if USE(APPKIT)
162    case NSFontType: {
163        RetainPtr<NSFont> font;
164        if (!decode(decoder, font))
165            return false;
166        result = font;
167        return true;
168    }
169#endif
170    case NSNumberType: {
171        RetainPtr<NSNumber> number;
172        if (!decode(decoder, number))
173            return false;
174        result = number;
175        return true;
176    }
177    case NSStringType: {
178        RetainPtr<NSString> string;
179        if (!decode(decoder, string))
180            return false;
181        result = string;
182        return true;
183    }
184    case NSArrayType: {
185        RetainPtr<NSArray> array;
186        if (!decode(decoder, array))
187            return false;
188        result = array;
189        return true;
190    }
191    case NSDateType: {
192        RetainPtr<NSDate> date;
193        if (!decode(decoder, date))
194            return false;
195        result = date;
196        return true;
197    }
198    case NSDataType: {
199        RetainPtr<NSData> data;
200        if (!decode(decoder, data))
201            return false;
202        result = data;
203        return true;
204    }
205    case Unknown:
206        ASSERT_NOT_REACHED();
207        return false;
208    }
209
210    return false;
211}
212
213void encode(ArgumentEncoder& encoder, NSAttributedString *string)
214{
215    // Even though NSAttributedString is toll free bridged with CFAttributedStringRef, attributes' values may be not, so we should stay within this file's code.
216
217    NSString *plainString = [string string];
218    NSUInteger length = [plainString length];
219    IPC::encode(encoder, plainString);
220
221    Vector<std::pair<NSRange, RetainPtr<NSDictionary>>> ranges;
222
223    NSUInteger position = 0;
224    while (position < length) {
225        // Collect ranges in a vector, becasue the total count should be encoded first.
226        NSRange effectiveRange;
227        RetainPtr<NSDictionary> attributesAtIndex = [string attributesAtIndex:position effectiveRange:&effectiveRange];
228        ASSERT(effectiveRange.location == position);
229        ASSERT(effectiveRange.length);
230        ASSERT(NSMaxRange(effectiveRange) <= length);
231
232        ranges.append(std::make_pair(effectiveRange, attributesAtIndex));
233
234        position = NSMaxRange(effectiveRange);
235    }
236
237    encoder << static_cast<uint64_t>(ranges.size());
238
239    for (size_t i = 0; i < ranges.size(); ++i) {
240        encoder << static_cast<uint64_t>(ranges[i].first.location);
241        encoder << static_cast<uint64_t>(ranges[i].first.length);
242        IPC::encode(encoder, ranges[i].second.get());
243    }
244}
245
246bool decode(ArgumentDecoder& decoder, RetainPtr<NSAttributedString>& result)
247{
248    RetainPtr<NSString> plainString;
249    if (!IPC::decode(decoder, plainString))
250        return false;
251
252    NSUInteger stringLength = [plainString length];
253
254    RetainPtr<NSMutableAttributedString> resultString = adoptNS([[NSMutableAttributedString alloc] initWithString:plainString.get()]);
255
256    uint64_t rangeCount;
257    if (!decoder.decode(rangeCount))
258        return false;
259
260    while (rangeCount--) {
261        uint64_t rangeLocation;
262        uint64_t rangeLength;
263        RetainPtr<NSDictionary> attributes;
264        if (!decoder.decode(rangeLocation))
265            return false;
266        if (!decoder.decode(rangeLength))
267            return false;
268
269        ASSERT(rangeLocation + rangeLength > rangeLocation);
270        ASSERT(rangeLocation + rangeLength <= stringLength);
271        if (rangeLocation + rangeLength <= rangeLocation || rangeLocation + rangeLength > stringLength)
272            return false;
273
274        if (!IPC::decode(decoder, attributes))
275            return false;
276        [resultString addAttributes:attributes.get() range:NSMakeRange(rangeLocation, rangeLength)];
277    }
278
279    result = adoptNS(resultString.leakRef());
280    return true;
281}
282
283#if USE(APPKIT)
284void encode(ArgumentEncoder& encoder, NSColor *color)
285{
286    encoder << colorFromNSColor(color);
287}
288
289bool decode(ArgumentDecoder& decoder, RetainPtr<NSColor>& result)
290{
291    Color color;
292    if (!decoder.decode(color))
293        return false;
294
295    result = nsColor(color);
296    return true;
297}
298#endif
299
300void encode(ArgumentEncoder& encoder, NSDictionary *dictionary)
301{
302    // Even though NSDictionary is toll free bridged with CFDictionaryRef, values may be not, so we should stay within this file's code.
303
304    NSUInteger size = [dictionary count];
305    NSArray *keys = [dictionary allKeys];
306    NSArray *values = [dictionary allValues];
307
308    encoder << static_cast<uint64_t>(size);
309
310    for (NSUInteger i = 0; i < size; ++i) {
311        id key = [keys objectAtIndex:i];
312        id value = [values objectAtIndex:i];
313        ASSERT(key);
314        ASSERT([key isKindOfClass:[NSString class]]);
315        ASSERT(value);
316
317        // Ignore values we don't recognize.
318        if (typeFromObject(value) == Unknown)
319            continue;
320
321        encode(encoder, (NSString *)key);
322        encode(encoder, value);
323    }
324}
325
326bool decode(ArgumentDecoder& decoder, RetainPtr<NSDictionary>& result)
327{
328    uint64_t size;
329    if (!decoder.decode(size))
330        return false;
331
332    RetainPtr<NSMutableDictionary> dictionary = adoptNS([[NSMutableDictionary alloc] initWithCapacity:size]);
333    for (uint64_t i = 0; i < size; ++i) {
334        // Try to decode the key name.
335        RetainPtr<NSString> key;
336        if (!decode(decoder, key))
337            return false;
338
339        RetainPtr<id> value;
340        if (!decode(decoder, value))
341            return false;
342
343        [dictionary setObject:value.get() forKey:key.get()];
344    }
345
346    result = adoptNS(dictionary.leakRef());
347    return true;
348}
349
350#if USE(APPKIT)
351void encode(ArgumentEncoder& encoder, NSFont *font)
352{
353    // NSFont could use CTFontRef code if we had it in ArgumentCodersCF.
354    encode(encoder, [[font fontDescriptor] fontAttributes]);
355}
356
357bool decode(ArgumentDecoder& decoder, RetainPtr<NSFont>& result)
358{
359    RetainPtr<NSDictionary> fontAttributes;
360    if (!decode(decoder, fontAttributes))
361        return false;
362
363    NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:fontAttributes.get()];
364    result = [NSFont fontWithDescriptor:fontDescriptor size:0];
365
366    return true;
367}
368#endif
369
370void encode(ArgumentEncoder& encoder, NSNumber *number)
371{
372    encode(encoder, (CFNumberRef)number);
373}
374
375bool decode(ArgumentDecoder& decoder, RetainPtr<NSNumber>& result)
376{
377    RetainPtr<CFNumberRef> number;
378    if (!decode(decoder, number))
379        return false;
380
381    result = adoptNS((NSNumber *)number.leakRef());
382    return true;
383}
384
385void encode(ArgumentEncoder& encoder, NSString *string)
386{
387    encode(encoder, (CFStringRef)string);
388}
389
390bool decode(ArgumentDecoder& decoder, RetainPtr<NSString>& result)
391{
392    RetainPtr<CFStringRef> string;
393    if (!decode(decoder, string))
394        return false;
395
396    result = adoptNS((NSString *)string.leakRef());
397    return true;
398}
399
400void encode(ArgumentEncoder& encoder, NSArray *array)
401{
402    NSUInteger size = [array count];
403    encoder << static_cast<uint64_t>(size);
404
405    for (NSUInteger i = 0; i < size; ++i) {
406        id value = [array objectAtIndex:i];
407
408        // Ignore values we don't recognize.
409        if (typeFromObject(value) == Unknown)
410            continue;
411
412        encode(encoder, value);
413    }
414}
415
416bool decode(ArgumentDecoder& decoder, RetainPtr<NSArray>& result)
417{
418    uint64_t size;
419    if (!decoder.decode(size))
420        return false;
421
422    RetainPtr<NSMutableArray> array = adoptNS([[NSMutableArray alloc] initWithCapacity:size]);
423    for (uint64_t i = 0; i < size; ++i) {
424        RetainPtr<id> value;
425        if (!decode(decoder, value))
426            return false;
427
428        [array addObject:value.get()];
429    }
430
431    result = adoptNS(array.leakRef());
432    return true;
433}
434
435void encode(ArgumentEncoder& encoder, NSDate *date)
436{
437    encode(encoder, (CFDateRef)date);
438}
439
440bool decode(ArgumentDecoder& decoder, RetainPtr<NSDate>& result)
441{
442    RetainPtr<CFDateRef> date;
443    if (!decode(decoder, date))
444        return false;
445
446    result = adoptNS((NSDate *)date.leakRef());
447    return true;
448}
449
450void encode(ArgumentEncoder& encoder, NSData *data)
451{
452    encode(encoder, (CFDataRef)data);
453}
454
455bool decode(ArgumentDecoder& decoder, RetainPtr<NSData>& result)
456{
457    RetainPtr<CFDataRef> data;
458    if (!decode(decoder, data))
459        return false;
460
461    result = adoptNS((NSData *)data.leakRef());
462    return true;
463}
464
465} // namespace IPC
466