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