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;
36using namespace std;
37
38namespace CoreIPC {
39
40enum NSType {
41    NSAttributedStringType,
42    NSColorType,
43    NSDictionaryType,
44    NSFontType,
45    NSNumberType,
46    NSStringType,
47    Unknown,
48};
49
50static NSType typeFromObject(id object)
51{
52    ASSERT(object);
53
54    if ([object isKindOfClass:[NSAttributedString class]])
55        return NSAttributedStringType;
56    if ([object isKindOfClass:[NSColor class]])
57        return NSColorType;
58    if ([object isKindOfClass:[NSDictionary class]])
59        return NSDictionaryType;
60    if ([object isKindOfClass:[NSFont class]])
61        return NSFontType;
62    if ([object isKindOfClass:[NSNumber class]])
63        return NSNumberType;
64    if ([object isKindOfClass:[NSString class]])
65        return NSStringType;
66
67    ASSERT_NOT_REACHED();
68    return Unknown;
69}
70
71static void encode(ArgumentEncoder* encoder, id object)
72{
73    NSType type = typeFromObject(object);
74    encoder->encodeEnum(type);
75
76    switch (type) {
77    case NSAttributedStringType:
78        encode(encoder, static_cast<NSAttributedString *>(object));
79        return;
80    case NSColorType:
81        encode(encoder, static_cast<NSColor *>(object));
82        return;
83    case NSDictionaryType:
84        encode(encoder, static_cast<NSDictionary *>(object));
85        return;
86    case NSFontType:
87        encode(encoder, static_cast<NSFont *>(object));
88        return;
89    case NSNumberType:
90        encode(encoder, static_cast<NSNumber *>(object));
91        return;
92    case NSStringType:
93        encode(encoder, static_cast<NSString *>(object));
94        return;
95    case Unknown:
96        break;
97    }
98
99    ASSERT_NOT_REACHED();
100}
101
102static bool decode(ArgumentDecoder* decoder, RetainPtr<id>& result)
103{
104    NSType type;
105    if (!decoder->decodeEnum(type))
106        return false;
107
108    switch (type) {
109    case NSAttributedStringType: {
110        RetainPtr<NSAttributedString> string;
111        if (!decode(decoder, string))
112            return false;
113        result = string;
114        return true;
115    }
116    case NSColorType: {
117        RetainPtr<NSColor> color;
118        if (!decode(decoder, color))
119            return false;
120        result = color;
121        return true;
122    }
123    case NSDictionaryType: {
124        RetainPtr<NSDictionary> dictionary;
125        if (!decode(decoder, dictionary))
126            return false;
127        result = dictionary;
128        return true;
129    }
130    case NSFontType: {
131        RetainPtr<NSFont> font;
132        if (!decode(decoder, font))
133            return false;
134        result = font;
135        return true;
136    }
137    case NSNumberType: {
138        RetainPtr<NSNumber> number;
139        if (!decode(decoder, number))
140            return false;
141        result = number;
142        return true;
143    }
144    case NSStringType: {
145        RetainPtr<NSString> string;
146        if (!decode(decoder, string))
147            return false;
148        result = string;
149        return true;
150    }
151    case Unknown:
152        ASSERT_NOT_REACHED();
153        return false;
154    }
155
156    return false;
157}
158
159void encode(ArgumentEncoder* encoder, NSAttributedString *string)
160{
161    // Even though NSAttributedString is toll free bridged with CFAttributedStringRef, attributes' values may be not, so we should stay within this file's code.
162
163    NSString *plainString = [string string];
164    NSUInteger length = [plainString length];
165    CoreIPC::encode(encoder, plainString);
166
167    Vector<pair<NSRange, RetainPtr<NSDictionary> > > ranges;
168
169    NSUInteger position = 0;
170    while (position < length) {
171        // Collect ranges in a vector, becasue the total count should be encoded first.
172        NSRange effectiveRange;
173        RetainPtr<NSDictionary> attributesAtIndex = [string attributesAtIndex:position effectiveRange:&effectiveRange];
174        ASSERT(effectiveRange.location == position);
175        ASSERT(effectiveRange.length);
176        ASSERT(NSMaxRange(effectiveRange) <= length);
177
178        ranges.append(make_pair(effectiveRange, attributesAtIndex));
179
180        position = NSMaxRange(effectiveRange);
181    }
182
183    encoder->encodeUInt64(ranges.size());
184
185    for (size_t i = 0; i < ranges.size(); ++i) {
186        encoder->encodeUInt64(ranges[i].first.location);
187        encoder->encodeUInt64(ranges[i].first.length);
188        CoreIPC::encode(encoder, ranges[i].second.get());
189    }
190}
191
192bool decode(ArgumentDecoder* decoder, RetainPtr<NSAttributedString>& result)
193{
194    RetainPtr<NSString> plainString;
195    if (!CoreIPC::decode(decoder, plainString))
196        return false;
197
198    NSUInteger stringLength = [plainString.get() length];
199
200    RetainPtr<NSMutableAttributedString> resultString(AdoptNS, [[NSMutableAttributedString alloc] initWithString:plainString.get()]);
201
202    uint64_t rangeCount;
203    if (!decoder->decode(rangeCount))
204        return false;
205
206    while (rangeCount--) {
207        uint64_t rangeLocation;
208        uint64_t rangeLength;
209        RetainPtr<NSDictionary> attributes;
210        if (!decoder->decode(rangeLocation))
211            return false;
212        if (!decoder->decode(rangeLength))
213            return false;
214
215        ASSERT(rangeLocation + rangeLength > rangeLocation);
216        ASSERT(rangeLocation + rangeLength <= stringLength);
217        if (rangeLocation + rangeLength <= rangeLocation || rangeLocation + rangeLength > stringLength)
218            return false;
219
220        if (!CoreIPC::decode(decoder, attributes))
221            return false;
222        [resultString.get() addAttributes:attributes.get() range:NSMakeRange(rangeLocation, rangeLength)];
223    }
224
225    result.adoptCF(resultString.leakRef());
226    return true;
227}
228
229void encode(ArgumentEncoder* encoder, NSColor *color)
230{
231    encoder->encode(colorFromNSColor(color));
232}
233
234bool decode(ArgumentDecoder* decoder, RetainPtr<NSColor>& result)
235{
236    Color color;
237    if (!decoder->decode(color))
238        return false;
239
240    result = nsColor(color);
241    return true;
242}
243
244void encode(ArgumentEncoder* encoder, NSDictionary *dictionary)
245{
246    // Even though NSDictionary is toll free bridged with CFDictionaryRef, values may be not, so we should stay within this file's code.
247
248    NSUInteger size = [dictionary count];
249    NSArray *keys = [dictionary allKeys];
250    NSArray *values = [dictionary allValues];
251
252    encoder->encodeUInt64(size);
253
254    for (NSUInteger i = 0; i < size; ++i) {
255        id key = [keys objectAtIndex:i];
256        id value = [values objectAtIndex:i];
257        ASSERT(key);
258        ASSERT([key isKindOfClass:[NSString class]]);
259        ASSERT(value);
260
261        // Ignore values we don't recognize.
262        if (typeFromObject(value) == Unknown)
263            continue;
264
265        encode(encoder, (NSString *)key);
266        encode(encoder, value);
267    }
268}
269
270bool decode(ArgumentDecoder* decoder, RetainPtr<NSDictionary>& result)
271{
272    uint64_t size;
273    if (!decoder->decodeUInt64(size))
274        return false;
275
276    RetainPtr<NSMutableDictionary> dictionary(AdoptNS, [[NSMutableDictionary alloc] initWithCapacity:size]);
277    for (uint64_t i = 0; i < size; ++i) {
278        // Try to decode the key name.
279        RetainPtr<NSString> key;
280        if (!decode(decoder, key))
281            return false;
282
283        RetainPtr<id> value;
284        if (!decode(decoder, value))
285            return false;
286
287        [dictionary.get() setObject:value.get() forKey:key.get()];
288    }
289
290    result.adoptCF(dictionary.leakRef());
291    return true;
292}
293
294
295void encode(ArgumentEncoder* encoder, NSFont *font)
296{
297    // NSFont could use CTFontRef code if we had it in ArgumentCodersCF.
298    encode(encoder, [[font fontDescriptor] fontAttributes]);
299}
300
301bool decode(ArgumentDecoder* decoder, RetainPtr<NSFont>& result)
302{
303    RetainPtr<NSDictionary> fontAttributes;
304    if (!decode(decoder, fontAttributes))
305        return false;
306
307    NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:fontAttributes.get()];
308    result = [NSFont fontWithDescriptor:fontDescriptor size:0];
309
310    return true;
311}
312
313void encode(ArgumentEncoder* encoder, NSNumber *number)
314{
315    encode(encoder, (CFNumberRef)number);
316}
317
318bool decode(ArgumentDecoder* decoder, RetainPtr<NSNumber>& result)
319{
320    RetainPtr<CFNumberRef> number;
321    if (!decode(decoder, number))
322        return false;
323
324    result.adoptCF((NSNumber *)number.leakRef());
325    return true;
326}
327
328void encode(ArgumentEncoder* encoder, NSString *string)
329{
330    encode(encoder, (CFStringRef)string);
331}
332
333bool decode(ArgumentDecoder* decoder, RetainPtr<NSString>& result)
334{
335    RetainPtr<CFStringRef> string;
336    if (!decode(decoder, string))
337        return false;
338
339    result.adoptCF((NSString *)string.leakRef());
340    return true;
341}
342
343}
344