Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -95,11 +95,11 @@ OFXMLElement.m \ OFXMLElement+Serialization.m \ OFXMLElementBuilder.m \ OFXMLNode.m \ OFXMLParser.m \ - OFXMLProcessingInstructions.m \ + OFXMLProcessingInstruction.m \ OFZIPArchive.m \ OFZIPArchiveEntry.m \ base64.m \ crc16.m \ crc32.m \ Index: src/OFXMLElementBuilder.m ================================================================== --- src/OFXMLElementBuilder.m +++ src/OFXMLElementBuilder.m @@ -14,18 +14,18 @@ */ #include "config.h" #import "OFXMLElementBuilder.h" -#import "OFXMLElement.h" +#import "OFArray.h" #import "OFXMLAttribute.h" -#import "OFXMLCharacters.h" #import "OFXMLCDATA.h" +#import "OFXMLCharacters.h" #import "OFXMLComment.h" -#import "OFXMLProcessingInstructions.h" +#import "OFXMLElement.h" #import "OFXMLParser.h" -#import "OFArray.h" +#import "OFXMLProcessingInstruction.h" #import "OFMalformedXMLException.h" @implementation OFXMLElementBuilder @synthesize delegate = _delegate; @@ -54,15 +54,17 @@ [_stack release]; [super dealloc]; } -- (void)parser: (OFXMLParser *)parser - foundProcessingInstructions: (OFString *)pi +- (void)parser: (OFXMLParser *)parser + foundProcessingInstructionWithTarget: (OFString *)target + data: (OFString *)data { - OFXMLProcessingInstructions *node = [OFXMLProcessingInstructions - processingInstructionsWithString: pi]; + OFXMLProcessingInstruction *node = [OFXMLProcessingInstruction + processingInstructionWithTarget: target + data: data]; OFXMLElement *parent = _stack.lastObject; if (parent != nil) [parent addChild: node]; else if ([_delegate respondsToSelector: Index: src/OFXMLParser.h ================================================================== --- src/OFXMLParser.h +++ src/OFXMLParser.h @@ -32,18 +32,20 @@ * @brief A protocol that needs to be implemented by delegates for OFXMLParser. */ @protocol OFXMLParserDelegate @optional /** - * @brief This callback is called when the XML parser found processing - * instructions. - * - * @param parser The parser which found processing instructions - * @param processingInstructions The processing instructions - */ -- (void)parser: (OFXMLParser *)parser - foundProcessingInstructions: (OFString *)processingInstructions; + * @brief This callback is called when the XML parser found a processing + * instruction. + * + * @param parser The parser which found a processing instruction + * @param target The target of the processing instruction + * @param data The data of the processing instruction + */ +- (void)parser: (OFXMLParser *)parser + foundProcessingInstructionWithTarget: (OFString *)target + data: (OFString *)data; /** * @brief This callback is called when the XML parser found the start of a new * tag. * @@ -130,11 +132,11 @@ id _Nullable _delegate; enum of_xml_parser_state { OF_XMLPARSER_IN_BYTE_ORDER_MARK, OF_XMLPARSER_OUTSIDE_TAG, OF_XMLPARSER_TAG_OPENED, - OF_XMLPARSER_IN_PROCESSING_INSTRUCTIONS, + OF_XMLPARSER_IN_PROCESSING_INSTRUCTION, OF_XMLPARSER_IN_TAG_NAME, OF_XMLPARSER_IN_CLOSE_TAG_NAME, OF_XMLPARSER_IN_TAG, OF_XMLPARSER_IN_ATTRIBUTE_NAME, OF_XMLPARSER_EXPECT_ATTRIBUTE_EQUAL_SIGN, Index: src/OFXMLParser.m ================================================================== --- src/OFXMLParser.m +++ src/OFXMLParser.m @@ -18,20 +18,21 @@ #define OF_XML_PARSER_M #include #import "OFXMLParser.h" -#import "OFString.h" #import "OFArray.h" -#import "OFDictionary.h" +#import "OFCharacterSet.h" #import "OFData.h" -#import "OFXMLAttribute.h" -#import "OFStream.h" +#import "OFDictionary.h" #ifdef OF_HAVE_FILES # import "OFFile.h" #endif +#import "OFStream.h" +#import "OFString.h" #import "OFSystemInfo.h" +#import "OFXMLAttribute.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" @@ -43,11 +44,11 @@ @end static void inByteOrderMarkState(OFXMLParser *); static void outsideTagState(OFXMLParser *); static void tagOpenedState(OFXMLParser *); -static void inProcessingInstructionsState(OFXMLParser *); +static void inProcessingInstructionState(OFXMLParser *); static void inTagNameState(OFXMLParser *); static void inCloseTagNameState(OFXMLParser *); static void inTagState(OFXMLParser *); static void inAttributeNameState(OFXMLParser *); static void expectAttributeEqualSignState(OFXMLParser *); @@ -65,12 +66,11 @@ typedef void (*state_function_t)(OFXMLParser *); static state_function_t lookupTable[] = { [OF_XMLPARSER_IN_BYTE_ORDER_MARK] = inByteOrderMarkState, [OF_XMLPARSER_OUTSIDE_TAG] = outsideTagState, [OF_XMLPARSER_TAG_OPENED] = tagOpenedState, - [OF_XMLPARSER_IN_PROCESSING_INSTRUCTIONS] = - inProcessingInstructionsState, + [OF_XMLPARSER_IN_PROCESSING_INSTRUCTION] = inProcessingInstructionState, [OF_XMLPARSER_IN_TAG_NAME] = inTagNameState, [OF_XMLPARSER_IN_CLOSE_TAG_NAME] = inCloseTagNameState, [OF_XMLPARSER_IN_TAG] = inTagState, [OF_XMLPARSER_IN_ATTRIBUTE_NAME] = inAttributeNameState, [OF_XMLPARSER_EXPECT_ATTRIBUTE_EQUAL_SIGN] = @@ -350,11 +350,11 @@ @throw [OFMalformedXMLException exceptionWithParser: self]; switch (self->_data[self->_i]) { case '?': self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_IN_PROCESSING_INSTRUCTIONS; + self->_state = OF_XMLPARSER_IN_PROCESSING_INSTRUCTION; self->_level = 0; break; case '/': self->_last = self->_i + 1; self->_state = OF_XMLPARSER_IN_CLOSE_TAG_NAME; @@ -377,11 +377,11 @@ } } /* */ static bool -parseXMLProcessingInstructions(OFXMLParser *self, OFString *pi) +parseXMLProcessingInstruction(OFXMLParser *self, OFString *data) { const char *cString; size_t length, last; int PIState = 0; OFString *attribute = nil; @@ -392,15 +392,12 @@ if (!self->_acceptProlog) return false; self->_acceptProlog = false; - pi = [pi substringFromIndex: 3]; - pi = pi.stringByDeletingEnclosingWhitespaces; - - cString = pi.UTF8String; - length = pi.UTF8StringLength; + cString = data.UTF8String; + length = data.UTF8StringLength; last = 0; for (size_t i = 0; i < length; i++) { switch (PIState) { case 0: @@ -471,35 +468,49 @@ return false; return true; } -/* Inside processing instructions */ +/* Inside processing instruction */ static void -inProcessingInstructionsState(OFXMLParser *self) +inProcessingInstructionState(OFXMLParser *self) { if (self->_data[self->_i] == '?') self->_level = 1; else if (self->_level == 1 && self->_data[self->_i] == '>') { void *pool = objc_autoreleasePoolPush(); - OFString *PI; + OFString *PI, *target, *data = nil; + OFCharacterSet *whitespaceCS; + size_t pos; appendToBuffer(self->_buffer, self->_data + self->_last, self->_encoding, self->_i - self->_last); PI = transformString(self, self->_buffer, 1, false); - if ([PI isEqual: @"xml"] || [PI hasPrefix: @"xml "] || - [PI hasPrefix: @"xml\t"] || [PI hasPrefix: @"xml\r"] || - [PI hasPrefix: @"xml\n"]) - if (!parseXMLProcessingInstructions(self, PI)) + whitespaceCS = [OFCharacterSet + characterSetWithCharactersInString: @" \r\n\r"]; + pos = [PI indexOfCharacterFromSet: whitespaceCS]; + if (pos != OF_NOT_FOUND) { + target = [PI substringToIndex: pos]; + data = [[PI substringFromIndex: pos + 1] + stringByDeletingEnclosingWhitespaces]; + + if (data.length == 0) + data = nil; + } else + target = PI; + + if ([target caseInsensitiveCompare: @"xml"] == OF_ORDERED_SAME) + if (!parseXMLProcessingInstruction(self, data)) @throw [OFMalformedXMLException exceptionWithParser: self]; - if ([self->_delegate respondsToSelector: - @selector(parser:foundProcessingInstructions:)]) + if ([self->_delegate respondsToSelector: @selector( + parser:foundProcessingInstructionWithTarget:data:)]) [self->_delegate parser: self - foundProcessingInstructions: PI]; + foundProcessingInstructionWithTarget: target + data: data]; objc_autoreleasePoolPop(pool); [self->_buffer removeAllItems]; @@ -546,13 +557,11 @@ self->_name = [bufferString copy]; self->_prefix = nil; } if (self->_data[self->_i] == '>' || self->_data[self->_i] == '/') { - OFString *namespace; - - namespace = namespaceForPrefix(self->_prefix, + OFString *namespace = namespaceForPrefix(self->_prefix, self->_namespaces); if (self->_prefix != nil && namespace == nil) @throw [OFUnboundPrefixException exceptionWithPrefix: self->_prefix ADDED src/OFXMLProcessingInstruction.h Index: src/OFXMLProcessingInstruction.h ================================================================== --- src/OFXMLProcessingInstruction.h +++ src/OFXMLProcessingInstruction.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2021 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFXMLNode.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFXMLProcessingInstruction \ + * OFXMLProcessingInstruction.h ObjFW/OFXMLProcessingInstruction.h + * + * @brief A class for representing an XML processing instruction. + */ +@interface OFXMLProcessingInstruction: OFXMLNode +{ + OFString *_target, *_data; + OF_RESERVE_IVARS(OFXMLProcessingInstruction, 4) +} + +/** + * @brief The target of the processing instruction. + */ +@property (readonly, nonatomic) OFString *target; + +/** + * @brief The data of the processing instruction. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *data; + +/** + * @brief Creates a new OFXMLProcessingInstruction with the specified target + * and data. + * + * @param target The target for the processing instruction + * @param data The data for the processing instruction + * @return A new OFXMLProcessingInstruction + */ ++ (instancetype)processingInstructionWithTarget: (OFString *)target + data: (OFString *)data; + +/** + * @brief Initializes an already allocated OFXMLProcessingInstruction with the + * specified target and data. + * + * @param target The target for the processing instruction + * @param data The data for the processing instruction + * @return An initialized OFXMLProcessingInstruction + */ +- (instancetype)initWithTarget: (OFString *)target + data: (OFString *)data OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithSerialization: (OFXMLElement *)element; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFXMLProcessingInstruction.m Index: src/OFXMLProcessingInstruction.m ================================================================== --- src/OFXMLProcessingInstruction.m +++ src/OFXMLProcessingInstruction.m @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2008-2021 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "OFXMLProcessingInstruction.h" +#import "OFString.h" +#import "OFXMLAttribute.h" +#import "OFXMLElement.h" +#import "OFXMLNode+Private.h" + +#import "OFInvalidArgumentException.h" + +@implementation OFXMLProcessingInstruction +@synthesize target = _target, data = _data; + ++ (instancetype)processingInstructionWithTarget: (OFString *)target + data: (OFString *)data +{ + return [[[self alloc] initWithTarget: target + data: data] autorelease]; +} + +- (instancetype)initWithTarget: (OFString *)target + data: (OFString *)data +{ + self = [super of_init]; + + @try { + _target = [target copy]; + _data = [data copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithSerialization: (OFXMLElement *)element +{ + @try { + void *pool = objc_autoreleasePoolPush(); + OFXMLAttribute *targetAttr; + + if (![element.name isEqual: self.className] || + ![element.namespace isEqual: OF_SERIALIZATION_NS]) + @throw [OFInvalidArgumentException exception]; + + targetAttr = [element attributeForName: @"target" + namespace: OF_SERIALIZATION_NS]; + if (targetAttr.stringValue.length == 0) + @throw [OFInvalidArgumentException exception]; + + self = [self initWithTarget: targetAttr.stringValue + data: element.stringValue]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_target release]; + [_data release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFXMLProcessingInstruction *processingInstruction; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFXMLProcessingInstruction class]]) + return false; + + processingInstruction = object; + + if (![processingInstruction->_target isEqual: _target]) + return false; + + if (processingInstruction->_data != _data && + ![processingInstruction->_data isEqual: _data]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OF_HASH_INIT(hash); + OF_HASH_ADD_HASH(hash, _target.hash); + OF_HASH_ADD_HASH(hash, _data.hash); + OF_HASH_FINALIZE(hash); + + return hash; +} + +- (OFString *)stringValue +{ + return @""; +} + +- (OFString *)XMLString +{ + if (_data.length > 0) + return [OFString stringWithFormat: @"", + _target, _data]; + else + return [OFString stringWithFormat: @"", _target]; +} + +- (OFString *)XMLStringWithIndentation: (unsigned int)indentation +{ + return self.XMLString; +} + +- (OFString *)XMLStringWithIndentation: (unsigned int)indentation + level: (unsigned int)level +{ + if (indentation > 0 && level > 0) { + OFString *ret; + char *whitespaces = of_alloc((level * indentation) + 1, 1); + memset(whitespaces, ' ', level * indentation); + whitespaces[level * indentation] = 0; + + @try { + if (_data.length > 0) + ret = [OFString stringWithFormat: + @"%s", whitespaces, + _target, _data]; + else + ret = [OFString stringWithFormat: + @"%s", whitespaces, _target]; + } @finally { + free(whitespaces); + } + + return ret; + } else + return self.XMLString; +} + +- (OFString *)description +{ + return self.XMLString; +} + +- (OFXMLElement *)XMLElementBySerializing +{ + OFXMLElement *ret = [OFXMLElement elementWithName: self.className + namespace: OF_SERIALIZATION_NS + stringValue: _data]; + void *pool = objc_autoreleasePoolPush(); + + [ret addAttribute: [OFXMLAttribute attributeWithName: @"target" + stringValue: _target]]; + + objc_autoreleasePoolPop(pool); + + return ret; +} +@end DELETED src/OFXMLProcessingInstructions.h Index: src/OFXMLProcessingInstructions.h ================================================================== --- src/OFXMLProcessingInstructions.h +++ src/OFXMLProcessingInstructions.h @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2008-2021 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFXMLNode.h" - -OF_ASSUME_NONNULL_BEGIN - -/** - * @class OFXMLProcessingInstructions \ - * OFXMLProcessingInstructions.h ObjFW/OFXMLProcessingInstructions.h - * - * @brief A class for representing XML processing instructions. - */ -@interface OFXMLProcessingInstructions: OFXMLNode -{ - OFString *_processingInstructions; - OF_RESERVE_IVARS(OFXMLProcessingInstructions, 4) -} - -/** - * @brief Creates a new OFXMLProcessingInstructions with the specified string. - * - * @param string The string for the processing instructions - * @return A new OFXMLProcessingInstructions - */ -+ (instancetype)processingInstructionsWithString: (OFString *)string; - -/** - * @brief Initializes an already allocated OFXMLProcessingInstructions with the - * specified string. - * - * @param string The string for the processing instructions - * @return An initialized OFXMLProcessingInstructions - */ -- (instancetype)initWithString: (OFString *)string; - -- (instancetype)initWithSerialization: (OFXMLElement *)element; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFXMLProcessingInstructions.m Index: src/OFXMLProcessingInstructions.m ================================================================== --- src/OFXMLProcessingInstructions.m +++ src/OFXMLProcessingInstructions.m @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2008-2021 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "OFXMLProcessingInstructions.h" -#import "OFXMLNode+Private.h" -#import "OFString.h" -#import "OFXMLElement.h" - -#import "OFInvalidArgumentException.h" - -@implementation OFXMLProcessingInstructions -+ (instancetype)processingInstructionsWithString: (OFString *)string -{ - return [[[self alloc] initWithString: string] autorelease]; -} - -- (instancetype)initWithString: (OFString *)string -{ - self = [super of_init]; - - @try { - _processingInstructions = [string copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [super of_init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) - @throw [OFInvalidArgumentException exception]; - - _processingInstructions = [element.stringValue copy]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_processingInstructions release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFXMLProcessingInstructions *processingInstructions; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFXMLProcessingInstructions class]]) - return false; - - processingInstructions = object; - - return [processingInstructions->_processingInstructions - isEqual: _processingInstructions]; -} - -- (unsigned long)hash -{ - return _processingInstructions.hash; -} - -- (OFString *)stringValue -{ - return @""; -} - -- (OFString *)XMLString -{ - return [OFString stringWithFormat: @"", _processingInstructions]; -} - -- (OFString *)XMLStringWithIndentation: (unsigned int)indentation -{ - return [OFString stringWithFormat: @"", _processingInstructions]; -} - -- (OFString *)XMLStringWithIndentation: (unsigned int)indentation - level: (unsigned int)level -{ - OFString *ret; - - if (indentation > 0 && level > 0) { - char *whitespaces = of_alloc((level * indentation) + 1, 1); - memset(whitespaces, ' ', level * indentation); - whitespaces[level * indentation] = 0; - - @try { - ret = [OFString stringWithFormat: - @"%s", whitespaces, _processingInstructions]; - } @finally { - free(whitespaces); - } - } else - ret = [OFString stringWithFormat: @"", - _processingInstructions]; - - return ret; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"", _processingInstructions]; -} - -- (OFXMLElement *)XMLElementBySerializing -{ - return [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS - stringValue: _processingInstructions]; -} -@end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -114,11 +114,11 @@ #import "OFXMLElement.h" #import "OFXMLAttribute.h" #import "OFXMLCharacters.h" #import "OFXMLCDATA.h" #import "OFXMLComment.h" -#import "OFXMLProcessingInstructions.h" +#import "OFXMLProcessingInstruction.h" #import "OFXMLParser.h" #import "OFXMLElementBuilder.h" #import "OFMessagePackExtension.h" Index: tests/OFXMLParserTests.m ================================================================== --- tests/OFXMLParserTests.m +++ tests/OFXMLParserTests.m @@ -22,11 +22,11 @@ static OFString *module = @"OFXMLParser"; static int i = 0; enum event_type { - PROCESSING_INSTRUCTIONS, + PROCESSING_INSTRUCTION, TAG_OPEN, TAG_CLOSE, STRING, CDATA, COMMENT @@ -46,16 +46,17 @@ i++; msg = [OFString stringWithFormat: @"Parsing part #%d", i]; switch (i) { case 1: - TEST(msg, type == PROCESSING_INSTRUCTIONS && - [string isEqual: @"xml version='1.0'"]) + TEST(msg, type == PROCESSING_INSTRUCTION && + [name isEqual: @"xml"] && + [string isEqual: @"version='1.0'"]) break; case 2: - TEST(msg, type == PROCESSING_INSTRUCTIONS && - [string isEqual: @"p?i"]) + TEST(msg, type == PROCESSING_INSTRUCTION && + [name isEqual: @"p?i"] && string == nil) break; case 3: TEST(msg, type == TAG_OPEN && [name isEqual: @"root"] && prefix == nil && ns == nil && attrs.count == 0) break; @@ -230,20 +231,21 @@ prefix == nil && ns == nil); break; } } -- (void)parser: (OFXMLParser *)parser - foundProcessingInstructions: (OFString *)pi +- (void)parser: (OFXMLParser *)parser + foundProcessingInstructionWithTarget: (OFString *)target + data: (OFString *)data { [self parser: parser - didCreateEvent: PROCESSING_INSTRUCTIONS - name: nil + didCreateEvent: PROCESSING_INSTRUCTION + name: target prefix: nil namespace: nil attributes: nil - string: pi]; + string: data]; } - (void)parser: (OFXMLParser *)parser didStartElement: (OFString *)name prefix: (OFString *)prefix @@ -369,22 +371,22 @@ EXPECT_EXCEPTION(@"Detection of junk after the document #2", OFMalformedXMLException, [parser parseString: @""]) parser = [OFXMLParser parser]; - EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #2", + EXPECT_EXCEPTION(@"Detection of invalid XML processing instruction #2", OFInvalidEncodingException, [parser parseString: @""]) parser = [OFXMLParser parser]; - EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #3", + EXPECT_EXCEPTION(@"Detection of invalid XML processing instruction #3", OFMalformedXMLException, [parser parseString: @""]) objc_autoreleasePoolPop(pool); } @end