1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// https://developers.google.com/protocol-buffers/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31#import "GPBExtensionRegistry.h" 32 33#import "GPBBootstrap.h" 34#import "GPBDescriptor.h" 35 36@implementation GPBExtensionRegistry { 37 NSMutableDictionary *mutableClassMap_; 38} 39 40- (instancetype)init { 41 if ((self = [super init])) { 42 mutableClassMap_ = [[NSMutableDictionary alloc] init]; 43 } 44 return self; 45} 46 47- (void)dealloc { 48 [mutableClassMap_ release]; 49 [super dealloc]; 50} 51 52// Direct access is use for speed, to avoid even internally declaring things 53// read/write, etc. The warning is enabled in the project to ensure code calling 54// protos can turn on -Wdirect-ivar-access without issues. 55#pragma clang diagnostic push 56#pragma clang diagnostic ignored "-Wdirect-ivar-access" 57 58- (instancetype)copyWithZone:(NSZone *)zone { 59 GPBExtensionRegistry *result = [[[self class] allocWithZone:zone] init]; 60 [result addExtensions:self]; 61 return result; 62} 63 64- (void)addExtension:(GPBExtensionDescriptor *)extension { 65 if (extension == nil) { 66 return; 67 } 68 69 Class containingMessageClass = extension.containingMessageClass; 70 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef) 71 [mutableClassMap_ objectForKey:containingMessageClass]; 72 if (extensionMap == nil) { 73 // Use a custom dictionary here because the keys are numbers and conversion 74 // back and forth from NSNumber isn't worth the cost. 75 extensionMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, 76 &kCFTypeDictionaryValueCallBacks); 77 [mutableClassMap_ setObject:(id)extensionMap 78 forKey:(id<NSCopying>)containingMessageClass]; 79 CFRelease(extensionMap); 80 } 81 82 ssize_t key = extension.fieldNumber; 83 CFDictionarySetValue(extensionMap, (const void *)key, extension); 84} 85 86- (GPBExtensionDescriptor *)extensionForDescriptor:(GPBDescriptor *)descriptor 87 fieldNumber:(NSInteger)fieldNumber { 88 Class messageClass = descriptor.messageClass; 89 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef) 90 [mutableClassMap_ objectForKey:messageClass]; 91 ssize_t key = fieldNumber; 92 GPBExtensionDescriptor *result = 93 (extensionMap 94 ? CFDictionaryGetValue(extensionMap, (const void *)key) 95 : nil); 96 return result; 97} 98 99static void CopyKeyValue(const void *key, const void *value, void *context) { 100 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)context; 101 CFDictionarySetValue(extensionMap, key, value); 102} 103 104- (void)addExtensions:(GPBExtensionRegistry *)registry { 105 if (registry == nil) { 106 // In the case where there are no extensions just ignore. 107 return; 108 } 109 NSMutableDictionary *otherClassMap = registry->mutableClassMap_; 110 [otherClassMap enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL * stop) { 111#pragma unused(stop) 112 Class containingMessageClass = key; 113 CFMutableDictionaryRef otherExtensionMap = (CFMutableDictionaryRef)value; 114 115 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef) 116 [mutableClassMap_ objectForKey:containingMessageClass]; 117 if (extensionMap == nil) { 118 extensionMap = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, otherExtensionMap); 119 [mutableClassMap_ setObject:(id)extensionMap 120 forKey:(id<NSCopying>)containingMessageClass]; 121 CFRelease(extensionMap); 122 } else { 123 CFDictionaryApplyFunction(otherExtensionMap, CopyKeyValue, extensionMap); 124 } 125 }]; 126} 127 128#pragma clang diagnostic pop 129 130@end 131