Index: ChangeLog ================================================================== --- ChangeLog +++ ChangeLog @@ -1,9 +1,29 @@ Legend: * Changes of existing features or bugfixes. + New features. +ObjFW 0.4-alpha1 -> ObjFW 0.5, 09.04.2011 + + %@ is now allowed in format strings. + + Added of_log for easy logging. + * Exceptions have one header per exception now. + * Lots of exception improvements. + * Huge improvements in XML handling. + * Improvements in socket handling, including improved API. + * OFStreamObserver is now thread-safe and stops the current observe call when + the set of streams to observe is modified. + + New class OFURL. + + New class OFHTTPRequest. + + New class OFCondition. + * Improvements in objfw-compile. + + Blocks can be used together with Cocoa now. + + When linking ObjFW and Cocoa, OFAutoreleasePools are used by both now. + + Support for Base64. + + Use a real Xcode project instead of just calling make. + + Add Haiku to the list of supported platforms. + * Lots of small bugfixes and countless small changes. Read the commits! + ObjFW 0.3.1 -> 0.4-alpha1, 03.01.2011 * ObjFW is now available under the terms of the QPL, GPLv2 and GPLv3. + Support for blocks was added, including a blocks runtime. + Added support for the new GNU runtime, introduced in GCC 4.6. * Objects returned from collections are no longer retained and autoreleased. Index: Info.plist ================================================================== --- Info.plist +++ Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType FMWK CFBundleSignature OBJFW CFBundleVersion - 0.4-dev + 0.6-dev CFBundleShortVersionString - 0.4-dev + 0.6-dev Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -1,6 +1,6 @@ -AC_INIT(ObjFW, 0.4-dev, js@webkeks.org) +AC_INIT(ObjFW, 0.6-dev, js@webkeks.org) AC_CONFIG_SRCDIR(src) AS_IF([test x"$host" = x"psp"], [ OBJCFLAGS="-G0 $OBJCFLAGS" LIBS="$LIBS -lpspdebug -lpspdisplay -lpspge -lpspctrl -lpspsdk -lc" Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -1,8 +1,8 @@ OBJFW_SHARED_LIB = @OBJFW_SHARED_LIB@ OBJFW_STATIC_LIB = @OBJFW_STATIC_LIB@ -OBJFW_LIB_MAJOR = 3 +OBJFW_LIB_MAJOR = 4 OBJFW_LIB_MINOR = 0 OBJFW_LIB_MAJOR_MINOR = ${OBJFW_LIB_MAJOR}.${OBJFW_LIB_MINOR} ASPRINTF_M = @ASPRINTF_M@ ATOMIC_H = @ATOMIC_H@ Index: src/OFXMLParser.h ================================================================== --- src/OFXMLParser.h +++ src/OFXMLParser.h @@ -177,10 +177,11 @@ of_xml_parser_string_block_t CDATAHandler; of_xml_parser_string_block_t commentHandler; of_xml_parser_unknown_entity_block_t unknownEntityHandler; #endif size_t level; + BOOL acceptProlog; size_t lineNumber; BOOL lastCarriageReturn; BOOL finishedParsing; } Index: src/OFXMLParser.m ================================================================== --- src/OFXMLParser.m +++ src/OFXMLParser.m @@ -49,11 +49,11 @@ [cache replaceOccurrencesOfString: @"\r" withString: @"\n"]; return [cache stringByXMLUnescapingWithDelegate: delegate]; } -static OF_INLINE OFString* +static OFString* namespace_for_prefix(OFString *prefix, OFArray *namespaces) { OFDictionary **carray = [namespaces cArray]; ssize_t i; @@ -155,10 +155,11 @@ dict = [OFMutableDictionary dictionaryWithKeysAndObjects: @"xml", @"http://www.w3.org/XML/1998/namespace", @"xmlns", @"http://www.w3.org/2000/xmlns/", nil]; [namespaces addObject: dict]; + acceptProlog = YES; lineNumber = 1; [pool release]; } @catch (id e) { [self release]; @@ -265,11 +266,11 @@ } } /* * The following methods handle the different states of the parser. They are - * lookup up in +[initialize] and put in a lookup table to speed things up. + * looked up in +[initialize] and put in a lookup table to speed things up. * One dispatch for every character would be way too slow! */ /* Not in a tag */ - (void)_parseOutsideTagWithBuffer: (const char*)buf @@ -276,12 +277,13 @@ i: (size_t*)i last: (size_t*)last { size_t len; - if (finishedParsing && buf[*i] != ' ' && buf[*i] != '\t' && - buf[*i] != '\n' && buf[*i] != '\r' && buf[*i] != '<') + if ((finishedParsing || [previous count] < 1) && buf[*i] != ' ' && + buf[*i] != '\t' && buf[*i] != '\n' && buf[*i] != '\r' && + buf[*i] != '<') @throw [OFMalformedXMLException newWithClass: isa parser: self]; if (buf[*i] != '<') return; @@ -317,11 +319,11 @@ /* Tag was just opened */ - (void)_parseTagOpenedWithBuffer: (const char*)buf i: (size_t*)i last: (size_t*)last { - if (finishedParsing && buf[*i] != '!') + if (finishedParsing && buf[*i] != '!' && buf[*i] != '?') @throw [OFMalformedXMLException newWithClass: isa parser: self]; switch (buf[*i]) { case '?': @@ -330,23 +332,108 @@ level = 0; break; case '/': *last = *i + 1; state = OF_XMLPARSER_IN_CLOSE_TAG_NAME; + acceptProlog = NO; break; case '!': *last = *i + 1; state = OF_XMLPARSER_IN_EXCLAMATIONMARK; + acceptProlog = NO; break; default: state = OF_XMLPARSER_IN_TAG_NAME; + acceptProlog = NO; (*i)--; break; } } -/* Inside prolog */ +/* */ +- (BOOL)_parseXMLProcessingInstructions: (OFString*)pi +{ + const char *pi_c; + size_t i, last, pi_len; + int xstate = 0; + OFString *attr = nil; + OFString *val = nil; + char xdelim = 0; + + if (!acceptProlog) + return NO; + + acceptProlog = NO; + + pi = [pi substringFromIndex: 3 + toIndex: [pi length]]; + pi = [pi stringByDeletingLeadingAndTrailingWhitespaces]; + + pi_c = [pi cString]; + pi_len = [pi cStringLength]; + + for (i = last = 0; i < pi_len; i++) { + switch (xstate) { + case 0: + if (pi_c[i] == ' ' || pi_c[i] == '\t' || + pi_c[i] == '\r' || pi_c[i] == '\n') + continue; + + last = i; + xstate = 1; + i--; + + break; + case 1: + if (pi_c[i] != '=') + continue; + + attr = [OFString stringWithCString: pi_c + last + length: i - last]; + last = i + 1; + xstate = 2; + + break; + case 2: + if (pi_c[i] != '\'' && pi_c[i] != '"') + return NO; + + xdelim = pi_c[i]; + last = i + 1; + xstate = 3; + + break; + case 3: + if (pi_c[i] != xdelim) + continue; + + val = [OFString stringWithCString: pi_c + last + length: i - last]; + + if ([attr isEqual: @"version"]) + if (![val hasPrefix: @"1."]) + return NO; + + if ([attr isEqual: @"encoding"]) + if ([val caseInsensitiveCompare: @"utf-8"] != + OF_ORDERED_SAME) + return NO; + + last = i + 1; + xstate = 0; + + break; + } + } + + if (xstate != 0) + return NO; + + return YES; +} + +/* Inside processing instructions */ - (void)_parseInProcessingInstructionsWithBuffer: (const char*)buf i: (size_t*)i last: (size_t*)last { if (buf[*i] == '?') @@ -368,10 +455,18 @@ * Class swizzle the string to be immutable. We pass it as * OFString*, so it can't be modified anyway. But not swizzling * it would create a real copy each time -[copy] is called. */ pi->isa = [OFString class]; + + if ([pi isEqual: @"xml"] || [pi hasPrefix: @"xml "] || + [pi hasPrefix: @"xml\t"] || [pi hasPrefix: @"xml\r"] || + [pi hasPrefix: @"xml\n"]) + if (![self _parseXMLProcessingInstructions: pi]) + @throw [OFMalformedXMLException + newWithClass: isa + parser: self]; [delegate parser: self foundProcessingInstructions: pi]; [pool release]; Index: tests/OFXMLParserTests.m ================================================================== --- tests/OFXMLParserTests.m +++ tests/OFXMLParserTests.m @@ -374,8 +374,23 @@ OFMalformedXMLException, [parser parseString: @"a"]) EXPECT_EXCEPTION(@"Detection of junk after the document #2", OFMalformedXMLException, [parser parseString: @""]) + + parser = [OFXMLParser parser]; + EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #2", + OFMalformedXMLException, + [parser parseString: @""]) + + parser = [OFXMLParser parser]; + EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #3", + OFMalformedXMLException, + [parser parseString: @""]) + [pool drain]; } @end Index: utils/objfw-config.in ================================================================== --- utils/objfw-config.in +++ utils/objfw-config.in @@ -35,11 +35,11 @@ LIBS="-L${libdir} -lobjfw @LIBS@" PLUGIN_CFLAGS="@PLUGIN_CFLAGS@" PLUGIN_LDFLAGS="@PLUGIN_LDFLAGS@" PLUGIN_SUFFIX="@PLUGIN_SUFFIX@" PROG_SUFFIX="@EXEEXT@" -VERSION="0.4-dev" +VERSION="0.6-dev" show_help() { cat <<__EOF__ objfw-config: Available arguments are: