/* * 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; using namespace std; namespace CoreIPC { enum NSType { NSAttributedStringType, NSColorType, NSDictionaryType, NSFontType, NSNumberType, NSStringType, Unknown, }; static NSType typeFromObject(id object) { ASSERT(object); if ([object isKindOfClass:[NSAttributedString class]]) return NSAttributedStringType; if ([object isKindOfClass:[NSColor class]]) return NSColorType; if ([object isKindOfClass:[NSDictionary class]]) return NSDictionaryType; if ([object isKindOfClass:[NSFont class]]) return NSFontType; if ([object isKindOfClass:[NSNumber class]]) return NSNumberType; if ([object isKindOfClass:[NSString class]]) return NSStringType; ASSERT_NOT_REACHED(); return Unknown; } static void encode(ArgumentEncoder* encoder, id object) { NSType type = typeFromObject(object); encoder->encodeEnum(type); switch (type) { case NSAttributedStringType: encode(encoder, static_cast(object)); return; case NSColorType: encode(encoder, static_cast(object)); return; case NSDictionaryType: encode(encoder, static_cast(object)); return; case NSFontType: encode(encoder, static_cast(object)); return; case NSNumberType: encode(encoder, static_cast(object)); return; case NSStringType: encode(encoder, static_cast(object)); return; case Unknown: break; } ASSERT_NOT_REACHED(); } static 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; } case NSColorType: { RetainPtr color; if (!decode(decoder, color)) return false; result = color; return true; } case NSDictionaryType: { RetainPtr dictionary; if (!decode(decoder, dictionary)) return false; result = dictionary; return true; } case NSFontType: { RetainPtr font; if (!decode(decoder, font)) return false; result = font; return true; } 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 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]; CoreIPC::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(make_pair(effectiveRange, attributesAtIndex)); position = NSMaxRange(effectiveRange); } encoder->encodeUInt64(ranges.size()); for (size_t i = 0; i < ranges.size(); ++i) { encoder->encodeUInt64(ranges[i].first.location); encoder->encodeUInt64(ranges[i].first.length); CoreIPC::encode(encoder, ranges[i].second.get()); } } bool decode(ArgumentDecoder* decoder, RetainPtr& result) { RetainPtr plainString; if (!CoreIPC::decode(decoder, plainString)) return false; NSUInteger stringLength = [plainString.get() 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 (!CoreIPC::decode(decoder, attributes)) return false; [resultString.get() addAttributes:attributes.get() range:NSMakeRange(rangeLocation, rangeLength)]; } result.adoptCF(resultString.leakRef()); return true; } void encode(ArgumentEncoder* encoder, NSColor *color) { encoder->encode(colorFromNSColor(color)); } bool decode(ArgumentDecoder* decoder, RetainPtr& result) { Color color; if (!decoder->decode(color)) return false; result = nsColor(color); return true; } 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->encodeUInt64(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->decodeUInt64(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.get() setObject:value.get() forKey:key.get()]; } result.adoptCF(dictionary.leakRef()); return true; } 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; } 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.adoptCF((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.adoptCF((NSString *)string.leakRef()); return true; } }