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 CFMutableDictionaryRef mutableClassMap_; 38} 39 40- (instancetype)init { 41 if ((self = [super init])) { 42 // The keys are ObjC classes, so straight up ptr comparisons are fine. 43 mutableClassMap_ = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, 44 &kCFTypeDictionaryValueCallBacks); 45 } 46 return self; 47} 48 49- (void)dealloc { 50 CFRelease(mutableClassMap_); 51 [super dealloc]; 52} 53 54// Direct access is use for speed, to avoid even internally declaring things 55// read/write, etc. The warning is enabled in the project to ensure code calling 56// protos can turn on -Wdirect-ivar-access without issues. 57#pragma clang diagnostic push 58#pragma clang diagnostic ignored "-Wdirect-ivar-access" 59 60- (instancetype)copyWithZone:(NSZone *)zone { 61 GPBExtensionRegistry *result = [[[self class] allocWithZone:zone] init]; 62 [result addExtensions:self]; 63 return result; 64} 65 66- (void)addExtension:(GPBExtensionDescriptor *)extension { 67 if (extension == nil) { 68 return; 69 } 70 71 Class containingMessageClass = extension.containingMessageClass; 72 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef) 73 CFDictionaryGetValue(mutableClassMap_, containingMessageClass); 74 if (extensionMap == nil) { 75 // Use a custom dictionary here because the keys are numbers and conversion 76 // back and forth from NSNumber isn't worth the cost. 77 extensionMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, 78 &kCFTypeDictionaryValueCallBacks); 79 CFDictionarySetValue(mutableClassMap_, containingMessageClass, extensionMap); 80 CFRelease(extensionMap); 81 } 82 83 ssize_t key = extension.fieldNumber; 84 CFDictionarySetValue(extensionMap, (const void *)key, extension); 85} 86 87- (GPBExtensionDescriptor *)extensionForDescriptor:(GPBDescriptor *)descriptor 88 fieldNumber:(NSInteger)fieldNumber { 89 Class messageClass = descriptor.messageClass; 90 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef) 91 CFDictionaryGetValue(mutableClassMap_, messageClass); 92 ssize_t key = fieldNumber; 93 GPBExtensionDescriptor *result = 94 (extensionMap 95 ? CFDictionaryGetValue(extensionMap, (const void *)key) 96 : nil); 97 return result; 98} 99 100static void CopyKeyValue(const void *key, const void *value, void *context) { 101 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)context; 102 CFDictionarySetValue(extensionMap, key, value); 103} 104 105static void CopySubDictionary(const void *key, const void *value, void *context) { 106 CFMutableDictionaryRef mutableClassMap = (CFMutableDictionaryRef)context; 107 Class containingMessageClass = key; 108 CFMutableDictionaryRef otherExtensionMap = (CFMutableDictionaryRef)value; 109 110 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef) 111 CFDictionaryGetValue(mutableClassMap, containingMessageClass); 112 if (extensionMap == nil) { 113 extensionMap = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, otherExtensionMap); 114 CFDictionarySetValue(mutableClassMap, containingMessageClass, extensionMap); 115 CFRelease(extensionMap); 116 } else { 117 CFDictionaryApplyFunction(otherExtensionMap, CopyKeyValue, extensionMap); 118 } 119} 120 121- (void)addExtensions:(GPBExtensionRegistry *)registry { 122 if (registry == nil) { 123 // In the case where there are no extensions just ignore. 124 return; 125 } 126 CFDictionaryApplyFunction(registry->mutableClassMap_, CopySubDictionary, mutableClassMap_); 127} 128 129#pragma clang diagnostic pop 130 131@end 132