/* * Copyright (C) 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "ArgumentCodersMac.h" #import "ArgumentCodersCF.h" #import "ArgumentDecoder.h" #import "ArgumentEncoder.h" #import "WebCoreArgumentCoders.h" #import using namespace WebCore; namespace IPC { enum NSType { NSAttributedStringType, #if USE(APPKIT) NSColorType, #endif NSDictionaryType, NSArrayType, #if USE(APPKIT) NSFontType, #endif NSNumberType, NSStringType, NSDateType, NSDataType, Unknown, }; static NSType typeFromObject(id object) { ASSERT(object); if ([object isKindOfClass:[NSAttributedString class]]) return NSAttributedStringType; #if USE(APPKIT) if ([object isKindOfClass:[NSColor class]]) return NSColorType; #endif if ([object isKindOfClass:[NSDictionary class]]) return NSDictionaryType; #if USE(APPKIT) if ([object isKindOfClass:[NSFont class]]) return NSFontType; #endif if ([object isKindOfClass:[NSNumber class]]) return NSNumberType; if ([object isKindOfClass:[NSString class]]) return NSStringType; if ([object isKindOfClass:[NSArray class]]) return NSArrayType; if ([object isKindOfClass:[NSDate class]]) return NSDateType; if ([object isKindOfClass:[NSData class]]) return NSDataType; ASSERT_NOT_REACHED(); return Unknown; } void encode(ArgumentEncoder& encoder, id object) { NSType type = typeFromObject(object); encoder.encodeEnum(type); switch (type) { case NSAttributedStringType: encode(encoder, static_cast(object)); return; #if USE(APPKIT) case NSColorType: encode(encoder, static_cast(object)); return; #endif case NSDictionaryType: encode(encoder, static_cast(object)); return; #if USE(APPKIT) case NSFontType: encode(encoder, static_cast(object)); return; #endif case NSNumberType: encode(encoder, static_cast(object)); return; case NSStringType: encode(encoder, static_cast(object)); return; case NSArrayType: encode(encoder, static_cast(object)); return; case NSDateType: encode(encoder, static_cast(object)); return; case NSDataType: encode(encoder, static_cast(object)); return; case Unknown: break; } ASSERT_NOT_REACHED(); } bool decode(ArgumentDecoder& decoder, RetainPtr& result) { NSType type; if (!decoder.decodeEnum(type)) return false; switch (type) { case NSAttributedStringType: { RetainPtr string; if (!decode(decoder, string)) return false; result = string; return true; } #if USE(APPKIT) case NSColorType: { RetainPtr color; if (!decode(decoder, color)) return false; result = color; return true; } #endif case NSDictionaryType: { RetainPtr dictionary; if (!decode(decoder, dictionary)) return false; result = dictionary; return true; } #if USE(APPKIT) case NSFontType: { RetainPtr font; if (!decode(decoder, font)) return false; result = font; return true; } #endif case NSNumberType: { RetainPtr number; if (!decode(decoder, number)) return false; result = number; return true; } case NSStringType: { RetainPtr string; if (!decode(decoder, string)) return false; result = string; return true; } case NSArrayType: { RetainPtr array; if (!decode(decoder, array)) return false; result = array; return true; } case NSDateType: { RetainPtr date; if (!decode(decoder, date)) return false; result = date; return true; } case NSDataType: { RetainPtr data; if (!decode(decoder, data)) return false; result = data; return true; } case Unknown: ASSERT_NOT_REACHED(); return false; } return false; } void encode(ArgumentEncoder& encoder, NSAttributedString *string) { // Even though NSAttributedString is toll free bridged with CFAttributedStringRef, attributes' values may be not, so we should stay within this file's code. NSString *plainString = [string string]; NSUInteger length = [plainString length]; IPC::encode(encoder, plainString); Vector>> ranges; NSUInteger position = 0; while (position < length) { // Collect ranges in a vector, becasue the total count should be encoded first. NSRange effectiveRange; RetainPtr attributesAtIndex = [string attributesAtIndex:position effectiveRange:&effectiveRange]; ASSERT(effectiveRange.location == position); ASSERT(effectiveRange.length); ASSERT(NSMaxRange(effectiveRange) <= length); ranges.append(std::make_pair(effectiveRange, attributesAtIndex)); position = NSMaxRange(effectiveRange); } encoder << static_cast(ranges.size()); for (size_t i = 0; i < ranges.size(); ++i) { encoder << static_cast(ranges[i].first.location); encoder << static_cast(ranges[i].first.length); IPC::encode(encoder, ranges[i].second.get()); } } bool decode(ArgumentDecoder& decoder, RetainPtr& result) { RetainPtr plainString; if (!IPC::decode(decoder, plainString)) return false; NSUInteger stringLength = [plainString length]; RetainPtr resultString = adoptNS([[NSMutableAttributedString alloc] initWithString:plainString.get()]); uint64_t rangeCount; if (!decoder.decode(rangeCount)) return false; while (rangeCount--) { uint64_t rangeLocation; uint64_t rangeLength; RetainPtr attributes; if (!decoder.decode(rangeLocation)) return false; if (!decoder.decode(rangeLength)) return false; ASSERT(rangeLocation + rangeLength > rangeLocation); ASSERT(rangeLocation + rangeLength <= stringLength); if (rangeLocation + rangeLength <= rangeLocation || rangeLocation + rangeLength > stringLength) return false; if (!IPC::decode(decoder, attributes)) return false; [resultString addAttributes:attributes.get() range:NSMakeRange(rangeLocation, rangeLength)]; } result = adoptNS(resultString.leakRef()); return true; } #if USE(APPKIT) void encode(ArgumentEncoder& encoder, NSColor *color) { encoder << colorFromNSColor(color); } bool decode(ArgumentDecoder& decoder, RetainPtr& result) { Color color; if (!decoder.decode(color)) return false; result = nsColor(color); return true; } #endif void encode(ArgumentEncoder& encoder, NSDictionary *dictionary) { // Even though NSDictionary is toll free bridged with CFDictionaryRef, values may be not, so we should stay within this file's code. NSUInteger size = [dictionary count]; NSArray *keys = [dictionary allKeys]; NSArray *values = [dictionary allValues]; encoder << static_cast(size); for (NSUInteger i = 0; i < size; ++i) { id key = [keys objectAtIndex:i]; id value = [values objectAtIndex:i]; ASSERT(key); ASSERT([key isKindOfClass:[NSString class]]); ASSERT(value); // Ignore values we don't recognize. if (typeFromObject(value) == Unknown) continue; encode(encoder, (NSString *)key); encode(encoder, value); } } bool decode(ArgumentDecoder& decoder, RetainPtr& result) { uint64_t size; if (!decoder.decode(size)) return false; RetainPtr dictionary = adoptNS([[NSMutableDictionary alloc] initWithCapacity:size]); for (uint64_t i = 0; i < size; ++i) { // Try to decode the key name. RetainPtr key; if (!decode(decoder, key)) return false; RetainPtr value; if (!decode(decoder, value)) return false; [dictionary setObject:value.get() forKey:key.get()]; } result = adoptNS(dictionary.leakRef()); return true; } #if USE(APPKIT) void encode(ArgumentEncoder& encoder, NSFont *font) { // NSFont could use CTFontRef code if we had it in ArgumentCodersCF. encode(encoder, [[font fontDescriptor] fontAttributes]); } bool decode(ArgumentDecoder& decoder, RetainPtr& result) { RetainPtr fontAttributes; if (!decode(decoder, fontAttributes)) return false; NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:fontAttributes.get()]; result = [NSFont fontWithDescriptor:fontDescriptor size:0]; return true; } #endif void encode(ArgumentEncoder& encoder, NSNumber *number) { encode(encoder, (CFNumberRef)number); } bool decode(ArgumentDecoder& decoder, RetainPtr& result) { RetainPtr number; if (!decode(decoder, number)) return false; result = adoptNS((NSNumber *)number.leakRef()); return true; } void encode(ArgumentEncoder& encoder, NSString *string) { encode(encoder, (CFStringRef)string); } bool decode(ArgumentDecoder& decoder, RetainPtr& result) { RetainPtr string; if (!decode(decoder, string)) return false; result = adoptNS((NSString *)string.leakRef()); return true; } void encode(ArgumentEncoder& encoder, NSArray *array) { NSUInteger size = [array count]; encoder << static_cast(size); for (NSUInteger i = 0; i < size; ++i) { id value = [array objectAtIndex:i]; // Ignore values we don't recognize. if (typeFromObject(value) == Unknown) continue; encode(encoder, value); } } bool decode(ArgumentDecoder& decoder, RetainPtr& result) { uint64_t size; if (!decoder.decode(size)) return false; RetainPtr array = adoptNS([[NSMutableArray alloc] initWithCapacity:size]); for (uint64_t i = 0; i < size; ++i) { RetainPtr value; if (!decode(decoder, value)) return false; [array addObject:value.get()]; } result = adoptNS(array.leakRef()); return true; } void encode(ArgumentEncoder& encoder, NSDate *date) { encode(encoder, (CFDateRef)date); } bool decode(ArgumentDecoder& decoder, RetainPtr& result) { RetainPtr date; if (!decode(decoder, date)) return false; result = adoptNS((NSDate *)date.leakRef()); return true; } void encode(ArgumentEncoder& encoder, NSData *data) { encode(encoder, (CFDataRef)data); } bool decode(ArgumentDecoder& decoder, RetainPtr& result) { RetainPtr data; if (!decode(decoder, data)) return false; result = adoptNS((NSData *)data.leakRef()); return true; } } // namespace IPC