Index: ChangeLog ================================================================== --- ChangeLog +++ ChangeLog @@ -1,9 +1,59 @@ Legend: * Changes of existing features or bugfixes. + New features. +ObjFW 0.3 -> 0.3.1, 19.06.2010 + * Fix a typo in OFMutableDictionary that prevented termination in case + the last bucket is already used when the dictionary is resized. + * The mutations pointer is now correctly initialized in enumerators for + immutable collections. + * The objc_sync test was still using the old threads API and was + updated to use the new one now. + * PLATFORMS has been updated to be more specific. + +ObjFW 0.2.1 -> 0.3, 09.05.2010 + + Many new methods were added to different classes. + + A huge amount of methods was added to OFStream, allowing easy binary + stream handling and even mixing string-based and binary operations. + + An optional write buffer was added to OFStream. + + OFSeekableStream was added for streams that allow seeking, for example + OFFiles. + * OFNumber was completely reworked and got many new features now. + * Large parts of OFDictionary were rewritten for better readability, better + memory usage and to fix a bug with removing objects. + * OFThread has been greatly improved. + * Many small optimizations. + * Many documentation improvements. + * Method replacing was reworked and the methods renamed. + + Tests for OFStream were added. + * A bug with building ObjFW as a Universal Binary Framework was fixed. + + Support for ObjFW-RT, the ObjFW Objective C runtime, was added. + * Sockets are now properly closed before an exception is thrown. + * Error handling with sockets was improved. + * OFFile now uses open(), read() and write(), thus allowing -[readLine] to be + used on of_stdin and fixing many other annoyances. + * A few misc methods were renamed. + + OFApplication was added. + * All tests and the table generator are now using OFApplication. + + It is now possible to get the remote address of an OFTCPSocket. + + OFString can now build paths in the OS-native format. + + It is now possible to create a string with the contents of a file. + + Many new file operations were added to OFFile. + * The existing file operations in OFFile were improved. + * Almost all functions that returned self before now return void. + + OFHash was added as a superclass for OFMD5Hash and OFSHA1Hash and OFHashes + renamed to OFHash. + + objfw-compile was added for easy compilation of ObjFW projects, which + includes dependency checking for headers etc. + * The instance variable naming convention was changed so that properties work. + + Properties were added to the interfaces and are used if they are supported + by the compiler. + + The library version is now included in the resulting dylib and libobjc is + reexported now. Additionally, objfw-config offers --reexport now to produce + libraries that link against ObjFW and reexport it. + ObjFW 0.2 -> 0.2.1, 14.03.2010 * Fix for OFNumbers not doing calculations. * Improved -[hash] for OFNumbers with floats and doubles. + Tests for OFNumber. * Small optimization for OFArray's -[componentsJoinedByString:]. Index: Info.plist ================================================================== --- Info.plist +++ Info.plist @@ -4,23 +4,21 @@ CFBundleDevelopmentRegion English CFBundleExecutable ObjFW - CFBundleGetInfoString - https://webkeks.org/objfw + CFBundleName + ObjFW CFBundleIdentifier - ObjFW + org.webkeks.objfw CFBundleInfoDictionaryVersion 6.0 - CFBundleName - objfw CFBundlePackageType FMWK - CFBundleShortVersionString - 0.3-dev CFBundleSignature - OBJF + OBJFW CFBundleVersion - 0.3-dev + 0.3 + CFBundleShortVersionString + 0.3 Index: PLATFORMS ================================================================== --- PLATFORMS +++ PLATFORMS @@ -1,33 +1,34 @@ ObjFW is known to work on the following platforms, but should run on many others as well: - +-------------------------+--------------+----------------------+ - | OS | Architecture | Compiler | - +-------------------------+--------------+----------------------+ - | FreeBSD >= 8.0 | x86 | | - +-------------------------+--------------+----------------------+ - | Linux | x86 | gcc 4.4.1 | - | Linux | x86 | llvm/clang r83252 | - | Linux | x86_64 | gcc 4.4.1 | - +-------------------------+--------------+----------------------+ - | iPhone OS >= 2.2.1 | arm | gcc 4.2 | - | Mac OS X >= 10.5 | ppc | gcc 4.0 + 4.2 | - | Mac OS X >= 10.5 | ppc64 | gcc 4.0 + 4.2 | - | Mac OS X >= 10.5 | x86 | gcc 4.0 + 4.2 | - | Mac OS X >= 10.5 | x86_64 | gcc 4.0 + 4.2 | - +-------------------------+--------------+----------------------+ - | MirBSD >= 10uAB | x86 | gcc 4.4.2 | - +-------------------------+--------------+----------------------+ - | NetBSD >= 4.0 | x86 | gcc 4.1.2 prerelease | - +-------------------------+--------------+----------------------+ - | OpenBSD >= 4.6 | x86_64 | gcc 4.2.4 | - +-------------------------+--------------+----------------------+ - | OpenSolaris >= 2009.06 | x86 | | - | OpenSolaris >= 2009.06 | x86_64 | | - +-------------------------+--------------+----------------------+ - | Windows >= XP / cygwin | x86 | | - | Windows >= XP / mingw32 | x86 | | - +-------------------------+--------------+----------------------+ - -Basically, it should run on any POSIX system to which gcc4 has been -ported. If not, please send a bug report. + +--------------------------+--------------+----------------------+---------+ + | OS | Architecture | Compiler | Runtime | + +--------------------------+--------------+----------------------+---------+ + | FreeBSD 8.0 | x86 | | GNU | + +--------------------------+--------------+----------------------+---------+ + | Linux 2.6.* | x86 | gcc 4.4.1 | GNU | + | Linux 2.6.* | x86 | llvm/clang r83252 | GNU | + | Linux 2.6.* | x86_64 | gcc 4.4.1 | GNU | + +--------------------------+--------------+----------------------+---------+ + | iPhone OS 2.2.1 - 3.1.2 | arm | gcc 4.2 | Apple | + | Mac OS X 10.5 | ppc | gcc 4.0 + 4.2 | Apple | + | Mac OS X 10.5 | ppc64 | gcc 4.0 + 4.2 | Apple | + | Mac OS X 10.5 - 10.6 | x86 | gcc 4.0 + 4.2 | Apple | + | Mac OS X 10.5 - 10.6 | x86_64 | gcc 4.0 + 4.2 | Apple | + +--------------------------+--------------+----------------------+---------+ + | MirBSD 10uAB | x86 | gcc 4.4.2 | GNU | + +--------------------------+--------------+----------------------+---------+ + | NetBSD 4.0 | x86 | gcc 4.1.2 prerelease | GNU | + +--------------------------+--------------+----------------------+---------+ + | OpenBSD 4.6 | x86_64 | gcc 4.2.4 | GNU | + +--------------------------+--------------+----------------------+---------+ + | OpenSolaris 2009.06 | x86 | | GNU | + | OpenSolaris 2009.06 | x86_64 | | GNU | + +--------------------------+--------------+----------------------+---------+ + | Windows XP - 7 / cygwin | x86 | | GNU | + | Windows XP - 7 / mingw32 | x86 | | GNU | + +--------------------------+--------------+----------------------+---------+ + +Basically, it should run on any POSIX system to which gcc4 or a recent +clang version has been ported. If not, please send an e-mail with a bug +report. Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -1,6 +1,6 @@ -AC_INIT(ObjFW, 0.3-dev, js@webkeks.org) +AC_INIT(ObjFW, 0.3, js@webkeks.org) AC_CONFIG_SRCDIR(src) AC_CANONICAL_HOST AC_LANG([Objective C]) @@ -121,10 +121,17 @@ AC_SUBST(OFPLUGINTESTS_M, "OFPluginTests.m") AC_SUBST(TESTPLUGIN, "plugin") AC_DEFINE(OF_PLUGINS, 1, [Whether we have plugin support]) AC_SUBST(OFPLUGINS_DEF, "-DOF_PLUGINS") fi + +case "$host_os" in + darwin*) + AC_SUBST(REEXPORT_LIBOBJC, [-Wl,-reexport-lobjc]) + AC_SUBST(LDFLAGS_REEXPORT, [-Wl,-reexport-lobjfw]) + ;; +esac AC_C_BIGENDIAN([ AC_DEFINE(OF_BIG_ENDIAN, 1, [Whether we are big endian]) AC_SUBST(ENDIANESS_DEF, "-DOF_BIG_ENDIAN")]) @@ -406,12 +413,5 @@ AC_SUBST(PACKAGE, ObjFW) AC_CONFIG_FILES([buildsys.mk extra.mk utils/objfw-config]) AC_CONFIG_HEADERS([config.h src/objfw-defs.h]) AC_OUTPUT - -if test x"$objc_runtime" = x"GNU"; then - echo - echo "Warning: You are using GNU libobjc! Support for GNU libobjc will " - echo "be dropped in the next version! You should upgrade to ObjFW-RT" - echo "(the ObjFW runtime) instead!" -fi Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -9,9 +9,10 @@ OFPLUGIN_M = @OFPLUGIN_M@ OFPLUGINTESTS_M = @OFPLUGINTESTS_M@ OFTHREAD_M = @OFTHREAD_M@ OFTHREADTESTS_M = @OFTHREADTESTS_M@ PROPERTIESTESTS_M = @PROPERTIESTESTS_M@ +REEXPORT_LIBOBJC = @REEXPORT_LIBOBJC@ TESTPLUGIN = @TESTPLUGIN@ TESTS = @TESTS@ TEST_LAUNCHER = @TEST_LAUNCHER@ THREADING_H = @THREADING_H@ Index: m4/buildsys.m4 ================================================================== --- m4/buildsys.m4 +++ m4/buildsys.m4 @@ -55,17 +55,17 @@ case "$host_os" in darwin*) AC_MSG_RESULT(Darwin) LIB_CPPFLAGS='-DPIC' LIB_CFLAGS='-fPIC' - LIB_LDFLAGS='-dynamiclib -flat_namespace' + LIB_LDFLAGS='-dynamiclib -current_version ${LIB_MAJOR}.${LIB_MINOR} -compatibility_version ${LIB_MAJOR}' LIB_PREFIX='lib' LIB_SUFFIX='.dylib' LDFLAGS_RPATH='-Wl,-rpath,${libdir}' PLUGIN_CPPFLAGS='-DPIC' PLUGIN_CFLAGS='-fPIC' - PLUGIN_LDFLAGS='-bundle -flat_namespace -undefined suppress' + PLUGIN_LDFLAGS='-bundle -undefined dynamic_lookup' PLUGIN_SUFFIX='.impl' INSTALL_LIB='${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib && ${LN_S} -f $${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.dylib && ${LN_S} -f $${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib ${DESTDIR}${libdir}/$$i' UNINSTALL_LIB='rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.dylib ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib' CLEAN_LIB='' ;; Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -10,11 +10,11 @@ OFConstString.m \ OFDataArray.m \ OFDictionary.m \ OFExceptions.m \ OFFile.m \ - OFHashes.m \ + OFHash.m \ OFEnumerator.m \ OFList.m \ OFMutableArray.m \ OFMutableDictionary.m \ OFMutableString.m \ @@ -49,5 +49,6 @@ include ../buildsys.mk CPPFLAGS += -I.. ${LIB_CPPFLAGS} OBJCFLAGS += ${LIB_CFLAGS} LD = ${OBJC} +LDFLAGS += ${REEXPORT_LIBOBJC} Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -372,11 +372,11 @@ { self = [super init]; array = array_; count = [array_ count]; - mutations = *mutationsPtr_; + mutations = (mutationsPtr_ != NULL ? *mutationsPtr_ : 0); mutationsPtr = mutationsPtr_; return self; } Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -688,11 +688,11 @@ { self = [super init]; data = data_; size = size_; - mutations = *mutationsPtr_; + mutations = (mutationsPtr_ != NULL ? *mutationsPtr_ : 0); mutationsPtr = mutationsPtr_; return self; } Index: src/OFExceptions.m ================================================================== --- src/OFExceptions.m +++ src/OFExceptions.m @@ -84,11 +84,11 @@ - initWithClass: (Class)class_ { self = [super init]; - class_ = class_; + inClass = class_; return self; } - (void)dealloc @@ -1257,11 +1257,11 @@ if (string != nil) return string; string = [[OFString alloc] initWithFormat: @"A connection to service %s on node %s could not be established " - @"in class %s! " ERRFMT, [node cString], [service cString], + @"in class %s! " ERRFMT, [service cString], [node cString], [inClass className], ERRPARAM]; return string; } Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -39,10 +39,16 @@ # define S_IRGRP 0 #endif #ifndef S_IROTH # define S_IROTH 0 #endif +#ifndef S_IWGRP +# define S_IWGRP 0 +#endif +#ifndef S_IWOTH +# define S_IWOTH 0 +#endif #define DEFAULT_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH #define DIR_MODE DEFAULT_MODE | S_IXUSR | S_IXGRP | S_IXOTH OFFile *of_stdin = nil; @@ -114,15 +120,23 @@ ssize_t i; if (path_len == 0) return @""; +#ifndef _WIN32 if (path_c[path_len - 1] == OF_PATH_DELIM) +#else + if (path_c[path_len - 1] == '/' || path_c[path_len - 1] == '\\') +#endif path_len--; for (i = path_len - 1; i >= 0; i--) { +#ifndef _WIN32 if (path_c[i] == OF_PATH_DELIM) { +#else + if (path_c[i] == '/' || path_c[i] == '\\') { +#endif i++; break; } } @@ -316,16 +330,18 @@ intoBuffer: buf]; [dest writeNBytes: len fromBuffer: buf]; } +#ifndef _WIN32 if (!override) { struct stat s; if (fstat(src->fd, &s) == 0) fchmod(dest->fd, s.st_mode); } +#endif } @finally { [src close]; [dest close]; } ADDED src/OFHash.h Index: src/OFHash.h ================================================================== --- src/OFHash.h +++ src/OFHash.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2008 - 2010 + * 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 included in + * the packaging of this file. + */ + +#import "OFObject.h" +#import "OFString.h" + +#define OF_MD5_DIGEST_SIZE 16 +#define OF_SHA1_DIGEST_SIZE 20 + +extern int _OFHashing_reference; + +/** + * \brief A base class for classes providing hash functions. + */ +@interface OFHash: OFObject +{ + BOOL calculated; +} + +#ifdef OF_HAVE_PROPERTIES +@property (readonly) BOOL calculated; +#endif + +/** + * Adds a buffer to the hash to be calculated. + * + * \param buf The buffer which should be included into the calculation. + * \param size The size of the buffer + */ +- (void)updateWithBuffer: (const char*)buf + ofSize: (size_t)size; + +/** + * \return A buffer containing the hash. The size of the buffer is depending + * on the hash used. The buffer is part of object's memory pool. + */ +- (uint8_t*)digest; + +/** + * \return A boolean whether the hash has already been calculated + */ +- (BOOL)calculated; +@end + +/** + * \brief A class which provides functions to create an MD5 hash. + */ +@interface OFMD5Hash: OFHash +{ + uint32_t buf[4]; + uint32_t bits[2]; + uint8_t in[64]; +} + +/** + * \return A new autoreleased MD5 Hash + */ ++ md5Hash; +@end + +/** + * \brief A class which provides functions to create an SHA1 hash. + */ +@interface OFSHA1Hash: OFHash +{ + uint32_t state[5]; + uint64_t count; + char buffer[64]; + uint8_t digest[OF_SHA1_DIGEST_SIZE]; +} + +/** + * \return A new autoreleased SHA1 Hash + */ ++ sha1Hash; +@end + +/** + * The OFString (OFHashing) category provides methods to calculate hashes for + * strings. + */ +@interface OFString (OFHashing) +/** + * \return The MD5 hash of the string as an autoreleased OFString + */ +- (OFString*)md5Hash; + +/** + * \return The SHA1 hash of the string as an autoreleased OFString + */ +- (OFString*)sha1Hash; +@end ADDED src/OFHash.m Index: src/OFHash.m ================================================================== --- src/OFHash.m +++ src/OFHash.m @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2008 - 2010 + * 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 included in + * the packaging of this file. + */ + +#include "config.h" + +#include + +#import "OFHash.h" +#import "OFAutoreleasePool.h" +#import "OFExceptions.h" +#import "macros.h" + +int _OFHashing_reference; + +@implementation OFHash +- (void)updateWithBuffer: (const char*)buffer + ofSize: (size_t)size +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- (uint8_t*)digest +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- (BOOL)calculated +{ + return calculated; +} +@end + +/* + * MD5 + */ + +/* The four MD5 core functions - F1 is optimized somewhat */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) + +static inline void +md5_transform(uint32_t buf[4], const uint32_t in[16]) +{ + register uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xD76AA478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xE8C7B756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070DB, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xC1BDCEEE, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xF57C0FAF, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787C62A, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xA8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xFD469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098D8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8B44F7AF, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xFFFF5BB1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895CD7Be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6B901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xFD987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xA679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49B40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xF61E2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xC040B340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265E5A51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xE9B6C7AA, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xD62F105D, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xD8A1E681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xE7D3FBC8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21E1CDE6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xC33707D6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xF4D50D87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455A14ED, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xA9E3E905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xFCEFA3F8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676F02D9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8D2A4C8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xFFFA3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771F681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6D9D6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xFDE5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xA4BEEA44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4BDECFA9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xF6BB4B60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xBEBFBC70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289B7EC6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xEAA127FA, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xD4EF3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881D05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xD9D4D039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xE6DB99E5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1FA27CF8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xC4AC5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xF4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432AFF97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xAB9423A7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xFC93A039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655B59C3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8F0CCC92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xFFEFF47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845DD1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6FA87E4F, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xFE2CE6E0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xA3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4E0811A1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xF7537E82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xBD3AF235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2AD7D2BB, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xEB86D391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +@implementation OFMD5Hash ++ md5Hash +{ + return [[[self alloc] init] autorelease]; +} + +- init +{ + self = [super init]; + + buf[0] = 0x67452301; + buf[1] = 0xEFCDAB89; + buf[2] = 0x98BADCFE; + buf[3] = 0x10325476; + + return self; +} + +- (void)updateWithBuffer: (const char*)buffer + ofSize: (size_t)size +{ + uint32_t t; + + if (size == 0) + return; + + if (calculated) + @throw [OFHashAlreadyCalculatedException newWithClass: isa]; + + /* Update bitcount */ + t = bits[0]; + if ((bits[0] = t + ((uint32_t)size << 3)) < t) + /* Carry from low to high */ + bits[1]++; + bits[1] += size >> 29; + + /* Bytes already in shsInfo->data */ + t = (t >> 3) & 0x3F; + + /* Handle any leading odd-sized chunks */ + if (t) { + uint8_t *p = in + t; + + t = 64 - t; + + if (size < t) { + memcpy(p, buffer, size); + return; + } + + memcpy(p, buffer, t); + OF_BSWAP32_V_IF_BE((uint32_t*)in, 16); + md5_transform(buf, (uint32_t*)in); + + buffer += t; + size -= t; + } + + /* Process data in 64-byte chunks */ + while (size >= 64) { + memcpy(in, buffer, 64); + OF_BSWAP32_V_IF_BE((uint32_t*)in, 16); + md5_transform(buf, (uint32_t*)in); + + buffer += 64; + size -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(in, buffer, size); +} + +- (uint8_t*)digest +{ + uint8_t *p; + size_t count; + + if (calculated) + return (uint8_t*)buf; + + /* Compute number of bytes mod 64 */ + count = (bits[0] >> 3) & 0x3F; + + /* + * Set the first char of padding to 0x80. This is safe since there is + * always at least one byte free + */ + p = in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + OF_BSWAP32_V_IF_BE((uint32_t*)in, 16); + md5_transform(buf, (uint32_t*)in); + + /* Now fill the next block with 56 bytes */ + memset(in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + OF_BSWAP32_V_IF_BE((uint32_t*)in, 14); + + /* Append length in bits and transform */ + ((uint32_t*)in)[14] = bits[0]; + ((uint32_t*)in)[15] = bits[1]; + + md5_transform(buf, (uint32_t*)in); + OF_BSWAP32_V_IF_BE(buf, 4); + + calculated = YES; + + return (uint8_t*)buf; +} +@end + +#undef F1 +#undef F2 +#undef F3 +#undef F4 +#undef MD5STEP + +/* + * SHA1 + */ + +/* blk0() and blk() perform the initial expand. */ +#ifndef OF_BIG_ENDIAN +#define blk0(i) \ + (block->l[i] = (OF_ROL(block->l[i], 24) & 0xFF00FF00) | \ + (OF_ROL(block->l[i], 8) & 0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) \ + (block->l[i & 15] = OF_ROL(block->l[(i + 13) & 15] ^ \ + block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ \ + block->l[i & 15], 1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + OF_ROL(v, 5); \ + w = OF_ROL(w, 30); +#define R1(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + OF_ROL(v, 5); \ + w = OF_ROL(w, 30); +#define R2(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + OF_ROL(v, 5); \ + w = OF_ROL(w, 30); +#define R3(v, w, x, y, z, i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + OF_ROL(v, 5); \ + w = OF_ROL(w, 30); +#define R4(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + OF_ROL(v, 5); \ + w = OF_ROL(w, 30); + +/// \cond internal +typedef union { + char c[64]; + uint32_t l[16]; +} sha1_c64l16_t; +/// \endcond + +static inline void +sha1_transform(uint32_t state[5], const char buffer[64]) +{ + uint32_t a, b, c, d, e; + char workspace[64]; + sha1_c64l16_t *block; + + block = (sha1_c64l16_t*)workspace; + memcpy(block, buffer, 64); + + /* Copy state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working vars back into state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; +} + +static inline void +sha1_update(uint32_t *state, uint64_t *count, char *buffer, + const char *buf, size_t size) +{ + size_t i, j; + + j = (size_t)((*count >> 3) & 63); + *count += (size << 3); + + if ((j + size) > 63) { + memcpy(&buffer[j], buf, (i = 64 - j)); + + sha1_transform(state, buffer); + + for (; i + 63 < size; i += 64) + sha1_transform(state, &buf[i]); + + j = 0; + } else + i = 0; + + memcpy(&buffer[j], &buf[i], size - i); +} + +@implementation OFSHA1Hash ++ sha1Hash +{ + return [[[self alloc] init] autorelease]; +} + +- init +{ + self = [super init]; + + state[0] = 0x67452301; + state[1] = 0xEFCDAB89; + state[2] = 0x98BADCFE; + state[3] = 0x10325476; + state[4] = 0xC3D2E1F0; + + return self; +} + +- (void)updateWithBuffer: (const char*)buf + ofSize: (size_t)size +{ + if (size == 0) + return; + + if (calculated) + @throw [OFHashAlreadyCalculatedException newWithClass: isa]; + + sha1_update(state, &count, buffer, buf, size); +} + +- (uint8_t*)digest +{ + size_t i; + char finalcount[8]; + + if (calculated) + return digest; + + for (i = 0; i < 8; i++) + /* Endian independent */ + finalcount[i] = (char)((count >> ((7 - (i & 7)) * 8)) & 255); + sha1_update(state, &count, buffer, "\200", 1); + + while ((count & 504) != 448) + sha1_update(state, &count, buffer, "\0", 1); + /* Should cause a sha1_transform() */ + sha1_update(state, &count, buffer, finalcount, 8); + + for (i = 0; i < OF_SHA1_DIGEST_SIZE; i++) + digest[i] = (char)((state[i >> 2] >> + ((3 - (i & 3)) * 8)) & 255); + + calculated = YES; + + return digest; +} +@end + +#undef blk0 +#undef blk +#undef R0 +#undef R1 +#undef R2 +#undef R3 +#undef R4 + +@implementation OFString (OFHashing) +- (OFString*)md5Hash +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFMD5Hash *hash = [OFMD5Hash md5Hash]; + uint8_t *digest; + char ret_c[32]; + size_t i; + + [hash updateWithBuffer: string + ofSize: length]; + digest = [hash digest]; + + for (i = 0; i < 16; i++) { + uint8_t high, low; + + high = digest[i] >> 4; + low = digest[i] & 0x0F; + + ret_c[i * 2] = (high > 9 ? high - 10 + 'a' : high + '0'); + ret_c[i * 2 + 1] = (low > 9 ? low - 10 + 'a' : low + '0'); + } + + [pool release]; + + return [OFString stringWithCString: ret_c + length: 32]; +} + +- (OFString*)sha1Hash +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFMD5Hash *hash = [OFSHA1Hash sha1Hash]; + uint8_t *digest; + char ret_c[40]; + size_t i; + + [hash updateWithBuffer: string + ofSize: length]; + digest = [hash digest]; + + for (i = 0; i < 20; i++) { + uint8_t high, low; + + high = digest[i] >> 4; + low = digest[i] & 0x0F; + + ret_c[i * 2] = (high > 9 ? high - 10 + 'a' : high + '0'); + ret_c[i * 2 + 1] = (low > 9 ? low - 10 + 'a' : low + '0'); + } + + [pool release]; + + return [OFString stringWithCString: ret_c + length: 40]; +} +@end DELETED src/OFHashes.h Index: src/OFHashes.h ================================================================== --- src/OFHashes.h +++ src/OFHashes.h @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2008 - 2010 - * 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 included in - * the packaging of this file. - */ - -#import "OFObject.h" -#import "OFString.h" - -#define OF_MD5_DIGEST_SIZE 16 -#define OF_SHA1_DIGEST_SIZE 20 - -extern int _OFHashing_reference; - -/** - * \brief A base class for classes providing hash functions. - */ -@interface OFHash: OFObject -{ - BOOL calculated; -} - -#ifdef OF_HAVE_PROPERTIES -@property (readonly) BOOL calculated; -#endif - -/** - * Adds a buffer to the hash to be calculated. - * - * \param buf The buffer which should be included into the calculation. - * \param size The size of the buffer - */ -- (void)updateWithBuffer: (const char*)buf - ofSize: (size_t)size; - -/** - * \return A buffer containing the hash. The size of the buffer is depending - * on the hash used. The buffer is part of object's memory pool. - */ -- (uint8_t*)digest; - -/** - * \return A boolean whether the hash has already been calculated - */ -- (BOOL)calculated; -@end - -/** - * \brief A class which provides functions to create an MD5 hash. - */ -@interface OFMD5Hash: OFHash -{ - uint32_t buf[4]; - uint32_t bits[2]; - uint8_t in[64]; -} - -/** - * \return A new autoreleased MD5 Hash - */ -+ md5Hash; -@end - -/** - * \brief A class which provides functions to create an SHA1 hash. - */ -@interface OFSHA1Hash: OFHash -{ - uint32_t state[5]; - uint64_t count; - char buffer[64]; - uint8_t digest[OF_SHA1_DIGEST_SIZE]; -} - -/** - * \return A new autoreleased SHA1 Hash - */ -+ sha1Hash; -@end - -/** - * The OFString (OFHashing) category provides methods to calculate hashes for - * strings. - */ -@interface OFString (OFHashing) -/** - * \return The MD5 hash of the string as an autoreleased OFString - */ -- (OFString*)md5Hash; - -/** - * \return The SHA1 hash of the string as an autoreleased OFString - */ -- (OFString*)sha1Hash; -@end DELETED src/OFHashes.m Index: src/OFHashes.m ================================================================== --- src/OFHashes.m +++ src/OFHashes.m @@ -1,503 +0,0 @@ -/* - * Copyright (c) 2008 - 2010 - * 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 included in - * the packaging of this file. - */ - -#include "config.h" - -#include - -#import "OFHashes.h" -#import "OFAutoreleasePool.h" -#import "OFExceptions.h" -#import "macros.h" - -int _OFHashing_reference; - -@implementation OFHash -- (void)updateWithBuffer: (const char*)buffer - ofSize: (size_t)size -{ - @throw [OFNotImplementedException newWithClass: isa - selector: _cmd]; -} - -- (uint8_t*)digest -{ - @throw [OFNotImplementedException newWithClass: isa - selector: _cmd]; -} - -- (BOOL)calculated -{ - return calculated; -} -@end - -/* - * MD5 - */ - -/* The four MD5 core functions - F1 is optimized somewhat */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) - -static inline void -md5_transform(uint32_t buf[4], const uint32_t in[16]) -{ - register uint32_t a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xD76AA478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xE8C7B756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070DB, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xC1BDCEEE, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xF57C0FAF, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787C62A, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xA8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xFD469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098D8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8B44F7AF, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xFFFF5BB1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895CD7Be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6B901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xFD987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xA679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49B40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xF61E2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xC040B340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265E5A51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xE9B6C7AA, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xD62F105D, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xD8A1E681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xE7D3FBC8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21E1CDE6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xC33707D6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xF4D50D87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455A14ED, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xA9E3E905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xFCEFA3F8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676F02D9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8D2A4C8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xFFFA3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771F681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6D9D6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xFDE5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xA4BEEA44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4BDECFA9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xF6BB4B60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xBEBFBC70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289B7EC6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xEAA127FA, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xD4EF3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881D05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xD9D4D039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xE6DB99E5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1FA27CF8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xC4AC5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xF4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432AFF97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xAB9423A7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xFC93A039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655B59C3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8F0CCC92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xFFEFF47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845DD1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6FA87E4F, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xFE2CE6E0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xA3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4E0811A1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xF7537E82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xBD3AF235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2AD7D2BB, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xEB86D391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -@implementation OFMD5Hash -+ md5Hash -{ - return [[[self alloc] init] autorelease]; -} - -- init -{ - self = [super init]; - - buf[0] = 0x67452301; - buf[1] = 0xEFCDAB89; - buf[2] = 0x98BADCFE; - buf[3] = 0x10325476; - - return self; -} - -- (void)updateWithBuffer: (const char*)buffer - ofSize: (size_t)size -{ - uint32_t t; - - if (size == 0) - return; - - if (calculated) - @throw [OFHashAlreadyCalculatedException newWithClass: isa]; - - /* Update bitcount */ - t = bits[0]; - if ((bits[0] = t + ((uint32_t)size << 3)) < t) - /* Carry from low to high */ - bits[1]++; - bits[1] += size >> 29; - - /* Bytes already in shsInfo->data */ - t = (t >> 3) & 0x3F; - - /* Handle any leading odd-sized chunks */ - if (t) { - uint8_t *p = in + t; - - t = 64 - t; - - if (size < t) { - memcpy(p, buffer, size); - return; - } - - memcpy(p, buffer, t); - OF_BSWAP32_V_IF_BE((uint32_t*)in, 16); - md5_transform(buf, (uint32_t*)in); - - buffer += t; - size -= t; - } - - /* Process data in 64-byte chunks */ - while (size >= 64) { - memcpy(in, buffer, 64); - OF_BSWAP32_V_IF_BE((uint32_t*)in, 16); - md5_transform(buf, (uint32_t*)in); - - buffer += 64; - size -= 64; - } - - /* Handle any remaining bytes of data. */ - memcpy(in, buffer, size); -} - -- (uint8_t*)digest -{ - uint8_t *p; - size_t count; - - if (calculated) - return (uint8_t*)buf; - - /* Compute number of bytes mod 64 */ - count = (bits[0] >> 3) & 0x3F; - - /* - * Set the first char of padding to 0x80. This is safe since there is - * always at least one byte free - */ - p = in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - OF_BSWAP32_V_IF_BE((uint32_t*)in, 16); - md5_transform(buf, (uint32_t*)in); - - /* Now fill the next block with 56 bytes */ - memset(in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - OF_BSWAP32_V_IF_BE((uint32_t*)in, 14); - - /* Append length in bits and transform */ - ((uint32_t*)in)[14] = bits[0]; - ((uint32_t*)in)[15] = bits[1]; - - md5_transform(buf, (uint32_t*)in); - OF_BSWAP32_V_IF_BE(buf, 4); - - calculated = YES; - - return (uint8_t*)buf; -} -@end - -#undef F1 -#undef F2 -#undef F3 -#undef F4 -#undef MD5STEP - -/* - * SHA1 - */ - -/* blk0() and blk() perform the initial expand. */ -#ifndef OF_BIG_ENDIAN -#define blk0(i) \ - (block->l[i] = (OF_ROL(block->l[i], 24) & 0xFF00FF00) | \ - (OF_ROL(block->l[i], 8) & 0x00FF00FF)) -#else -#define blk0(i) block->l[i] -#endif -#define blk(i) \ - (block->l[i & 15] = OF_ROL(block->l[(i + 13) & 15] ^ \ - block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ \ - block->l[i & 15], 1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v, w, x, y, z, i) \ - z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + OF_ROL(v, 5); \ - w = OF_ROL(w, 30); -#define R1(v, w, x, y, z, i) \ - z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + OF_ROL(v, 5); \ - w = OF_ROL(w, 30); -#define R2(v, w, x, y, z, i) \ - z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + OF_ROL(v, 5); \ - w = OF_ROL(w, 30); -#define R3(v, w, x, y, z, i) \ - z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + OF_ROL(v, 5); \ - w = OF_ROL(w, 30); -#define R4(v, w, x, y, z, i) \ - z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + OF_ROL(v, 5); \ - w = OF_ROL(w, 30); - -/// \cond internal -typedef union { - char c[64]; - uint32_t l[16]; -} sha1_c64l16_t; -/// \endcond - -static inline void -sha1_transform(uint32_t state[5], const char buffer[64]) -{ - uint32_t a, b, c, d, e; - char workspace[64]; - sha1_c64l16_t *block; - - block = (sha1_c64l16_t*)workspace; - memcpy(block, buffer, 64); - - /* Copy state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - - /* Add the working vars back into state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; -} - -static inline void -sha1_update(uint32_t *state, uint64_t *count, char *buffer, - const char *buf, size_t size) -{ - size_t i, j; - - j = (size_t)((*count >> 3) & 63); - *count += (size << 3); - - if ((j + size) > 63) { - memcpy(&buffer[j], buf, (i = 64 - j)); - - sha1_transform(state, buffer); - - for (; i + 63 < size; i += 64) - sha1_transform(state, &buf[i]); - - j = 0; - } else - i = 0; - - memcpy(&buffer[j], &buf[i], size - i); -} - -@implementation OFSHA1Hash -+ sha1Hash -{ - return [[[self alloc] init] autorelease]; -} - -- init -{ - self = [super init]; - - state[0] = 0x67452301; - state[1] = 0xEFCDAB89; - state[2] = 0x98BADCFE; - state[3] = 0x10325476; - state[4] = 0xC3D2E1F0; - - return self; -} - -- (void)updateWithBuffer: (const char*)buf - ofSize: (size_t)size -{ - if (size == 0) - return; - - if (calculated) - @throw [OFHashAlreadyCalculatedException newWithClass: isa]; - - sha1_update(state, &count, buffer, buf, size); -} - -- (uint8_t*)digest -{ - size_t i; - char finalcount[8]; - - if (calculated) - return digest; - - for (i = 0; i < 8; i++) - /* Endian independent */ - finalcount[i] = (char)((count >> ((7 - (i & 7)) * 8)) & 255); - sha1_update(state, &count, buffer, "\200", 1); - - while ((count & 504) != 448) - sha1_update(state, &count, buffer, "\0", 1); - /* Should cause a sha1_transform() */ - sha1_update(state, &count, buffer, finalcount, 8); - - for (i = 0; i < OF_SHA1_DIGEST_SIZE; i++) - digest[i] = (char)((state[i >> 2] >> - ((3 - (i & 3)) * 8)) & 255); - - calculated = YES; - - return digest; -} -@end - -#undef blk0 -#undef blk -#undef R0 -#undef R1 -#undef R2 -#undef R3 -#undef R4 - -@implementation OFString (OFHashing) -- (OFString*)md5Hash -{ - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFMD5Hash *hash = [OFMD5Hash md5Hash]; - uint8_t *digest; - char ret_c[32]; - size_t i; - - [hash updateWithBuffer: string - ofSize: length]; - digest = [hash digest]; - - for (i = 0; i < 16; i++) { - uint8_t high, low; - - high = digest[i] >> 4; - low = digest[i] & 0x0F; - - ret_c[i * 2] = (high > 9 ? high - 10 + 'a' : high + '0'); - ret_c[i * 2 + 1] = (low > 9 ? low - 10 + 'a' : low + '0'); - } - - [pool release]; - - return [OFString stringWithCString: ret_c - length: 32]; -} - -- (OFString*)sha1Hash -{ - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFMD5Hash *hash = [OFSHA1Hash sha1Hash]; - uint8_t *digest; - char ret_c[40]; - size_t i; - - [hash updateWithBuffer: string - ofSize: length]; - digest = [hash digest]; - - for (i = 0; i < 20; i++) { - uint8_t high, low; - - high = digest[i] >> 4; - low = digest[i] & 0x0F; - - ret_c[i * 2] = (high > 9 ? high - 10 + 'a' : high + '0'); - ret_c[i * 2 + 1] = (low > 9 ? low - 10 + 'a' : low + '0'); - } - - [pool release]; - - return [OFString stringWithCString: ret_c - length: 40]; -} -@end Index: src/OFMutableDictionary.m ================================================================== --- src/OFMutableDictionary.m +++ src/OFMutableDictionary.m @@ -59,11 +59,11 @@ /* In case the last bucket is already used */ if (j >= last) { last = data[i]->hash & (newsize - 1); for (j = 0; j < last && - newdata[j] != NULL; i++); + newdata[j] != NULL; j++); } if (j >= last) { [self freeMemory: newdata]; @throw [OFOutOfRangeException Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -138,12 +138,12 @@ * * \param selector The selector of the class method to replace * \param class_ The class from which the new class method should be taken * \return The old implementation */ -+ (IMP)replaceClassMethod: (SEL)selector - withClassMethodFromClass: (Class)class_; ++ (IMP)replaceClassMethod: (SEL)selector + withMethodFromClass: (Class)class_; /** * Replaces an instance method implementation with another implementation. * * \param newimp The new implementation for the instance method @@ -158,12 +158,12 @@ * * \param selector The selector of the instance method to replace * \param class_ The class from which the new instance method should be taken * \return The old implementation */ -+ (IMP)replaceInstanceMethod: (SEL)selector - withInstanceMethodFromClass: (Class)class_; ++ (IMP)replaceInstanceMethod: (SEL)selector + withMethodFromClass: (Class)class_; /** * Initializes an already allocated object. * * Derived classes may override this, but need to do self = [super init] before Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -260,14 +260,18 @@ return oldimp; #endif } -+ (IMP)replaceClassMethod: (SEL)selector - withClassMethodFromClass: (Class)class; ++ (IMP)replaceClassMethod: (SEL)selector + withMethodFromClass: (Class)class; { IMP newimp; + + if (![class isSubclassOfClass: self]) + @throw [OFInvalidArgumentException newWithClass: self + selector: _cmd]; #if defined(OF_OBJFW_RUNTIME) newimp = objc_get_class_method(class, selector); #elif defined(OF_APPLE_RUNTIME) newimp = method_getImplementation(class_getClassMethod(class, @@ -312,14 +316,18 @@ return oldimp; #endif } -+ (IMP)replaceInstanceMethod: (SEL)selector - withInstanceMethodFromClass: (Class)class; ++ (IMP)replaceInstanceMethod: (SEL)selector + withMethodFromClass: (Class)class; { IMP newimp; + + if (![class isSubclassOfClass: self]) + @throw [OFInvalidArgumentException newWithClass: self + selector: _cmd]; #if defined(OF_OBJFW_RUNTIME) newimp = objc_get_instance_method(class, selector); #elif defined(OF_APPLE_RUNTIME) newimp = class_getMethodImplementation(class, selector); Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -368,9 +368,9 @@ - (uintmax_t)hexadecimalValueAsInteger; @end #import "OFConstString.h" #import "OFMutableString.h" -#import "OFHashes.h" +#import "OFHash.h" #import "OFURLEncoding.h" #import "OFXMLElement.h" #import "OFXMLParser.h" Index: src/OFXMLElement.m ================================================================== --- src/OFXMLElement.m +++ src/OFXMLElement.m @@ -15,259 +15,14 @@ #include #include #import "OFXMLElement.h" #import "OFString.h" -#import "OFArray.h" -#import "OFAutoreleasePool.h" #import "OFExceptions.h" int _OFXMLElement_reference; -@implementation OFXMLAttribute -+ attributeWithName: (OFString*)name - prefix: (OFString*)prefix - namespace: (OFString*)ns - stringValue: (OFString*)value -{ - return [[[self alloc] initWithName: name - prefix: prefix - namespace: ns - stringValue: value] autorelease]; -} - -- initWithName: (OFString*)name_ - prefix: (OFString*)prefix_ - namespace: (OFString*)ns - stringValue: (OFString*)value -{ - self = [super init]; - - name = [name_ copy]; - prefix = [prefix_ copy]; - namespace = [ns copy]; - stringValue = [value copy]; - - return self; -} - -- (void)dealloc -{ - [name release]; - [prefix release]; - [namespace release]; - [stringValue release]; - - [super dealloc]; -} - -- (OFString*)name -{ - return [[name copy] autorelease]; -} - -- (OFString*)prefix -{ - return [[prefix copy] autorelease]; -} - -- (OFString*)namespace -{ - return [[namespace copy] autorelease]; -} - -- (OFString*)stringValue -{ - return [[stringValue copy] autorelease]; -} -@end - -@implementation OFXMLElement -+ elementWithName: (OFString*)name_ -{ - return [[[self alloc] initWithName: name_] autorelease]; -} - -+ elementWithName: (OFString*)name - stringValue: (OFString*)stringval -{ - return [[[self alloc] initWithName: name - stringValue: stringval] autorelease]; -} - -- init -{ - @throw [OFNotImplementedException newWithClass: isa - selector: _cmd]; -} - -- initWithName: (OFString*)name_ -{ - self = [super init]; - - name = [name_ copy]; - - return self; -} - -- initWithName: (OFString*)name_ - stringValue: (OFString*)stringval -{ - self = [super init]; - - name = [name_ copy]; - stringValue = [stringval copy]; - - return self; -} - -- (OFString*)string -{ - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - char *str_c; - size_t len, i, j, attrs_count; - OFXMLAttribute **attrs_carray; - OFString *ret, *tmp; - - len = [name cStringLength] + 3; - str_c = [self allocMemoryWithSize: len]; - - /* Start of tag */ - *str_c = '<'; - memcpy(str_c + 1, [name cString], [name cStringLength]); - i = [name cStringLength] + 1; - - /* Attributes */ - attrs_carray = [attributes cArray]; - attrs_count = [attributes count]; - - for (j = 0; j < attrs_count; j++) { - /* FIXME: Add namespace support */ - OFString *attr_name = [attrs_carray[j] name]; - tmp = [[attrs_carray[j] stringValue] stringByXMLEscaping]; - - len += [attr_name cStringLength] + [tmp cStringLength] + 4; - @try { - str_c = [self resizeMemory: str_c - toSize: len]; - } @catch (OFException *e) { - [self freeMemory: str_c]; - @throw e; - } - - str_c[i++] = ' '; - memcpy(str_c + i, [attr_name cString], - [attr_name cStringLength]); - i += [attr_name cStringLength]; - str_c[i++] = '='; - str_c[i++] = '\''; - memcpy(str_c + i, [tmp cString], [tmp cStringLength]); - i += [tmp cStringLength]; - str_c[i++] = '\''; - - [pool releaseObjects]; - } - - /* Childen */ - if (stringValue != nil || children != nil) { - if (stringValue != nil) - tmp = [stringValue stringByXMLEscaping]; - else if (children != nil) { - OFXMLElement **children_carray = [children cArray]; - size_t children_count = [children count]; - IMP append; - - tmp = [OFMutableString string]; - append = [tmp methodForSelector: - @selector(appendCStringWithoutUTF8Checking:)]; - - for (j = 0; j < children_count; j++) - append(tmp, @selector( - appendCStringWithoutUTF8Checking:), - [[children_carray[j] string] cString]); - } - - len += [tmp cStringLength] + [name cStringLength] + 2; - @try { - str_c = [self resizeMemory: str_c - toSize: len]; - } @catch (OFException *e) { - [self freeMemory: str_c]; - @throw e; - } - - str_c[i++] = '>'; - memcpy(str_c + i, [tmp cString], [tmp cStringLength]); - i += [tmp cStringLength]; - str_c[i++] = '<'; - str_c[i++] = '/'; - memcpy(str_c + i, [name cString], [name cStringLength]); - i += [name cStringLength]; - } else - str_c[i++] = '/'; - - str_c[i++] = '>'; - assert(i == len); - - [pool release]; - - @try { - ret = [OFString stringWithCString: str_c - length: len]; - } @finally { - [self freeMemory: str_c]; - } - return ret; -} - -- (void)addAttribute: (OFXMLAttribute*)attr -{ - if (attributes == nil) - attributes = [[OFMutableArray alloc] init]; - - /* FIXME: Prevent having it twice! */ - - [attributes addObject: attr]; -} - -- (void)addAttributeWithName: (OFString*)name_ - stringValue: (OFString*)value -{ - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - [self addAttribute: [OFXMLAttribute attributeWithName: name_ - prefix: nil - namespace: nil - stringValue: value]]; - [pool release]; -} - -/* TODO: Replace attribute */ -/* TODO: Remove attribute */ - -- (void)addChild: (OFXMLElement*)child -{ - if (stringValue != nil) - @throw [OFInvalidArgumentException newWithClass: isa - selector: _cmd]; - - if (children == nil) - children = [[OFMutableArray alloc] init]; - - [children addObject: child]; -} - -- (void)dealloc -{ - [name release]; - [attributes release]; - [stringValue release]; - [children release]; - - [super dealloc]; -} -@end - @implementation OFString (OFXMLEscaping) - (OFString*)stringByXMLEscaping { char *str_c, *append, *tmp; size_t len, append_len; Index: src/OFXMLParser.m ================================================================== --- src/OFXMLParser.m +++ src/OFXMLParser.m @@ -13,27 +13,16 @@ #include #import "OFXMLParser.h" #import "OFString.h" -#import "OFArray.h" #import "OFAutoreleasePool.h" #import "OFExceptions.h" #import "macros.h" int _OFXMLParser_reference; -static OF_INLINE OFString* -transform_string(OFMutableString *cache, - OFObject *handler) -{ - /* TODO: Support for xml:space */ - - [cache removeLeadingAndTrailingWhitespaces]; - return [cache stringByXMLUnescapingWithHandler: handler]; -} - static OF_INLINE OFString* parse_numeric_entity(const char *entity, size_t length) { of_unichar_t c; size_t i; @@ -78,426 +67,10 @@ return [OFString stringWithCString: buf length: i]; } -@implementation OFXMLParser -+ xmlParser -{ - return [[[self alloc] init] autorelease]; -} - -- init -{ - self = [super init]; - - @try { - cache = [[OFMutableString alloc] init]; - previous = [[OFMutableArray alloc] init]; - } @catch (OFException *e) { - /* We can't use [super dealloc] on OS X here. Compiler bug? */ - [self dealloc]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [delegate release]; - - [cache release]; - [name release]; - [prefix release]; - [ns release]; - [attrs release]; - [attrName release]; - [attrPrefix release]; - [previous release]; - - [super dealloc]; -} - -- (id)delegate -{ - return [[delegate retain] autorelease]; -} - -- (void)setDelegate: (OFObject *)delegate_ -{ - [delegate_ retain]; - [delegate release]; - delegate = delegate_; -} - -- (void)parseBuffer: (const char*)buf - withSize: (size_t)size -{ - OFAutoreleasePool *pool; - size_t i, last, len; - - last = 0; - - for (i = 0; i < size; i++) { - switch (state) { - /* Not in a tag */ - case OF_XMLPARSER_OUTSIDE_TAG: - if (buf[i] == '<') { - len = i - last; - - if (len > 0) - [cache appendCString: buf + last - withLength: len]; - - if ([cache cStringLength] > 0) { - OFString *str; - - pool = [[OFAutoreleasePool alloc] init]; - str = transform_string(cache, self); - [delegate xmlParser: self - foundString: str]; - [pool release]; - } - - [cache setToCString: ""]; - - last = i + 1; - state = OF_XMLPARSER_TAG_OPENED; - } - break; - - /* Tag was just opened */ - case OF_XMLPARSER_TAG_OPENED: - if (buf[i] == '/') { - last = i + 1; - state = OF_XMLPARSER_IN_CLOSE_TAG_NAME; - } else if(buf[i] == '!') { - last = i + 1; - state = OF_XMLPARSER_IN_COMMENT_1; - } else { - state = OF_XMLPARSER_IN_TAG_NAME; - i--; - } - break; - - /* Inside a tag, no name yet */ - case OF_XMLPARSER_IN_TAG_NAME: - if (buf[i] == ' ' || buf[i] == '>' || buf[i] == '/') { - const char *cache_c, *tmp; - size_t cache_len; - - len = i - last; - if (len > 0) - [cache appendCString: buf + last - withLength: len]; - cache_c = [cache cString]; - cache_len = [cache cStringLength]; - - if ((tmp = memchr(cache_c, ':', - cache_len)) != NULL) { - name = [[OFString alloc] - initWithCString: tmp + 1 - length: cache_len - (tmp - - cache_c) - 1]; - prefix = [[OFString alloc] - initWithCString: cache_c - length: tmp - cache_c]; - } else { - name = [cache copy]; - prefix = nil; - } - - if (buf[i] == '>' || buf[i] == '/') { - pool = [[OFAutoreleasePool alloc] init]; - - [delegate xmlParser: self - didStartTagWithName: name - prefix: prefix - namespace: ns - attributes: nil]; - - if (buf[i] == '/') - [delegate xmlParser: self - didEndTagWithName: name - prefix: prefix - namespace: ns]; - else - [previous addObject: - [[cache copy] autorelease]]; - - [pool release]; - - [name release]; - [prefix release]; - [ns release]; - name = prefix = ns = nil; - - state = (buf[i] == '/' - ? OF_XMLPARSER_EXPECT_CLOSE - : OF_XMLPARSER_OUTSIDE_TAG); - } else - state = OF_XMLPARSER_IN_TAG; - - [cache setToCString: ""]; - last = i + 1; - } - break; - - /* Inside a close tag, no name yet */ - case OF_XMLPARSER_IN_CLOSE_TAG_NAME: - if (buf[i] == ' ' || buf[i] == '>') { - const char *cache_c, *tmp; - size_t cache_len; - - len = i - last; - if (len > 0) - [cache appendCString: buf + last - withLength: len]; - cache_c = [cache cString]; - cache_len = [cache cStringLength]; - - if ((tmp = memchr(cache_c, ':', - cache_len)) != NULL) { - name = [[OFString alloc] - initWithCString: tmp + 1 - length: cache_len - (tmp - - cache_c) - 1]; - prefix = [[OFString alloc] - initWithCString: cache_c - length: tmp - cache_c]; - } else { - name = [cache copy]; - prefix = nil; - } - - if (![[previous lastObject] isEqual: cache]) - @throw [OFMalformedXMLException - newWithClass: isa]; - [previous removeNObjects: 1]; - - [cache setToCString: ""]; - - pool = [[OFAutoreleasePool alloc] init]; - - [delegate xmlParser: self - didEndTagWithName: name - prefix: prefix - namespace: ns]; - - [pool release]; - - [name release]; - [prefix release]; - [ns release]; - name = prefix = ns = nil; - - last = i + 1; - state = (buf[i] == ' ' - ? OF_XMLPARSER_EXPECT_SPACE_OR_CLOSE - : OF_XMLPARSER_OUTSIDE_TAG); - } - break; - - /* Inside a tag, name found */ - case OF_XMLPARSER_IN_TAG: - if (buf[i] == '>' || buf[i] == '/') { - pool = [[OFAutoreleasePool alloc] init]; - - [delegate xmlParser: self - didStartTagWithName: name - prefix: prefix - namespace: ns - attributes: attrs]; - - if (buf[i] == '/') - [delegate xmlParser: self - didEndTagWithName: name - prefix: prefix - namespace: ns]; - else if (prefix != nil) { - OFString *str = [OFString - stringWithFormat: @"%s:%s", - [prefix cString], - [name cString]]; - [previous addObject: str]; - } else - [previous addObject: name]; - - [pool release]; - - [name release]; - [prefix release]; - [ns release]; - [attrs release]; - name = prefix = ns = nil; - attrs = nil; - - last = i + 1; - state = (buf[i] == '/' - ? OF_XMLPARSER_EXPECT_CLOSE - : OF_XMLPARSER_OUTSIDE_TAG); - } else if (buf[i] != ' ') { - last = i; - state = OF_XMLPARSER_IN_ATTR_NAME; - i--; - } - break; - - /* Looking for attribute name */ - case OF_XMLPARSER_IN_ATTR_NAME: - if (buf[i] == '=') { - const char *cache_c, *tmp; - size_t cache_len; - - len = i - last; - if (len > 0) - [cache appendCString: buf + last - withLength: len]; - - cache_c = [cache cString]; - cache_len = [cache cStringLength]; - - if ((tmp = memchr(cache_c, ':', - cache_len)) != NULL ) { - attrName = [[OFString alloc] - initWithCString: tmp + 1 - length: cache_len - (tmp - - cache_c) - 1]; - attrPrefix = [[OFString alloc] - initWithCString: cache_c - length: tmp - cache_c]; - } else { - attrName = [cache copy]; - attrPrefix = nil; - } - - [cache setToCString: ""]; - - last = i + 1; - state = OF_XMLPARSER_EXPECT_DELIM; - } - break; - - /* Expecting delimiter */ - case OF_XMLPARSER_EXPECT_DELIM: - if (buf[i] != '\'' && buf[i] != '"') - @throw [OFMalformedXMLException - newWithClass: isa]; - - delim = buf[i]; - last = i + 1; - state = OF_XMLPARSER_IN_ATTR_VALUE; - break; - - /* Looking for attribute value */ - case OF_XMLPARSER_IN_ATTR_VALUE: - if (buf[i] == delim) { - OFString *attr_val; - - len = i - last; - if (len > 0) - [cache appendCString: buf + last - withLength: len]; - - if (attrs == nil) - attrs = [[OFMutableArray alloc] init]; - - pool = [[OFAutoreleasePool alloc] init]; - attr_val = [cache - stringByXMLUnescapingWithHandler: self]; - [attrs addObject: [OFXMLAttribute - attributeWithName: attrName - prefix: attrPrefix - namespace: nil - stringValue: attr_val]]; - [pool release]; - - [cache setToCString: ""]; - [attrName release]; - [attrPrefix release]; - attrName = attrPrefix = nil; - - last = i + 1; - state = OF_XMLPARSER_IN_TAG; - } - break; - - /* Expecting closing '>' */ - case OF_XMLPARSER_EXPECT_CLOSE: - if (buf[i] == '>') { - last = i + 1; - state = OF_XMLPARSER_OUTSIDE_TAG; - } else - @throw [OFMalformedXMLException - newWithClass: isa]; - break; - - /* Expecting closing '>' or space */ - case OF_XMLPARSER_EXPECT_SPACE_OR_CLOSE: - if (buf[i] == '>') { - last = i + 1; - state = OF_XMLPARSER_OUTSIDE_TAG; - } else if (buf[i] != ' ') - @throw [OFMalformedXMLException - newWithClass: isa]; - break; - - /* Comment */ - case OF_XMLPARSER_IN_COMMENT_1: - case OF_XMLPARSER_IN_COMMENT_2: - if (buf[i] != '-') - @throw [OFMalformedXMLException - newWithClass: isa]; - last = i + 1; - state++; - break; - case OF_XMLPARSER_IN_COMMENT_3: - if (buf[i] == '-') - state = OF_XMLPARSER_IN_COMMENT_4; - break; - case OF_XMLPARSER_IN_COMMENT_4: - if (buf[i] == '-') { - size_t cache_len; - - [cache appendCString: buf + last - withLength: i - last]; - cache_len = [cache length]; - - pool = [[OFAutoreleasePool alloc] init]; - [cache removeCharactersFromIndex: cache_len - 1 - toIndex: cache_len]; - [cache removeLeadingAndTrailingWhitespaces]; - [delegate xmlParser: self - foundComment: cache]; - [pool release]; - - [cache setToCString: ""]; - - last = i + 1; - state = OF_XMLPARSER_EXPECT_CLOSE; - } else - state = OF_XMLPARSER_IN_COMMENT_3; - - break; - } - } - - len = size - last; - /* In OF_XMLPARSER_IN_TAG, there can be only spaces */ - if (len > 0 && state != OF_XMLPARSER_IN_TAG) - [cache appendCString: buf + last - withLength: len]; -} - -- (OFString*)foundUnknownEntityNamed: (OFString*)entity -{ - return [delegate xmlParser: self - foundUnknownEntityNamed: entity]; -} -@end - @implementation OFString (OFXMLUnescaping) - (OFString*)stringByXMLUnescaping { return [self stringByXMLUnescapingWithHandler: nil]; } @@ -591,39 +164,6 @@ [ret appendCStringWithoutUTF8Checking: string + last length: i - last]; return ret; } -@end - -@implementation OFObject (OFXMLParserDelegate) -- (void)xmlParser: (OFXMLParser*)parser - didStartTagWithName: (OFString*)name - prefix: (OFString*)prefix - namespace: (OFString*)ns - attributes: (OFArray*)attrs -{ -} - -- (void)xmlParser: (OFXMLParser*)parser - didEndTagWithName: (OFString*)name - prefix: (OFString*)prefix - namespace: (OFString*)ns -{ -} - -- (void)xmlParser: (OFXMLParser*)parser - foundString: (OFString*)string -{ -} - -- (void)xmlParser: (OFXMLParser*)parser - foundComment: (OFString*)comment -{ -} - -- (OFString*)xmlParser: (OFXMLParser*)parser - foundUnknownEntityNamed: (OFString*)entity -{ - return nil; -} @end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -32,11 +32,11 @@ #import "OFFile.h" #import "OFSocket.h" #import "OFTCPSocket.h" -#import "OFHashes.h" +#import "OFHash.h" #import "OFXMLElement.h" #import "OFApplication.h" #import "macros.h" Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -1,10 +1,12 @@ #undef OF_APPLE_RUNTIME +#undef OF_HAVE_ASPRINTF #undef OF_ATOMIC_OPS #undef OF_BIG_ENDIAN #undef OF_GNU_RUNTIME #undef OF_HAVE_ASPRINTF +#undef OF_HAVE_FAST_ENUMERATION #undef OF_HAVE_GCC_ATOMIC_OPS #undef OF_HAVE_LIBKERN_OSATOMIC_H #undef OF_HAVE_PROPERTIES #undef OF_HAVE_PTHREADS #undef OF_HAVE_PTHREAD_SPINLOCKS Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -5,21 +5,19 @@ PROG_NOINST = tests${PROG_SUFFIX} SRCS = OFArrayTests.m \ OFDataArrayTests.m \ OFDictionaryTests.m \ OFFileTests.m \ - OFHashesTests.m \ + OFHashTests.m \ OFListTests.m \ OFNumberTests.m \ OFObjectTests.m \ ${OFPLUGINTESTS_M} \ OFStreamTests.m \ OFStringTests.m \ OFTCPSocketTests.m \ ${OFTHREADTESTS_M} \ - OFXMLElementTests.m \ - OFXMLParserTests.m \ ${PROPERTIESTESTS_M} \ TestsAppDelegate.m IPHONE_USER = mobile IPHONE_TMP = /tmp/objfw-test Index: tests/OFFileTests.m ================================================================== --- tests/OFFileTests.m +++ tests/OFFileTests.m @@ -27,12 +27,12 @@ TEST(@"+[lastComponentOfPath", [[OFFile lastComponentOfPath: @"/tmp"] isEqual: @"tmp"] && [[OFFile lastComponentOfPath: @"/tmp/"] isEqual: @"tmp"] && [[OFFile lastComponentOfPath: @"/"] isEqual: @""] && - [[OFFile lastComponentOfPath: @"foo"] isEqual: @"foo"] /* && + [[OFFile lastComponentOfPath: @"foo"] isEqual: @"foo"] && [[OFFile lastComponentOfPath: @"foo/bar"] isEqual: @"bar"] && - [[OFFile lastComponentOfPath: @"foo/bar/baz/"] isEqual: @"baz"]*/) + [[OFFile lastComponentOfPath: @"foo/bar/baz/"] isEqual: @"baz"]) [pool drain]; } @end ADDED tests/OFHashTests.m Index: tests/OFHashTests.m ================================================================== --- tests/OFHashTests.m +++ tests/OFHashTests.m @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008 - 2010 + * 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 included in + * the packaging of this file. + */ + +#include "config.h" + +#include + +#import "OFHash.h" +#import "OFFile.h" +#import "OFAutoreleasePool.h" +#import "OFString.h" +#import "OFExceptions.h" + +#import "TestsAppDelegate.h" + +static OFString *module = @"OFHash"; + +const uint8_t testfile_md5[OF_MD5_DIGEST_SIZE] = + "\x00\x8B\x9D\x1B\x58\xDF\xF8\xFE\xEE\xF3\xAE\x8D\xBB\x68\x2D\x38"; +const uint8_t testfile_sha1[OF_SHA1_DIGEST_SIZE] = + "\xC9\x9A\xB8\x7E\x1E\xC8\xEC\x65\xD5\xEB\xE4\x2E\x0D\xA6\x80\x96\xF5" + "\x94\xE7\x17"; + +@implementation TestsAppDelegate (OFHashTests) +- (void)hashTests +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFMD5Hash *md5; + OFSHA1Hash *sha1; + OFFile *f = [OFFile fileWithPath: @"testfile.bin" + mode: @"rb"]; + + TEST(@"+[md5Hash]", (md5 = [OFMD5Hash md5Hash])) + + TEST(@"+[sha1Hash]", (sha1 = [OFSHA1Hash sha1Hash])) + + while (![f atEndOfStream]) { + char buf[64]; + size_t len = [f readNBytes: 64 + intoBuffer: buf]; + [md5 updateWithBuffer: buf + ofSize: len]; + [sha1 updateWithBuffer: buf + ofSize: len]; + } + [f close]; + + TEST(@"-[digest]", + !memcmp([md5 digest], testfile_md5, OF_MD5_DIGEST_SIZE) && + !memcmp([sha1 digest], testfile_sha1, OF_MD5_DIGEST_SIZE)) + + EXPECT_EXCEPTION(@"Detect invalid call of -[updateWithBuffer] #1", + OFHashAlreadyCalculatedException, [md5 updateWithBuffer: "" + ofSize: 1]) + EXPECT_EXCEPTION(@"Detect invalid call of -[updateWithBuffer] #2", + OFHashAlreadyCalculatedException, [sha1 updateWithBuffer: "" + ofSize: 1]) + + [pool drain]; +} +@end DELETED tests/OFHashesTests.m Index: tests/OFHashesTests.m ================================================================== --- tests/OFHashesTests.m +++ tests/OFHashesTests.m @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2008 - 2010 - * 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 included in - * the packaging of this file. - */ - -#include "config.h" - -#include - -#import "OFHashes.h" -#import "OFFile.h" -#import "OFAutoreleasePool.h" -#import "OFString.h" -#import "OFExceptions.h" - -#import "TestsAppDelegate.h" - -static OFString *module = @"OFHashes"; - -const uint8_t testfile_md5[OF_MD5_DIGEST_SIZE] = - "\x00\x8B\x9D\x1B\x58\xDF\xF8\xFE\xEE\xF3\xAE\x8D\xBB\x68\x2D\x38"; -const uint8_t testfile_sha1[OF_SHA1_DIGEST_SIZE] = - "\xC9\x9A\xB8\x7E\x1E\xC8\xEC\x65\xD5\xEB\xE4\x2E\x0D\xA6\x80\x96\xF5" - "\x94\xE7\x17"; - -@implementation TestsAppDelegate (OFHashesTests) -- (void)hashesTests -{ - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFMD5Hash *md5; - OFSHA1Hash *sha1; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" - mode: @"rb"]; - - TEST(@"+[md5Hash]", (md5 = [OFMD5Hash md5Hash])) - - TEST(@"+[sha1Hash]", (sha1 = [OFSHA1Hash sha1Hash])) - - while (![f atEndOfStream]) { - char buf[64]; - size_t len = [f readNBytes: 64 - intoBuffer: buf]; - [md5 updateWithBuffer: buf - ofSize: len]; - [sha1 updateWithBuffer: buf - ofSize: len]; - } - [f close]; - - TEST(@"-[digest]", - !memcmp([md5 digest], testfile_md5, OF_MD5_DIGEST_SIZE) && - !memcmp([sha1 digest], testfile_sha1, OF_MD5_DIGEST_SIZE)) - - EXPECT_EXCEPTION(@"Detect invalid call of -[updateWithBuffer] #1", - OFHashAlreadyCalculatedException, [md5 updateWithBuffer: "" - ofSize: 1]) - EXPECT_EXCEPTION(@"Detect invalid call of -[updateWithBuffer] #2", - OFHashAlreadyCalculatedException, [sha1 updateWithBuffer: "" - ofSize: 1]) - - [pool drain]; -} -@end DELETED tests/OFXMLElementTests.m Index: tests/OFXMLElementTests.m ================================================================== --- tests/OFXMLElementTests.m +++ tests/OFXMLElementTests.m @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2008 - 2010 - * 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 included in - * the packaging of this file. - */ - -#include "config.h" - -#import "OFXMLElement.h" -#import "OFString.h" -#import "OFArray.h" -#import "OFAutoreleasePool.h" -#import "OFString.h" -#import "OFExceptions.h" - -#import "TestsAppDelegate.h" - -static OFString *module = @"OFXMLElement"; - -@implementation TestsAppDelegate (OFXMLElementTests) -- (void)XMLElementTests -{ - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFXMLElement *elem[2]; - - TEST(@"+[elementWithName:]", - (elem[0] = [OFXMLElement elementWithName: @"foo"]) && - [[elem[0] string] isEqual: @""]) - - TEST(@"+[elementWithName:stringValue:]", - (elem[1] = [OFXMLElement elementWithName: @"foo" - stringValue: @"b&ar"]) && - [[elem[1] string] isEqual: @"b&ar"]) - - TEST(@"-[addAttributeWithName:stringValue:]", - R([elem[0] addAttributeWithName: @"foo" - stringValue: @"b&ar"]) && - [[elem[0] string] isEqual: @""] && - R([elem[1] addAttributeWithName: @"foo" - stringValue: @"b&ar"]) && - [[elem[1] string] isEqual: @"b&ar"]) - - TEST(@"-[addChild:]", - R([elem[0] addChild: [OFXMLElement elementWithName: @"bar"]]) && - [[elem[0] string] isEqual: @""]) - - [pool drain]; -} -@end DELETED tests/OFXMLParserTests.m Index: tests/OFXMLParserTests.m ================================================================== --- tests/OFXMLParserTests.m +++ tests/OFXMLParserTests.m @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2008 - 2010 - * 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 included in - * the packaging of this file. - */ - -#include "config.h" - -#include - -#import "OFXMLParser.h" -#import "OFString.h" -#import "OFArray.h" -#import "OFAutoreleasePool.h" -#import "OFString.h" -#import "OFExceptions.h" - -#import "TestsAppDelegate.h" - -static OFString *module = @"OFXMLParser"; -static int i = 0; - -enum event_type { - TAG_START, - TAG_END, - STRING, - COMMENT -}; - -@implementation TestsAppDelegate (OFXMLParser) -- (void)xmlParserCallbackWithEventType: (enum event_type)et - name: (OFString*)name - prefix: (OFString*)prefix - namespace: (OFString*)ns - attributes: (OFArray*)attrs - string: (OFString*)string - comment: (OFString*)comment -{ - OFString *msg; - id *carray; - size_t count; - - i++; - msg = [OFString stringWithFormat: @"Parsing part #%d", i]; - - switch (i) { - case 1: - case 5: - TEST(msg, et == STRING && [string isEqual: @"bar"]) - break; - case 2: - /* FIXME: Namespace */ - carray = [attrs cArray]; - count = [attrs count]; - - TEST(msg, et == TAG_START && [name isEqual: @"bar"] && - [prefix isEqual: @"foo"] && ns == nil && - attrs != nil && count == 2 && - /* Attribute 1 */ - [[carray[0] name] isEqual: @"bar"] && - [carray[0] prefix] == nil && - [[carray[0] stringValue] isEqual: @"b&az"] && - [carray[0] namespace] == nil && - /* Attribute 2 */ - [[carray[1] name] isEqual: @"qux"] && - [[carray[1] prefix] isEqual: @"qux"] && - [[carray[1] stringValue] isEqual: @" quux "] && - [carray[1] namespace] == nil) - break; - case 3: - TEST(msg, et == STRING && [string isEqual: @"foo\r\n" - "foo<barbar quxbar\r\n" - ""; - size_t j, len; - - TEST(@"+[xmlParser]", (parser = [OFXMLParser xmlParser])) - - TEST(@"-[setDelegate:]", R([parser setDelegate: self])) - - /* Simulate a stream where we only get chunks */ - len = strlen(str); - - for (j = 0; j < len; j+= 2) { - if (j + 2 > len) - [parser parseBuffer: str + j - withSize: 1]; - else - [parser parseBuffer: str + j - withSize: 2]; - } - - TEST(@"Checking if everything was parsed", i == 11) - - [pool drain]; -} -@end Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -81,12 +81,12 @@ @interface TestsAppDelegate (OFFileTests) - (void)fileTests; @end -@interface TestsAppDelegate (OFHashesTests) -- (void)hashesTests; +@interface TestsAppDelegate (OFHashTests) +- (void)hashTests; @end @interface TestsAppDelegate (OFListTests) - (void)listTests; @end @@ -120,13 +120,5 @@ @end @interface TestsAppDelegate (OFThreadTests) - (void)threadTests; @end - -@interface TestsAppDelegate (OFXMLElementTests) -- (void)XMLElementTests; -@end - -@interface TestsAppDelegate (OFXMLParserTests) -- (void)XMLParserTests; -@end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -77,11 +77,11 @@ - (void)applicationDidFinishLaunching { [self objectTests]; [self stringTests]; [self fileTests]; - [self hashesTests]; + [self hashTests]; [self dataArrayTests]; [self arrayTests]; [self dictionaryTests]; [self listTests]; [self numberTests]; @@ -88,12 +88,10 @@ [self streamTests]; [self TCPSocketTests]; #ifdef OF_THREADS [self threadTests]; #endif - [self XMLElementTests]; - [self XMLParserTests]; #ifdef OF_PLUGINS [self pluginTests]; #endif #ifdef OF_HAVE_PROPERTIES [self propertiesTests]; Index: tests/objc_sync/test.m ================================================================== --- tests/objc_sync/test.m +++ tests/objc_sync/test.m @@ -43,11 +43,14 @@ main() { lock = [[OFObject alloc] init]; MyThread *t1 = [MyThread threadWithObject: @"A"]; MyThread *t2 = [MyThread threadWithObject: @"B"]; + + [t1 start]; + [t2 start]; [t1 join]; [t2 join]; return 0; } Index: utils/objfw-config.in ================================================================== --- utils/objfw-config.in +++ utils/objfw-config.in @@ -8,13 +8,14 @@ OBJC="@OBJC@" OBJCFLAGS="@GNU_RUNTIME@ -fexceptions -fobjc-exceptions" OBJCFLAGS="$OBJCFLAGS -fconstant-string-class=OFConstString" OBJCFLAGS="$OBJCFLAGS @NO_CONST_CFSTRINGS@ @NO_WARN_UNUSED@ @ATOMIC_OBJCFLAGS@" LDFLAGS="" +LDFLAGS_REEXPORT="@LDFLAGS_REEXPORT@" LDFLAGS_RPATH="@LDFLAGS_RPATH@" LIBS="-L${libdir} -lobjfw @LIBS@" -VERSION="0.3-dev" +VERSION="0.3" show_help() { cat <<__EOF__ objfw-config: Available arguments are: @@ -23,10 +24,11 @@ --cppflags Outputs the required CPPFLAGS --cxxflags Outputs the required CXXFLAGS --objc Outputs the OBJC used to compile ObjFW --objcflags Outputs the required OBJCFLAGS --ldflags Outputs the required LDFLAGS + --reexport Outputs LDFLAGS to reexport ObjFW --rpath Outputs LDFLAGS for using rpath --libs Outputs the required LIBS --version Outputs the installed version __EOF__ exit 0 @@ -40,11 +42,12 @@ echo "$CFLAGS" echo "$CPPFLAGS" echo "$CXXFLAGS" echo "$OBJCFLAGS" echo "$LDFLAGS" - echo "$RPATH_LDFLAGS" + echo "$LDFLAGS_REEXPORT" + echo "$LDFLAGS_RPATH" echo "$LIBS" ;; --cflags) echo "$CFLAGS" ;; @@ -64,10 +67,13 @@ echo "$LIBS" ;; --ldflags) echo "$LDFLAGS" ;; + --reexport) + echo "$LDFLAGS_REEXPORT" + ;; --rpath) echo "$LDFLAGS_RPATH" ;; --version) echo "$VERSION"