// ********************************************************************** // // Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** #import #import #import #import #import #import #import #import #import #import #import #include #include #include #include #import #import #ifdef ICE_NO_KQUEUE # define ICE_USE_CFSTREAM 1 #endif namespace { typedef std::map CompactIdMap; IceUtil::Mutex* _compactIdMapMutex = 0; CompactIdMap* _compactIdMap = 0; class CompactIdResolverI : public Ice::CompactIdResolver { public: virtual ::std::string resolve(::Ice::Int value) const { assert(_compactIdMapMutex); assert(_compactIdMap); IceUtilInternal::MutexPtrLock lock(_compactIdMapMutex); CompactIdMap::iterator p = _compactIdMap->find(value); if(p != _compactIdMap->end()) { return p->second; } return ::std::string(); } }; // // We don't use the constructor to initialize the compactIdMap as // static initializtion takes place after +load is called. // class Init { public: ~Init() { if(_compactIdMap) { delete _compactIdMap; _compactIdMap = 0; } if(_compactIdMapMutex) { delete _compactIdMapMutex; _compactIdMapMutex = 0; } } }; Init init; } @implementation CompactIdMapHelper +(void) initialize { assert(!_compactIdMapMutex); assert(!_compactIdMap); _compactIdMapMutex = new ::IceUtil::Mutex; _compactIdMap = new CompactIdMap; } +(void) registerClass:(NSString*)type value:(ICEInt)value { assert(_compactIdMapMutex); assert(_compactIdMap); IceUtilInternal::MutexPtrLock lock(_compactIdMapMutex); CompactIdMap::iterator p = _compactIdMap->find(value); if(p != _compactIdMap->end()) { _compactIdMap->erase(p); } _compactIdMap->insert(CompactIdMap::value_type(value, fromNSString(type))); } @end namespace IceObjC { class ThreadNotification : public Ice::ThreadNotification, public IceUtil::Mutex { public: ThreadNotification() { } virtual void start() { Lock sync(*this); _pools.insert(std::make_pair(IceUtil::ThreadControl().id(), [[NSAutoreleasePool alloc] init])); } virtual void stop() { Lock sync(*this); std::map::iterator p = _pools.find(IceUtil::ThreadControl().id()); [p->second drain]; _pools.erase(p); } private: std::map _pools; }; }; @implementation ICEInitializationData (ICEInternal) -(Ice::InitializationData)initializationData { Ice::InitializationData data; data.properties = [(ICEProperties*)properties properties]; data.logger = [ICELogger loggerWithLogger:logger]; if(batchRequestInterceptor) { data.batchRequestInterceptor = [ICEBatchRequestInterceptor batchRequestInterceptorWithBatchRequestInterceptor:batchRequestInterceptor]; } if(dispatcher) { data.dispatcher = [ICEDispatcher dispatcherWithDispatcher:dispatcher]; } data.compactIdResolver = new CompactIdResolverI; return data; } @end @implementation ICEInitializationData @synthesize properties; @synthesize logger; @synthesize dispatcher; @synthesize batchRequestInterceptor; @synthesize prefixTable__; -(id) init:(id)props logger:(id)log dispatcher:(void(^)(id, id))d; { self = [super init]; if(!self) { return nil; } properties = [props retain]; logger = [log retain]; dispatcher = [d copy]; return self; } +(id) initializationData; { ICEInitializationData *s = [[ICEInitializationData alloc] init]; [s autorelease]; return s; } +(id) initializationData:(id)p logger:(id)l dispatcher:(void(^)(id, id))d; { return [[((ICEInitializationData *)[ICEInitializationData alloc]) init:p logger:l dispatcher:d] autorelease]; } -(id) copyWithZone:(NSZone *)zone { ICEInitializationData *copy = [ICEInitializationData allocWithZone:zone]; copy->properties = [properties retain]; copy->logger = [logger retain]; copy->dispatcher = [dispatcher copy]; copy->prefixTable__ = [prefixTable__ retain]; return copy; } -(NSUInteger) hash; { NSUInteger h = 0; h = (h << 5 ^ [properties hash]); h = (h << 5 ^ [logger hash]); h = (h << 5 ^ [prefixTable__ hash]); return h; } -(BOOL) isEqual:(id)anObject; { if(self == anObject) { return YES; } if(!anObject || ![anObject isKindOfClass:[self class]]) { return NO; } ICEInitializationData * obj =(ICEInitializationData *)anObject; if(!properties) { if(obj->properties) { return NO; } } else { if(![properties isEqual:obj->properties]) { return NO; } } if(!logger) { if(obj->logger) { return NO; } } else { if(![logger isEqual:obj->logger]) { return NO; } } if(!dispatcher) { if(obj->dispatcher) { return NO; } } else { if(dispatcher == obj->dispatcher) { return NO; } } if(!prefixTable__) { if(obj->prefixTable__) { return NO; } } else { if(![prefixTable__ isEqual:obj->prefixTable__]) { return NO; } } return YES; } -(void) dealloc; { [properties release]; [logger release]; [dispatcher release]; [prefixTable__ release]; [super dealloc]; } @end @implementation ICEUtil +(id) createProperties { return [self createProperties:nil argv:nil]; } +(id) createProperties:(int*)argc argv:(char*[])argv { NSException* nsex = nil; try { Ice::PropertiesPtr properties; if(argc != nil && argv != nil) { properties = Ice::createProperties(*argc, argv); } else { properties = Ice::createProperties(); } return [ICEProperties localObjectWithCxxObject:properties.get()]; } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) createCommunicator { return [self createCommunicator:nil argv:nil initData:nil]; } +(id) createCommunicator:(ICEInitializationData*)initData { return [self createCommunicator:nil argv:nil initData:initData]; } +(id) createCommunicator:(int*)argc argv:(char*[])argv { return [self createCommunicator:argc argv:argv initData:nil]; } +(id) createCommunicator:(int*)argc argv:(char*[])argv initData:(ICEInitializationData*)initData { if(![NSThread isMultiThreaded]) // Ensure sure Cocoa is multithreaded. { NSThread* thread = [[NSThread alloc] init]; [thread start]; [thread release]; } id properties = [initData properties]; if(properties != nil && ![properties isKindOfClass:[ICEProperties class]]) { @throw [ICEInitializationException initializationException:__FILE__ line:__LINE__ reason:@"properties were not created with createProperties"]; } NSException* nsex = nil; try { Ice::InitializationData data; if(initData != nil) { data = [initData initializationData]; } data.threadHook = new IceObjC::ThreadNotification(); if(!data.properties) { data.properties = Ice::createProperties(); } if(argc != nil && argv != nil) { data.properties = createProperties(*argc, argv, data.properties); } Ice::CommunicatorPtr communicator; if(argc != nil && argv != nil) { communicator = Ice::initialize(*argc, argv, data); } else { communicator = Ice::initialize(data); } ICECommunicator* c = [ICECommunicator localObjectWithCxxObject:communicator.get()]; [c setup:initData.prefixTable__]; return c; } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) createInputStream:(id)communicator data:(NSData*)data { NSException* nsex = nil; try { Ice::CommunicatorPtr com = [(ICECommunicator*)communicator communicator]; Ice::Byte* start = (Ice::Byte*)[data bytes]; Ice::Byte* end = (Ice::Byte*)[data bytes] + [data length]; Ice::InputStreamPtr is = Ice::createInputStream(com, std::make_pair(start, end)); if(is) { return [ICEInputStream localObjectWithCxxObject:is.get()]; } else { return nil; } } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) createInputStream:(id)c data:(NSData*)data encoding:(ICEEncodingVersion*)e { NSException* nsex = nil; try { Ice::CommunicatorPtr com = [(ICECommunicator*)c communicator]; Ice::Byte* start = (Ice::Byte*)[data bytes]; Ice::Byte* end = (Ice::Byte*)[data bytes] + [data length]; Ice::InputStreamPtr is = Ice::createInputStream(com, std::make_pair(start, end), [e encodingVersion]); if(is) { return [ICEInputStream localObjectWithCxxObject:is.get()]; } else { return nil; } } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) wrapInputStream:(id)communicator data:(NSData*)data { NSException* nsex = nil; try { Ice::CommunicatorPtr com = [(ICECommunicator*)communicator communicator]; Ice::Byte* start = (Ice::Byte*)[data bytes]; Ice::Byte* end = (Ice::Byte*)[data bytes] + [data length]; Ice::InputStreamPtr is = Ice::wrapInputStream(com, std::make_pair(start, end)); if(is) { return [ICEInputStream localObjectWithCxxObject:is.get()]; } else { return nil; } } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) wrapInputStream:(id)c data:(NSData*)data encoding:(ICEEncodingVersion*)e { NSException* nsex = nil; try { Ice::CommunicatorPtr com = [(ICECommunicator*)c communicator]; Ice::Byte* start = (Ice::Byte*)[data bytes]; Ice::Byte* end = (Ice::Byte*)[data bytes] + [data length]; Ice::InputStreamPtr is = Ice::wrapInputStream(com, std::make_pair(start, end), [e encodingVersion]); if(is) { return [ICEInputStream localObjectWithCxxObject:is.get()]; } else { return nil; } } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) createOutputStream:(id)communicator { NSException* nsex = nil; try { Ice::CommunicatorPtr com = [(ICECommunicator*)communicator communicator]; Ice::OutputStreamPtr os = Ice::createOutputStream(com); if(os) { return [ICEOutputStream localObjectWithCxxObject:os.get()]; } else { return nil; } } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) createOutputStream:(id)communicator encoding:(ICEEncodingVersion*)encoding { NSException* nsex = nil; try { Ice::CommunicatorPtr com = [(ICECommunicator*)communicator communicator]; Ice::OutputStreamPtr os = Ice::createOutputStream(com, [encoding encodingVersion]); if(os) { return [ICEOutputStream localObjectWithCxxObject:os.get()]; } else { return nil; } } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(NSString*) generateUUID { return [NSString stringWithUTF8String:IceUtil::generateUUID().c_str()]; } +(NSArray*)argsToStringSeq:(int)argc argv:(char*[])argv { NSMutableArray* ns = [NSMutableArray array]; int i; for(i = 0; i < argc; ++i) { [ns addObject:[NSString stringWithCString:argv[i] encoding:NSUTF8StringEncoding]]; } return [[ns copy] autorelease]; } +(void)stringSeqToArgs:(NSArray*)args argc:(int*)argc argv:(char*[])argv; { // // Shift all elements in argv which are present in args to the // beginning of argv. We record the original value of argc so // that we can know later if we've shifted the array. // const int argcOrig = *argc; int i = 0; while(i < *argc) { BOOL found = NO; for(NSString* s in args) { if([s compare:[NSString stringWithCString:argv[i] encoding:NSUTF8StringEncoding]] == 0) { found = YES; break; } } if(!found) { int j; for(j = i; j < *argc - 1; j++) { argv[j] = argv[j + 1]; } --(*argc); } else { ++i; } } // // Make sure that argv[*argc] == 0, the ISO C++ standard requires this. // We can only do this if we've shifted the array, otherwise argv[*argc] // may point to an invalid address. // if(argv && argcOrig != *argc) { argv[*argc] = 0; } } @end @implementation ICEEncodingVersion(StringConv) +(ICEEncodingVersion*) encodingVersionWithString:(NSString*)str { return [ICEEncodingVersion encodingVersionWithEncodingVersion:Ice::stringToEncodingVersion(fromNSString(str))]; } @end @implementation ICEProtocolVersion(StringConv) +(ICEProtocolVersion*) protocolVersionWithString:(NSString*)str { return [ICEProtocolVersion protocolVersionWithProtocolVersion:Ice::stringToProtocolVersion(fromNSString(str))]; } @end