Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -8,13 +8,17 @@ STATIC_LIB = ${OBJFW_STATIC_LIB} FRAMEWORK = ${OBJFW_FRAMEWORK} LIB_MAJOR = ${OBJFW_LIB_MAJOR} LIB_MINOR = ${OBJFW_LIB_MINOR} -SRCS = OFApplication.m \ +SRCS = OFASPrintF.m \ + OFApplication.m \ OFArray.m \ + OFBase64.m \ OFBlock.m \ + OFCRC16.m \ + OFCRC32.m \ OFCharacterSet.m \ OFColor.m \ OFConstantString.m \ OFCountedSet.m \ OFData.m \ @@ -24,19 +28,20 @@ OFDictionary.m \ OFEnumerator.m \ OFFileManager.m \ OFGZIPStream.m \ OFHMAC.m \ + OFHuffmanTree.m \ OFInflate64Stream.m \ OFInflateStream.m \ OFInvocation.m \ OFLHAArchive.m \ OFLHAArchiveEntry.m \ OFList.m \ OFLocale.m \ - OFMapTable.m \ OFMD5Hash.m \ + OFMapTable.m \ OFMessagePackExtension.m \ OFMethodSignature.m \ OFMutableArray.m \ OFMutableData.m \ OFMutableDictionary.m \ @@ -51,26 +56,30 @@ OFNull.m \ OFNumber.m \ OFObject.m \ OFObject+KeyValueCoding.m \ OFObject+Serialization.m \ + OFOnce.m \ OFOptionsParser.m \ + OFPBKDF2.m \ OFPair.m \ OFRIPEMD160Hash.m \ OFRunLoop.m \ - OFSecureData.m \ - OFSeekableStream.m \ - OFSet.m \ OFSHA1Hash.m \ OFSHA224Hash.m \ OFSHA224Or256Hash.m \ OFSHA256Hash.m \ OFSHA384Hash.m \ OFSHA384Or512Hash.m \ OFSHA512Hash.m \ + OFScrypt.m \ + OFSecureData.m \ + OFSeekableStream.m \ + OFSet.m \ OFSortedList.m \ OFStdIOStream.m \ + OFStrPTime.m \ OFStream.m \ OFString.m \ OFString+CryptographicHashing.m \ OFString+JSONParsing.m \ OFString+PropertyListParsing.m \ @@ -98,19 +107,10 @@ OFXMLNode.m \ OFXMLParser.m \ OFXMLProcessingInstruction.m \ OFZIPArchive.m \ OFZIPArchiveEntry.m \ - base64.m \ - crc16.m \ - crc32.m \ - huffman_tree.m \ - of_asprintf.m \ - of_strptime.m \ - once.m \ - pbkdf2.m \ - scrypt.m \ ${UNICODE_M} \ ${USE_SRCS_FILES} \ ${USE_SRCS_PLUGINS} \ ${USE_SRCS_SOCKETS} \ ${USE_SRCS_THREADS} \ @@ -134,33 +134,33 @@ OFHTTPCookieManager.m \ OFHTTPRequest.m \ OFHTTPResponse.m \ OFHTTPServer.m \ OFSequencedPacketSocket.m \ + OFSocket.m \ OFStreamSocket.m \ OFTCPSocket.m \ OFUDPSocket.m \ - socket.m \ ${USE_SRCS_IPX} SRCS_THREADS = OFCondition.m \ OFMutex.m \ + OFPlainCondition.m \ + OFPlainMutex.m \ + OFPlainThread.m \ OFRecursiveMutex.m \ - OFThreadPool.m \ - condition.m \ - mutex.m \ - thread.m \ - tlskey.m + OFTLSKey.m \ + OFThreadPool.m SRCS_WINDOWS = OFWin32ConsoleStdIOStream.m \ OFWindowsRegistryKey.m -INCLUDES_ATOMIC = atomic.h \ - atomic_builtins.h \ - atomic_no_threads.h \ - atomic_osatomic.h \ - atomic_powerpc.h \ - atomic_sync_builtins.h \ - atomic_x86.h +INCLUDES_ATOMIC = OFAtomic.h \ + OFAtomic_builtins.h \ + OFAtomic_no_threads.h \ + OFAtomic_osatomic.h \ + OFAtomic_powerpc.h \ + OFAtomic_sync_builtins.h \ + OFAtomic_x86.h INCLUDES := ${SRCS:.m=.h} \ OFCollection.h \ OFCryptographicHash.h \ OFJSONRepresentation.h \ OFKernelEventObserver.h \ ADDED src/OFASPrintF.h Index: src/OFASPrintF.h ================================================================== --- src/OFASPrintF.h +++ src/OFASPrintF.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#include + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifdef __cplusplus +extern "C" { +#endif +extern int OFVASPrintF( + char *_Nullable *_Nonnull, const char *_Nonnull, va_list); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFASPrintF.m Index: src/OFASPrintF.m ================================================================== --- src/OFASPrintF.m +++ src/OFASPrintF.m @@ -0,0 +1,783 @@ +/* + * 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 +#include +#include +#include +#include + +#ifdef HAVE_WCHAR_H +# include +#endif + +#ifdef HAVE_ASPRINTF_L +# include +#endif +#ifdef HAVE_XLOCALE_H +# include +#endif + +#ifdef OF_HAVE_SYS_TYPES_H +# include +#endif + +#import "OFString.h" +#import "OFLocale.h" + +#import "OFInitializationFailedException.h" + +#define MAX_SUBFORMAT_LEN 64 + +#ifndef HAVE_ASPRINTF +/* + * (v)asprintf might be declared, but HAVE_ASPRINTF not defined because + * configure determined it is broken. In this case, we must make sure there is + * no name clash. + */ +# define asprintf asprintf_ +# define vasprintf vasprintf_ +#endif + +struct context { + const char *format; + size_t formatLen; + char subformat[MAX_SUBFORMAT_LEN + 1]; + size_t subformatLen; + va_list arguments; + char *buffer; + size_t bufferLen; + size_t i, last; + enum { + StateString, + StateFormatFlags, + StateFormatFieldWidth, + StateFormatLengthModifier, + StateFormatConversionSpecifier + } state; + enum { + LengthModifierNone, + LengthModifierHH, + LengthModifierH, + LengthModifierL, + LengthModifierLL, + LengthModifierJ, + LengthModifierZ, + LengthModifierT, + LengthModifierCapitalL + } lengthModifier; + bool useLocale; +}; + +#ifdef HAVE_ASPRINTF_L +static locale_t cLocale; + +OF_CONSTRUCTOR() +{ + if ((cLocale = newlocale(LC_ALL_MASK, "C", NULL)) == NULL) + @throw [OFInitializationFailedException exception]; +} +#endif + +#ifndef HAVE_ASPRINTF +static int +vasprintf(char **string, const char *format, va_list arguments) +{ + int length; + size_t bufferLength = 128; + + *string = NULL; + + for (;;) { + free(*string); + + if ((*string = malloc(bufferLength)) == NULL) + return -1; + + length = vsnprintf(*string, bufferLength - 1, format, + arguments); + + if (length >= 0 && (size_t)length < bufferLength - 1) + break; + + if (bufferLength > INT_MAX / 2) { + free(*string); + return -1; + } + + bufferLength <<= 1; + } + + if (length > 0 && (size_t)length != bufferLength - 1) { + char *resized = realloc(*string, length + 1); + + /* Ignore if making it smaller failed. */ + if (resized != NULL) + *string = resized; + } + + return length; +} + +static int +asprintf(char **string, const char *format, ...) +{ + int ret; + va_list arguments; + + va_start(arguments, format); + ret = vasprintf(string, format, arguments); + va_end(arguments); + + return ret; +} +#endif + +static bool +appendString(struct context *ctx, const char *append, size_t appendLen) +{ + char *newBuf; + + if (appendLen == 0) + return true; + + if ((newBuf = realloc(ctx->buffer, + ctx->bufferLen + appendLen + 1)) == NULL) + return false; + + memcpy(newBuf + ctx->bufferLen, append, appendLen); + + ctx->buffer = newBuf; + ctx->bufferLen += appendLen; + + return true; +} + +static bool +appendSubformat(struct context *ctx, const char *subformat, + size_t subformatLen) +{ + if (ctx->subformatLen + subformatLen > MAX_SUBFORMAT_LEN) + return false; + + memcpy(ctx->subformat + ctx->subformatLen, subformat, subformatLen); + ctx->subformatLen += subformatLen; + ctx->subformat[ctx->subformatLen] = 0; + + return true; +} + +static bool +stringState(struct context *ctx) +{ + if (ctx->format[ctx->i] == '%') { + if (ctx->i > 0) + if (!appendString(ctx, ctx->format + ctx->last, + ctx->i - ctx->last)) + return false; + + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + ctx->last = ctx->i + 1; + ctx->state = StateFormatFlags; + } + + return true; +} + +static bool +formatFlagsState(struct context *ctx) +{ + switch (ctx->format[ctx->i]) { + case '-': + case '+': + case ' ': + case '#': + case '0': + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + break; + case ',': + /* ObjFW extension: Use decimal point from locale */ + ctx->useLocale = true; + break; + default: + ctx->state = StateFormatFieldWidth; + ctx->i--; + + break; + } + + return true; +} + +static bool +formatFieldWidthState(struct context *ctx) +{ + if ((ctx->format[ctx->i] >= '0' && ctx->format[ctx->i] <= '9') || + ctx->format[ctx->i] == '*' || ctx->format[ctx->i] == '.') { + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + } else { + ctx->state = StateFormatLengthModifier; + ctx->i--; + } + + return true; +} + +static bool +formatLengthModifierState(struct context *ctx) +{ + /* Only one allowed */ + switch (ctx->format[ctx->i]) { + case 'h': /* and also hh */ + if (ctx->formatLen > ctx->i + 1 && + ctx->format[ctx->i + 1] == 'h') { + if (!appendSubformat(ctx, ctx->format + ctx->i, 2)) + return false; + + ctx->i++; + ctx->lengthModifier = LengthModifierHH; + } else { + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + ctx->lengthModifier = LengthModifierH; + } + + break; + case 'l': /* and also ll */ + if (ctx->formatLen > ctx->i + 1 && + ctx->format[ctx->i + 1] == 'l') { +#ifndef OF_WINDOWS + if (!appendSubformat(ctx, ctx->format + ctx->i, 2)) + return false; +#else + if (!appendSubformat(ctx, "I64", 3)) + return false; +#endif + + ctx->i++; + ctx->lengthModifier = LengthModifierLL; + } else { + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + ctx->lengthModifier = LengthModifierL; + } + + break; + case 'j': +#if defined(OF_WINDOWS) + if (!appendSubformat(ctx, "I64", 3)) + return false; +#elif defined(_NEWLIB_VERSION) || defined(OF_HPUX) + if (!appendSubformat(ctx, "ll", 2)) + return false; +#else + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; +#endif + + ctx->lengthModifier = LengthModifierJ; + + break; + case 'z': +#if defined(OF_WINDOWS) + if (sizeof(size_t) == 8) + if (!appendSubformat(ctx, "I64", 3)) + return false; +#elif defined(_NEWLIB_VERSION) || defined(OF_HPUX) + if (!appendSubformat(ctx, "l", 1)) + return false; +#else + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; +#endif + + ctx->lengthModifier = LengthModifierZ; + + break; + case 't': +#if defined(OF_WINDOWS) + if (sizeof(ptrdiff_t) == 8) + if (!appendSubformat(ctx, "I64", 3)) + return false; +#elif defined(_NEWLIB_VERSION) || defined(OF_HPUX) + if (!appendSubformat(ctx, "l", 1)) + return false; +#else + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; +#endif + + ctx->lengthModifier = LengthModifierT; + + break; + case 'L': + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + ctx->lengthModifier = LengthModifierCapitalL; + + break; +#ifdef OF_WINDOWS + case 'I': /* win32 strangeness (I64 instead of ll or j) */ + if (ctx->formatLen > ctx->i + 2 && + ctx->format[ctx->i + 1] == '6' && + ctx->format[ctx->i + 2] == '4') { + if (!appendSubformat(ctx, ctx->format + ctx->i, 3)) + return false; + + ctx->i += 2; + ctx->lengthModifier = LengthModifierLL; + } else + ctx->i--; + + break; +#endif +#ifdef OF_IOS + case 'q': /* iOS uses this for PRI?64 */ + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + ctx->lengthModifier = LengthModifierLL; + + break; +#endif + default: + ctx->i--; + + break; + } + + ctx->state = StateFormatConversionSpecifier; + return true; +} + +static bool +formatConversionSpecifierState(struct context *ctx) +{ + char *tmp = NULL; + int tmpLen = 0; +#ifndef HAVE_ASPRINTF_L + OFString *point; +#endif + + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + switch (ctx->format[ctx->i]) { + case '@': + if (ctx->lengthModifier != LengthModifierNone) + return false; + + ctx->subformat[ctx->subformatLen - 1] = 's'; + + @try { + id object; + + if ((object = va_arg(ctx->arguments, id)) != nil) { + void *pool = objc_autoreleasePoolPush(); + + tmpLen = asprintf(&tmp, ctx->subformat, + [object description].UTF8String); + + objc_autoreleasePoolPop(pool); + } else + tmpLen = asprintf(&tmp, ctx->subformat, + "(nil)"); + } @catch (id e) { + free(ctx->buffer); + @throw e; + } + + break; + case 'C': + if (ctx->lengthModifier != LengthModifierNone) + return false; + + ctx->subformat[ctx->subformatLen - 1] = 's'; + + { + char buffer[5]; + size_t len = of_string_utf8_encode( + va_arg(ctx->arguments, OFUnichar), buffer); + + if (len == 0) + return false; + + buffer[len] = 0; + tmpLen = asprintf(&tmp, ctx->subformat, buffer); + } + + break; + case 'S': + if (ctx->lengthModifier != LengthModifierNone) + return false; + + ctx->subformat[ctx->subformatLen - 1] = 's'; + + { + const OFUnichar *arg = + va_arg(ctx->arguments, const OFUnichar *); + size_t j, len = of_string_utf32_length(arg); + char *buffer; + + if (SIZE_MAX / 4 < len || (SIZE_MAX / 4) - len < 1) + return false; + + if ((buffer = malloc((len * 4) + 1)) == NULL) + return false; + + j = 0; + for (size_t i = 0; i < len; i++) { + size_t clen = of_string_utf8_encode(arg[i], + buffer + j); + + if (clen == 0) { + free(buffer); + return false; + } + + j += clen; + } + buffer[j] = 0; + + tmpLen = asprintf(&tmp, ctx->subformat, buffer); + + free(buffer); + } + + break; + case 'd': + case 'i': + switch (ctx->lengthModifier) { + case LengthModifierNone: + case LengthModifierHH: + case LengthModifierH: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, int)); + break; + case LengthModifierL: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, long)); + break; + case LengthModifierLL: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, long long)); + break; + case LengthModifierJ: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, intmax_t)); + break; + case LengthModifierZ: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, ssize_t)); + break; + case LengthModifierT: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, ptrdiff_t)); + break; + default: + return false; + } + + break; + case 'o': + case 'u': + case 'x': + case 'X': + switch (ctx->lengthModifier) { + case LengthModifierNone: + case LengthModifierHH: + case LengthModifierH: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, unsigned int)); + break; + case LengthModifierL: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, unsigned long)); + break; + case LengthModifierLL: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, unsigned long long)); + break; + case LengthModifierJ: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, uintmax_t)); + break; + case LengthModifierZ: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, size_t)); + break; + case LengthModifierT: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, ptrdiff_t)); + break; + default: + return false; + } + + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + switch (ctx->lengthModifier) { + case LengthModifierNone: + case LengthModifierL: +#ifdef HAVE_ASPRINTF_L + if (!ctx->useLocale) + tmpLen = asprintf_l(&tmp, cLocale, + ctx->subformat, + va_arg(ctx->arguments, double)); + else +#endif + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, double)); + break; + case LengthModifierCapitalL: +#ifdef HAVE_ASPRINTF_L + if (!ctx->useLocale) + tmpLen = asprintf_l(&tmp, cLocale, + ctx->subformat, + va_arg(ctx->arguments, long double)); + else +#endif + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, long double)); + break; + default: + return false; + } + +#ifndef HAVE_ASPRINTF_L + if (tmpLen == -1) + return false; + + /* + * If there's no asprintf_l, we have no other choice than to + * use this ugly hack to replace the locale's decimal point + * back to ".". + */ + point = [OFLocale decimalPoint]; + + if (!ctx->useLocale && point != nil && ![point isEqual: @"."]) { + void *pool = objc_autoreleasePoolPush(); + char *tmp2; + + @try { + OFMutableString *tmpStr = [OFMutableString + stringWithUTF8String: tmp + length: tmpLen]; + [tmpStr replaceOccurrencesOfString: point + withString: @"."]; + + if (tmpStr.UTF8StringLength > INT_MAX) + return false; + + tmpLen = (int)tmpStr.UTF8StringLength; + tmp2 = malloc(tmpLen); + memcpy(tmp2, tmpStr.UTF8String, tmpLen); + } @finally { + free(tmp); + objc_autoreleasePoolPop(pool); + } + + tmp = tmp2; + } +#endif + + break; + case 'c': + switch (ctx->lengthModifier) { + case LengthModifierNone: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, int)); + break; + case LengthModifierL: +#ifdef HAVE_WCHAR_H +# if WINT_MAX >= INT_MAX + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, wint_t)); +# else + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, int)); +# endif + break; +#endif + default: + return false; + } + + break; + case 's': + switch (ctx->lengthModifier) { + case LengthModifierNone: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, const char *)); + break; +#ifdef HAVE_WCHAR_T + case LengthModifierL: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, const wchar_t *)); + break; +#endif + default: + return false; + } + + break; + case 'p': + if (ctx->lengthModifier != LengthModifierNone) + return false; + + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, void *)); + + break; + case 'n': + switch (ctx->lengthModifier) { + case LengthModifierNone: + *va_arg(ctx->arguments, int *) = (int)ctx->bufferLen; + break; + case LengthModifierHH: + *va_arg(ctx->arguments, signed char *) = + (signed char)ctx->bufferLen; + break; + case LengthModifierH: + *va_arg(ctx->arguments, short *) = + (short)ctx->bufferLen; + break; + case LengthModifierL: + *va_arg(ctx->arguments, long *) = + (long)ctx->bufferLen; + break; + case LengthModifierLL: + *va_arg(ctx->arguments, long long *) = + (long long)ctx->bufferLen; + break; + case LengthModifierJ: + *va_arg(ctx->arguments, intmax_t *) = + (intmax_t)ctx->bufferLen; + break; + case LengthModifierZ: + *va_arg(ctx->arguments, size_t *) = + (size_t)ctx->bufferLen; + break; + case LengthModifierT: + *va_arg(ctx->arguments, ptrdiff_t *) = + (ptrdiff_t)ctx->bufferLen; + break; + default: + return false; + } + + break; + case '%': + if (ctx->lengthModifier != LengthModifierNone) + return false; + + if (!appendString(ctx, "%", 1)) + return false; + + break; + default: + return false; + } + + if (tmpLen == -1) + return false; + + if (tmp != NULL) { + if (!appendString(ctx, tmp, tmpLen)) { + free(tmp); + return false; + } + + free(tmp); + } + + memset(ctx->subformat, 0, MAX_SUBFORMAT_LEN); + ctx->subformatLen = 0; + ctx->lengthModifier = LengthModifierNone; + ctx->useLocale = false; + + ctx->last = ctx->i + 1; + ctx->state = StateString; + + return true; +} + +static bool (*states[])(struct context *) = { + stringState, + formatFlagsState, + formatFieldWidthState, + formatLengthModifierState, + formatConversionSpecifierState +}; + +int +OFVASPrintF(char **string, const char *format, va_list arguments) +{ + struct context ctx; + + ctx.format = format; + ctx.formatLen = strlen(format); + memset(ctx.subformat, 0, MAX_SUBFORMAT_LEN + 1); + ctx.subformatLen = 0; + va_copy(ctx.arguments, arguments); + ctx.bufferLen = 0; + ctx.last = 0; + ctx.state = StateString; + ctx.lengthModifier = LengthModifierNone; + ctx.useLocale = false; + + if ((ctx.buffer = malloc(1)) == NULL) + return -1; + + for (ctx.i = 0; ctx.i < ctx.formatLen; ctx.i++) { + if (!states[ctx.state](&ctx)) { + free(ctx.buffer); + return -1; + } + } + + if (ctx.state != StateString) { + free(ctx.buffer); + return -1; + } + + if (!appendString(&ctx, ctx.format + ctx.last, + ctx.formatLen - ctx.last)) { + free(ctx.buffer); + return -1; + } + + ctx.buffer[ctx.bufferLen] = 0; + + *string = ctx.buffer; + return (ctx.bufferLen <= INT_MAX ? (int)ctx.bufferLen : -1); +} ADDED src/OFAtomic.h Index: src/OFAtomic.h ================================================================== --- src/OFAtomic.h +++ src/OFAtomic.h @@ -0,0 +1,39 @@ +/* + * 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 + +#import "macros.h" + +#ifndef OF_HAVE_ATOMIC_OPS +# error No atomic operations available! +#endif + +#if !defined(OF_HAVE_THREADS) +# import "OFAtomic_no_threads.h" +#elif (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) +# import "OFAtomic_x86.h" +#elif defined(OF_POWERPC) && defined(__GNUC__) && !defined(__APPLE_CC__) && \ + !defined(OF_AIX) +# import "OFAtomic_powerpc.h" +#elif defined(OF_HAVE_ATOMIC_BUILTINS) +# import "OFAtomic_builtins.h" +#elif defined(OF_HAVE_SYNC_BUILTINS) +# import "OFAtomic_sync_builtins.h" +#elif defined(OF_HAVE_OSATOMIC) +# import "OFAtomic_osatomic.h" +#else +# error No atomic operations available! +#endif ADDED src/OFAtomic_builtins.h Index: src/OFAtomic_builtins.h ================================================================== --- src/OFAtomic_builtins.h +++ src/OFAtomic_builtins.h @@ -0,0 +1,150 @@ +/* + * 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. + */ + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + return __atomic_compare_exchange(p, &o, &n, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + return __atomic_compare_exchange(p, &o, &n, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + return __atomic_compare_exchange(p, &o, &n, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} + +static OF_INLINE void +of_memory_barrier_full(void) +{ + __atomic_thread_fence(__ATOMIC_SEQ_CST); +} + +static OF_INLINE void +of_memory_barrier_acquire(void) +{ + __atomic_thread_fence(__ATOMIC_ACQUIRE); +} + +static OF_INLINE void +of_memory_barrier_release(void) +{ + __atomic_thread_fence(__ATOMIC_RELEASE); +} ADDED src/OFAtomic_no_threads.h Index: src/OFAtomic_no_threads.h ================================================================== --- src/OFAtomic_no_threads.h +++ src/OFAtomic_no_threads.h @@ -0,0 +1,162 @@ +/* + * 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. + */ + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return (*p += i); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return (*p += i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return (*(char *volatile *)p += i); +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return (*p -= i); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return (*p -= i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return (*(char *volatile *)p -= i); +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return ++*p; +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return ++*p; +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return --*p; +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return --*p; +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return (*p |= i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return (*p |= i); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return (*p &= i); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return (*p &= i); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return (*p ^= i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return (*p ^= i); +} + +static OF_INLINE bool +OFAtomicIntCompareSwap(volatile int *_Nonnull p, int o, int n) +{ + if (*p == o) { + *p = n; + return true; + } + + return false; +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + if (*p == o) { + *p = n; + return true; + } + + return false; +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + if (*p == o) { + *p = n; + return true; + } + + return false; +} + +static OF_INLINE void +of_memory_barrier(void) +{ + /* nop */ +} + +static OF_INLINE void +of_memory_barrier_acquire(void) +{ + /* nop */ +} + +static OF_INLINE void +of_memory_barrier_release(void) +{ + /* nop */ +} ADDED src/OFAtomic_osatomic.h Index: src/OFAtomic_osatomic.h ================================================================== --- src/OFAtomic_osatomic.h +++ src/OFAtomic_osatomic.h @@ -0,0 +1,157 @@ +/* + * 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 + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return OSAtomicAdd32(i, p); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return OSAtomicAdd32(i, p); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#ifdef __LP64__ + return (void *)OSAtomicAdd64(i, (int64_t *)p); +#else + return (void *)OSAtomicAdd32(i, (int32_t *)p); +#endif +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return OSAtomicAdd32(-i, p); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return OSAtomicAdd32(-i, p); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#ifdef __LP64__ + return (void *)OSAtomicAdd64(-i, (int64_t *)p); +#else + return (void *)OSAtomicAdd32(-i, (int32_t *)p); +#endif +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return OSAtomicIncrement32(p); +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return OSAtomicIncrement32(p); +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return OSAtomicDecrement32(p); +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return OSAtomicDecrement32(p); +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return OSAtomicOr32(i, p); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return OSAtomicOr32(i, p); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return OSAtomicAnd32(i, p); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return OSAtomicAnd32(i, p); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return OSAtomicXor32(i, p); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return OSAtomicXor32(i, p); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + return OSAtomicCompareAndSwapInt(o, n, p); +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + return OSAtomicCompareAndSwap32(o, n, p); +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + return OSAtomicCompareAndSwapPtr(o, n, p); +} + +static OF_INLINE void +of_memory_barrier(void) +{ + OSMemoryBarrier(); +} + +static OF_INLINE void +of_memory_barrier_acquire(void) +{ + OSMemoryBarrier(); +} + +static OF_INLINE void +of_memory_barrier_release(void) +{ + OSMemoryBarrier(); +} ADDED src/OFAtomic_powerpc.h Index: src/OFAtomic_powerpc.h ================================================================== --- src/OFAtomic_powerpc.h +++ src/OFAtomic_powerpc.h @@ -0,0 +1,397 @@ +/* + * 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. + */ + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "add %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "add %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "add %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return (void *)i; +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "sub %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "sub %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "sub %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return (void *)i; +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + int i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "addi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "addi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + int i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "subi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "subi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "or %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "or %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "and %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "and %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "xor %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "xor %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE bool +OFAtomicIntCompAndSwap(volatile int *_Nonnull p, int o, int n) +{ + int r; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %3\n\t" + "cmpw %0, %1\n\t" + "bne 1f\n\t" + "stwcx. %2, 0, %3\n\t" + "bne- 0b\n\t" + "li %0, 1\n\t" + "b 2f\n\t" + "1:\n\t" + "stwcx. %0, 0, %3\n\t" + "li %0, 0\n\t" + "2:" + : "=&r"(r) + : "r"(o), "r"(n), "r"(p) + : "cc", "memory" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + int r; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %3\n\t" + "cmpw %0, %1\n\t" + "bne 1f\n\t" + "stwcx. %2, 0, %3\n\t" + "bne- 0b\n\t" + "li %0, 1\n\t" + "b 2f\n\t" + "1:\n\t" + "stwcx. %0, 0, %3\n\t" + "li %0, 0\n\t" + "2:" + : "=&r"(r) + : "r"(o), "r"(n), "r"(p) + : "cc", "memory" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + int r; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %3\n\t" + "cmpw %0, %1\n\t" + "bne 1f\n\t" + "stwcx. %2, 0, %3\n\t" + "bne- 0b\n\t" + "li %0, 1\n\t" + "b 2f\n\t" + "1:\n\t" + "stwcx. %0, 0, %3\n\t" + "li %0, 0\n\t" + "2:" + : "=&r"(r) + : "r"(o), "r"(n), "r"(p) + : "cc", "memory" + ); + + return r; +} + +static OF_INLINE void +of_memory_barrier(void) +{ + __asm__ __volatile__ ( + ".long 0x7C2004AC /* lwsync */" ::: "memory" + ); +} + +static OF_INLINE void +of_memory_barrier_acquire(void) +{ + __asm__ __volatile__ ( + ".long 0x7C2004AC /* lwsync */" ::: "memory" + ); +} + +static OF_INLINE void +of_memory_barrier_release(void) +{ + __asm__ __volatile__ ( + ".long 0x7C2004AC /* lwsync */" ::: "memory" + ); +} ADDED src/OFAtomic_sync_builtins.h Index: src/OFAtomic_sync_builtins.h ================================================================== --- src/OFAtomic_sync_builtins.h +++ src/OFAtomic_sync_builtins.h @@ -0,0 +1,147 @@ +/* + * 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. + */ + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return __sync_add_and_fetch(p, i); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return __sync_add_and_fetch(p, i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __sync_add_and_fetch(p, (void *)i); +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return __sync_sub_and_fetch(p, i); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return __sync_sub_and_fetch(p, i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __sync_sub_and_fetch(p, (void *)i); +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return __sync_add_and_fetch(p, 1); +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return __sync_add_and_fetch(p, 1); +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return __sync_sub_and_fetch(p, 1); +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return __sync_sub_and_fetch(p, 1); +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __sync_or_and_fetch(p, i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __sync_or_and_fetch(p, i); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __sync_and_and_fetch(p, i); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __sync_and_and_fetch(p, i); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __sync_xor_and_fetch(p, i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __sync_xor_and_fetch(p, i); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + return __sync_bool_compare_and_swap(p, o, n); +} + +static OF_INLINE bool +OFAtomicInt32CompAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + return __sync_bool_compare_and_swap(p, o, n); +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + return __sync_bool_compare_and_swap(p, o, n); +} + +static OF_INLINE void +of_memory_barrier(void) +{ + __sync_synchronize(); +} + +static OF_INLINE void +of_memory_barrier_acquire(void) +{ + __sync_synchronize(); +} + +static OF_INLINE void +of_memory_barrier_release(void) +{ + __sync_synchronize(); +} ADDED src/OFAtomic_x86.h Index: src/OFAtomic_x86.h ================================================================== --- src/OFAtomic_x86.h +++ src/OFAtomic_x86.h @@ -0,0 +1,502 @@ +/* + * 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. + */ + +OF_ASSUME_NONNULL_BEGIN + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "lock\n\t" + "xaddq %0, %2\n\t" + "addq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#if defined(OF_X86_64) + __asm__ __volatile__ ( + "lock\n\t" + "xaddq %0, %2\n\t" + "addq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#elif defined(OF_X86) + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#endif +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "negq %0\n\t" + "lock\n\t" + "xaddq %0, %2\n\t" + "subq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#if defined(OF_X86_64) + __asm__ __volatile__ ( + "negq %0\n\t" + "lock\n\t" + "xaddq %0, %2\n\t" + "subq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#elif defined(OF_X86) + __asm__ __volatile__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#endif +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + int i; + + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "xorl %0, %0\n\t" + "incl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "incl %0" + : "=&r"(i) + : "m"(*p) + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "xorq %0, %0\n\t" + "incq %0\n\t" + "lock\n\t" + "xaddq %0, %1\n\t" + "incq %0" + : "=&r"(i) + : "m"(*p) + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "xorl %0, %0\n\t" + "incl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "incl %0" + : "=&r"(i) + : "m"(*p) + ); + + return i; +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + int i; + + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "xorl %0, %0\n\t" + "decl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "decl %0" + : "=&r"(i) + : "m"(*p) + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "xorq %0, %0\n\t" + "decq %0\n\t" + "lock\n\t" + "xaddq %0, %1\n\t" + "decq %0" + : "=&r"(i) + : "m"(*p) + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "xorl %0, %0\n\t" + "decl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "decl %0" + : "=&r"(i) + : "m"(*p) + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "orl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %0, %%rax\n\t" + "orq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax", "cc" + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "orl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "andl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %0, %%rax\n\t" + "andq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax", "cc" + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "andl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "xorl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %0, %%rax\n\t" + "xorq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax", "cc" + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "xorl %1, %0\n\t" + "lock\n\t" + "cmpxchgl %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); + + return i; +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + int r; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchg %2, %3\n\t" + "sete %b0\n\t" + "movzbl %b0, %0" + : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ + : "r"(n), "m"(*p) + : "cc" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + int r; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchg %2, %3\n\t" + "sete %b0\n\t" + "movzbl %b0, %0" + : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ + : "r"(n), "m"(*p) + : "cc" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + int r; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchg %2, %3\n\t" + "sete %b0\n\t" + "movzbl %b0, %0" + : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ + : "r"(n), "m"(*p) + : "cc" + ); + + return r; +} + +static OF_INLINE void +of_memory_barrier(void) +{ + __asm__ __volatile__ ( + "mfence" ::: "memory" + ); +} + +static OF_INLINE void +of_memory_barrier_acquire(void) +{ + __asm__ __volatile__ ("" ::: "memory"); +} + +static OF_INLINE void +of_memory_barrier_release(void) +{ + __asm__ __volatile__ ("" ::: "memory"); +} + +OF_ASSUME_NONNULL_END ADDED src/OFBase64.h Index: src/OFBase64.h ================================================================== --- src/OFBase64.h +++ src/OFBase64.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; +@class OFMutableData; + +#ifdef __cplusplus +extern "C" { +#endif +extern OFString *OFBase64Encode(const void *, size_t); +extern bool OFBase64Decode(OFMutableData *, const char *, size_t); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFBase64.m Index: src/OFBase64.m ================================================================== --- src/OFBase64.m +++ src/OFBase64.m @@ -0,0 +1,156 @@ +/* + * 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" + +#import "OFBase64.h" +#import "OFString.h" +#import "OFData.h" + +static const unsigned char encodeTable[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; + +static const signed char decodeTable[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, -1, -1, -1, -1, -1 +}; + +OFString * +OFBase64Encode(const void *data, size_t length) +{ + OFMutableString *ret = [OFMutableString string]; + uint8_t *buffer = (uint8_t *)data; + size_t i; + uint8_t rest; + char tb[4]; + uint32_t sb; + + rest = length % 3; + + for (i = 0; i < length - rest; i += 3) { + sb = (buffer[i] << 16) | (buffer[i + 1] << 8) | buffer[i + 2]; + + tb[0] = encodeTable[(sb & 0xFC0000) >> 18]; + tb[1] = encodeTable[(sb & 0x03F000) >> 12]; + tb[2] = encodeTable[(sb & 0x000FC0) >> 6]; + tb[3] = encodeTable[sb & 0x00003F]; + + [ret appendCString: tb + encoding: OFStringEncodingASCII + length: 4]; + } + + switch (rest) { + case 1: + tb[0] = encodeTable[buffer[i] >> 2]; + tb[1] = encodeTable[(buffer[i] & 3) << 4]; + tb[2] = tb[3] = '='; + + [ret appendCString: tb + encoding: OFStringEncodingASCII + length: 4]; + + break; + case 2: + sb = (buffer[i] << 16) | (buffer[i + 1] << 8); + + tb[0] = encodeTable[(sb & 0xFC0000) >> 18]; + tb[1] = encodeTable[(sb & 0x03F000) >> 12]; + tb[2] = encodeTable[(sb & 0x000FC0) >> 6]; + tb[3] = '='; + + [ret appendCString: tb + encoding: OFStringEncodingASCII + length: 4]; + + break; + } + + [ret makeImmutable]; + + return ret; +} + +bool +OFBase64Decode(OFMutableData *data, const char *string, size_t length) +{ + const uint8_t *buffer = (const uint8_t *)string; + size_t i; + + if ((length & 3) != 0) + return false; + + if (data.itemSize != 1) + return false; + + for (i = 0; i < length; i += 4) { + uint32_t sb = 0; + uint8_t count = 3; + char db[3]; + int8_t tmp; + + if (buffer[i] > 0x7F || buffer[i + 1] > 0x7F || + buffer[i + 2] > 0x7F || buffer[i + 3] > 0x7F) + return false; + + if (buffer[i] == '=' || buffer[i + 1] == '=' || + (buffer[i + 2] == '=' && buffer[i + 3] != '=')) + return false; + + if (buffer[i + 2] == '=') + count--; + if (buffer[i + 3] == '=') + count--; + + if ((tmp = decodeTable[buffer[i]]) == -1) + return false; + + sb |= tmp << 18; + + if ((tmp = decodeTable[buffer[i + 1]]) == -1) + return false; + + sb |= tmp << 12; + + if ((tmp = decodeTable[buffer[i + 2]]) == -1) + return false; + + sb |= tmp << 6; + + if ((tmp = decodeTable[buffer[i + 3]]) == -1) + return false; + + sb |= tmp; + + db[0] = (sb & 0xFF0000) >> 16; + db[1] = (sb & 0x00FF00) >> 8; + db[2] = sb & 0x0000FF; + + [data addItems: db count: count]; + } + + return true; +} Index: src/OFBlock.m ================================================================== --- src/OFBlock.m +++ src/OFBlock.m @@ -18,26 +18,25 @@ #include #include #include #import "OFBlock.h" +#ifdef OF_HAVE_ATOMIC_OPS +# import "OFAtomic.h" +#endif +#ifdef OF_HAVE_THREADS +# import "OFPlainMutex.h" +#endif #import "OFAllocFailedException.h" #import "OFInitializationFailedException.h" #if defined(OF_OBJFW_RUNTIME) # import "runtime/private.h" #endif -#ifdef OF_HAVE_ATOMIC_OPS -# import "atomic.h" -#endif -#ifdef OF_HAVE_THREADS -# import "mutex.h" -#endif - -struct block { +struct Block { Class isa; int flags; int reserved; void (*invoke)(void *block, ...); struct { @@ -47,13 +46,13 @@ void (*_Nullable dispose_helper)(void *src); const char *signature; } *descriptor; }; -struct byref { +struct Byref { Class isa; - struct byref *forwarding; + struct Byref *forwarding; int flags; int size; void (*byref_keep)(void *dest, void *src); void (*byref_dispose)(void *); }; @@ -87,11 +86,11 @@ sizeof(_NSConcreteStackBlock_metaclass), NULL, NULL }; struct objc_class _NSConcreteStackBlock = { &_NSConcreteStackBlock_metaclass, (Class)(void *)"OFBlock", - "OFStackBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(struct block), + "OFStackBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(struct Block), NULL, NULL }; static struct objc_class _NSConcreteGlobalBlock_metaclass = { Nil, Nil, "OFGlobalBlock", 8, OBJC_CLASS_INFO_METACLASS, @@ -98,11 +97,11 @@ sizeof(_NSConcreteGlobalBlock_metaclass), NULL, NULL }; struct objc_class _NSConcreteGlobalBlock = { &_NSConcreteGlobalBlock_metaclass, (Class)(void *)"OFBlock", - "OFGlobalBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(struct block), + "OFGlobalBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(struct Block), NULL, NULL }; static struct objc_class _NSConcreteMallocBlock_metaclass = { Nil, Nil, "OFMallocBlock", 8, OBJC_CLASS_INFO_METACLASS, @@ -109,11 +108,11 @@ sizeof(_NSConcreteMallocBlock_metaclass), NULL, NULL }; struct objc_class _NSConcreteMallocBlock = { &_NSConcreteMallocBlock_metaclass, (Class)(void *)"OFBlock", - "OFMallocBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(struct block), + "OFMallocBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(struct Block), NULL, NULL }; static struct { unsigned long unknown; @@ -174,14 +173,14 @@ #endif void * _Block_copy(const void *block_) { - struct block *block = (struct block *)block_; + struct Block *block = (struct Block *)block_; if ([(id)block isMemberOfClass: (Class)&_NSConcreteStackBlock]) { - struct block *copy; + struct Block *copy; if ((copy = malloc(block->descriptor->size)) == NULL) { alloc_failed_exception.isa = [OFAllocFailedException class]; @throw (OFAllocFailedException *) @@ -214,11 +213,11 @@ } void _Block_release(const void *block_) { - struct block *block = (struct block *)block_; + struct Block *block = (struct Block *)block_; if (object_getClass((id)block) != (Class)&_NSConcreteMallocBlock) return; #ifdef OF_HAVE_ATOMIC_OPS @@ -256,19 +255,19 @@ if (src_ == NULL) return; switch (flags) { case OF_BLOCK_FIELD_IS_BLOCK: - *(struct block **)dst_ = _Block_copy(src_); + *(struct Block **)dst_ = _Block_copy(src_); break; case OF_BLOCK_FIELD_IS_OBJECT: if (!(flags_ & OF_BLOCK_BYREF_CALLER)) *(id *)dst_ = [(id)src_ retain]; break; case OF_BLOCK_FIELD_IS_BYREF:; - struct byref *src = (struct byref *)src_; - struct byref **dst = (struct byref **)dst_; + struct Byref *src = (struct Byref *)src_; + struct Byref **dst = (struct Byref **)dst_; src = src->forwarding; if ((src->flags & OF_BLOCK_REFCOUNT_MASK) == 0) { if ((*dst = malloc(src->size)) == NULL) { @@ -340,11 +339,11 @@ case OF_BLOCK_FIELD_IS_OBJECT: if (!(flags_ & OF_BLOCK_BYREF_CALLER)) [(id)object_ release]; break; case OF_BLOCK_FIELD_IS_BYREF:; - struct byref *object = (struct byref *)object_; + struct Byref *object = (struct Byref *)object_; object = object->forwarding; #ifdef OF_HAVE_ATOMIC_OPS if ((OFAtomicIntDecrease(&object->flags) & @@ -473,11 +472,11 @@ } - (unsigned int)retainCount { if ([self isMemberOfClass: (Class)&_NSConcreteMallocBlock]) - return ((struct block *)self)->flags & + return ((struct Block *)self)->flags & OF_BLOCK_REFCOUNT_MASK; return OF_RETAIN_COUNT_MAX; } ADDED src/OFCRC16.h Index: src/OFCRC16.h ================================================================== --- src/OFCRC16.h +++ src/OFCRC16.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +#ifdef __cplusplus +extern "C" { +#endif +extern uint16_t OFCRC16(uint16_t crc, const void *_Nonnull bytes, + size_t length); +#ifdef __cplusplus +} +#endif ADDED src/OFCRC16.m Index: src/OFCRC16.m ================================================================== --- src/OFCRC16.m +++ src/OFCRC16.m @@ -0,0 +1,35 @@ +/* + * 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" + +#import "OFCRC16.h" + +#define CRC16_MAGIC 0xA001 + +uint16_t +OFCRC16(uint16_t crc, const void *bytes_, size_t length) +{ + const unsigned char *bytes = bytes_; + + for (size_t i = 0; i < length; i++) { + crc ^= bytes[i]; + + for (uint8_t j = 0; j < 8; j++) + crc = (crc >> 1) ^ (CRC16_MAGIC & (~(crc & 1) + 1)); + } + + return crc; +} ADDED src/OFCRC32.h Index: src/OFCRC32.h ================================================================== --- src/OFCRC32.h +++ src/OFCRC32.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +#ifdef __cplusplus +extern "C" { +#endif +extern uint32_t OFCRC32(uint32_t crc, const void *_Nonnull bytes, + size_t length); +#ifdef __cplusplus +} +#endif ADDED src/OFCRC32.m Index: src/OFCRC32.m ================================================================== --- src/OFCRC32.m +++ src/OFCRC32.m @@ -0,0 +1,35 @@ +/* + * 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" + +#import "OFCRC32.h" + +#define CRC32_MAGIC 0xEDB88320 + +uint32_t +OFCRC32(uint32_t crc, const void *bytes_, size_t length) +{ + const unsigned char *bytes = bytes_; + + for (size_t i = 0; i < length; i++) { + crc ^= bytes[i]; + + for (uint8_t j = 0; j < 8; j++) + crc = (crc >> 1) ^ (CRC32_MAGIC & (~(crc & 1) + 1)); + } + + return crc; +} Index: src/OFCharacterSet.m ================================================================== --- src/OFCharacterSet.m +++ src/OFCharacterSet.m @@ -16,14 +16,13 @@ #include "config.h" #import "OFCharacterSet.h" #import "OFBitSetCharacterSet.h" #import "OFInvertedCharacterSet.h" +#import "OFOnce.h" #import "OFRangeCharacterSet.h" -#import "once.h" - @interface OFPlaceholderCharacterSet: OFCharacterSet @end @interface OFWhitespaceCharacterSet: OFCharacterSet @end Index: src/OFColor.m ================================================================== --- src/OFColor.m +++ src/OFColor.m @@ -14,12 +14,11 @@ */ #include "config.h" #import "OFColor.h" - -#import "once.h" +#import "OFOnce.h" #import "OFInvalidArgumentException.h" @implementation OFColor #define PREDEFINED_COLOR(name, redValue, greenValue, blueValue) \ Index: src/OFCondition.h ================================================================== --- src/OFCondition.h +++ src/OFCondition.h @@ -12,12 +12,11 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFMutex.h" - -#import "condition.h" +#import "OFPlainCondition.h" OF_ASSUME_NONNULL_BEGIN @class OFDate; Index: src/OFDNSResolverSettings.m ================================================================== --- src/OFDNSResolverSettings.m +++ src/OFDNSResolverSettings.m @@ -22,10 +22,11 @@ #import "OFCharacterSet.h" #import "OFDate.h" #import "OFDictionary.h" #import "OFFile.h" #import "OFLocale.h" +#import "OFSocket+Private.h" #import "OFString.h" #ifdef OF_WINDOWS # import "OFWindowsRegistryKey.h" #endif @@ -51,12 +52,10 @@ # include # include # include #endif -#import "socket_helpers.h" - #if defined(OF_HAIKU) # define HOSTS_PATH @"/system/settings/network/hosts" # define RESOLV_CONF_PATH @"/system/settings/network/resolv.conf" #elif defined(OF_AMIGAOS4) # define HOSTS_PATH @"DEVS:Internet/hosts" Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -12,14 +12,13 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" +#import "OFSocket.h" #import "OFString.h" -#import "socket.h" - OF_ASSUME_NONNULL_BEGIN /** @file */ @class OFArray OF_GENERIC(ObjectType); Index: src/OFData.m ================================================================== --- src/OFData.m +++ src/OFData.m @@ -18,10 +18,11 @@ #include #include #include #import "OFData.h" +#import "OFBase64.h" #import "OFDictionary.h" #ifdef OF_HAVE_FILES # import "OFFile.h" # import "OFFileManager.h" #endif @@ -38,12 +39,10 @@ #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" -#import "base64.h" - /* References for static linking */ void _references_to_categories_of_OFData(void) { _OFData_CryptographicHashing_reference = 1; @@ -332,11 +331,11 @@ } self = [(OFMutableData *)self initWithCapacity: string.length / 3]; @try { - if (!of_base64_decode((OFMutableData *)self, + if (!OFBase64Decode((OFMutableData *)self, [string cStringWithEncoding: OFStringEncodingASCII], [string cStringLengthWithEncoding: OFStringEncodingASCII])) @throw [OFInvalidFormatException exception]; } @catch (id e) { [self release]; @@ -539,11 +538,11 @@ return ret; } - (OFString *)stringByBase64Encoding { - return of_base64_encode(_items, _count * _itemSize); + return OFBase64Encode(_items, _count * _itemSize); } - (OFRange)rangeOfData: (OFData *)data options: (OFDataSearchOptions)options range: (OFRange)range @@ -622,11 +621,11 @@ pool = objc_autoreleasePoolPush(); element = [OFXMLElement elementWithName: self.className namespace: OF_SERIALIZATION_NS - stringValue: of_base64_encode(_items, _count * _itemSize)]; + stringValue: OFBase64Encode(_items, _count * _itemSize)]; [element retain]; objc_autoreleasePoolPop(pool); Index: src/OFDatagramSocket.h ================================================================== --- src/OFDatagramSocket.h +++ src/OFDatagramSocket.h @@ -14,12 +14,11 @@ */ #import "OFObject.h" #import "OFKernelEventObserver.h" #import "OFRunLoop.h" - -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN /** @file */ Index: src/OFDatagramSocket.m ================================================================== --- src/OFDatagramSocket.m +++ src/OFDatagramSocket.m @@ -26,12 +26,14 @@ # include #endif #import "OFDatagramSocket.h" #import "OFData.h" -#import "OFRunLoop+Private.h" #import "OFRunLoop.h" +#import "OFRunLoop+Private.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFGetOptionFailedException.h" #import "OFInitializationFailedException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" @@ -38,13 +40,10 @@ #import "OFReadFailedException.h" #import "OFSetOptionFailedException.h" #import "OFSetOptionFailedException.h" #import "OFWriteFailedException.h" -#import "socket.h" -#import "socket_helpers.h" - @implementation OFDatagramSocket @synthesize delegate = _delegate; + (void)initialize { Index: src/OFDate.m ================================================================== --- src/OFDate.m +++ src/OFDate.m @@ -28,10 +28,11 @@ #import "OFDictionary.h" #import "OFMessagePackExtension.h" #ifdef OF_HAVE_THREADS # import "OFMutex.h" #endif +#import "OFStrPTime.h" #import "OFString.h" #import "OFSystemInfo.h" #import "OFXMLElement.h" #import "OFInitializationFailedException.h" @@ -38,12 +39,10 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#import "of_strptime.h" - #ifdef OF_AMIGAOS_M68K /* amiga-gcc does not have trunc() */ # define trunc(x) ((int64_t)(x)) #endif @@ -447,11 +446,11 @@ void *pool = objc_autoreleasePoolPush(); const char *UTF8String = string.UTF8String; struct tm tm = { .tm_isdst = -1 }; short tz = 0; - if (of_strptime(UTF8String, format.UTF8String, &tm, &tz) != + if (OFStrPTime(UTF8String, format.UTF8String, &tm, &tz) != UTF8String + string.UTF8StringLength) @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); @@ -463,18 +462,18 @@ { void *pool = objc_autoreleasePoolPush(); const char *UTF8String = string.UTF8String; struct tm tm = { .tm_isdst = -1 }; /* - * of_strptime() can never set this to SHRT_MAX, no matter what is + * OFStrPTime() can never set this to SHRT_MAX, no matter what is * passed to it, so this is a safe way to figure out if the date * contains a time zone. */ short tz = SHRT_MAX; OFTimeInterval seconds; - if (of_strptime(UTF8String, format.UTF8String, &tm, &tz) != + if (OFStrPTime(UTF8String, format.UTF8String, &tm, &tz) != UTF8String + string.UTF8StringLength) @throw [OFInvalidFormatException exception]; if (tz == SHRT_MAX) { #ifdef OF_WINDOWS Index: src/OFGZIPStream.m ================================================================== --- src/OFGZIPStream.m +++ src/OFGZIPStream.m @@ -14,14 +14,13 @@ */ #include "config.h" #import "OFGZIPStream.h" -#import "OFInflateStream.h" +#import "OFCRC32.h" #import "OFDate.h" - -#import "crc32.h" +#import "OFInflateStream.h" #import "OFChecksumMismatchException.h" #import "OFInvalidFormatException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" @@ -237,11 +236,11 @@ if (!_inflateStream.atEndOfStream) { size_t bytesRead = [_inflateStream readIntoBuffer: buffer length: length]; - _CRC32 = of_crc32(_CRC32, buffer, bytesRead); + _CRC32 = OFCRC32(_CRC32, buffer, bytesRead); _uncompressedSize += bytesRead; return bytesRead; } Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -26,10 +26,11 @@ #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" #import "OFKernelEventObserver.h" #import "OFNumber.h" #import "OFRunLoop.h" +#import "OFSocket+Private.h" #import "OFString.h" #import "OFTCPSocket.h" #import "OFURL.h" #import "OFAlreadyConnectedException.h" @@ -45,12 +46,10 @@ #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" #import "OFUnsupportedVersionException.h" #import "OFWriteFailedException.h" -#import "socket_helpers.h" - #define REDIRECTS_DEFAULT 10 OF_DIRECT_MEMBERS @interface OFHTTPClientRequestHandler: OFObject { Index: src/OFHTTPRequest.h ================================================================== --- src/OFHTTPRequest.h +++ src/OFHTTPRequest.h @@ -12,14 +12,13 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" +#import "OFSocket.h" #import "OFString.h" -#import "socket.h" - OF_ASSUME_NONNULL_BEGIN @class OFURL; @class OFDictionary OF_GENERIC(KeyType, ObjectType); @class OFData; Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -24,10 +24,11 @@ #import "OFDate.h" #import "OFDictionary.h" #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" #import "OFNumber.h" +#import "OFSocket+Private.h" #import "OFTCPSocket.h" #import "OFTLSSocket.h" #import "OFThread.h" #import "OFTimer.h" #import "OFURL.h" @@ -41,12 +42,10 @@ #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" #import "OFWriteFailedException.h" -#import "socket_helpers.h" - #define BUFFER_SIZE 1024 /* * FIXME: Key normalization replaces headers like "DNT" with "Dnt". * FIXME: Errors are not reported to the user. Index: src/OFHostAddressResolver.h ================================================================== --- src/OFHostAddressResolver.h +++ src/OFHostAddressResolver.h @@ -14,12 +14,11 @@ */ #import "OFObject.h" #import "OFDNSResolver.h" #import "OFRunLoop.h" - -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN @class OFDNSResolverSettings; @class OFDNSResourceRecord; ADDED src/OFHuffmanTree.h Index: src/OFHuffmanTree.h ================================================================== --- src/OFHuffmanTree.h +++ src/OFHuffmanTree.h @@ -0,0 +1,66 @@ +/* + * 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 +#include + +#import "macros.h" + +#import "OFInvalidFormatException.h" + +OF_ASSUME_NONNULL_BEGIN + +typedef struct OFHuffmanTree { + struct OFHuffmanTree *_Nullable leaves[2]; + uint16_t value; +} OFHuffmanTree; + +/* Inlined for performance. */ +static OF_INLINE bool +OFHuffmanTreeWalk(id _Nullable stream, + bool (*bitReader)(id _Nullable, uint16_t *_Nonnull, uint8_t), + OFHuffmanTree *_Nonnull *_Nonnull tree, uint16_t *_Nonnull value) +{ + struct OFHuffmanTree *iter = *tree; + uint16_t bits; + + while (iter->value == 0xFFFF) { + if OF_UNLIKELY (!bitReader(stream, &bits, 1)) { + *tree = iter; + return false; + } + + if OF_UNLIKELY (iter->leaves[bits] == NULL) + @throw [OFInvalidFormatException exception]; + + iter = iter->leaves[bits]; + } + + *value = iter->value; + return true; +} + +#ifdef __cplusplus +extern "C" { +#endif +extern OFHuffmanTree *_Nonnull OFHuffmanTreeNew(uint8_t lengths[_Nonnull], + uint16_t count); +extern OFHuffmanTree *_Nonnull OFHuffmanTreeNewSingle(uint16_t value); +extern void OFHuffmanTreeFree(OFHuffmanTree *_Nonnull tree); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFHuffmanTree.m Index: src/OFHuffmanTree.m ================================================================== --- src/OFHuffmanTree.m +++ src/OFHuffmanTree.m @@ -0,0 +1,129 @@ +/* + * 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 +#include + +#import "OFHuffmanTree.h" + +#import "OFInvalidFormatException.h" +#import "OFOutOfMemoryException.h" + +static OFHuffmanTree * +newTree(void) +{ + OFHuffmanTree *tree; + + tree = OFAllocMemory(1, sizeof(*tree)); + tree->leaves[0] = tree->leaves[1] = NULL; + tree->value = 0xFFFF; + + return tree; +} + +static void +insertTree(OFHuffmanTree *tree, uint16_t code, uint8_t length, uint16_t value) +{ + while (length > 0) { + uint8_t bit; + + length--; + bit = (code & (1u << length)) >> length; + + if (tree->leaves[bit] == NULL) + tree->leaves[bit] = newTree(); + + tree = tree->leaves[bit]; + } + + tree->value = value; +} + +OFHuffmanTree * +OFHuffmanTreeNew(uint8_t lengths[], uint16_t count) +{ + OFHuffmanTree *tree; + uint16_t *lengthCount = NULL; + uint16_t code, maxCode = 0, *nextCode = NULL; + uint_fast8_t maxBit = 0; + + @try { + for (uint16_t i = 0; i < count; i++) { + uint_fast8_t length = lengths[i]; + + if OF_UNLIKELY (length > maxBit) { + lengthCount = OFResizeMemory(lengthCount, + length + 1, sizeof(uint16_t)); + nextCode = OFResizeMemory(nextCode, + length + 1, sizeof(uint16_t)); + + for (uint_fast8_t j = maxBit + 1; j <= length; + j++) { + lengthCount[j] = 0; + nextCode[j] = 0; + } + + maxBit = length; + } + + if (length > 0) { + lengthCount[length]++; + maxCode = i; + } + } + + code = 0; + for (size_t i = 1; i <= maxBit; i++) { + code = (code + lengthCount[i - 1]) << 1; + nextCode[i] = code; + } + + tree = newTree(); + + for (uint16_t i = 0; i <= maxCode; i++) { + uint8_t length = lengths[i]; + + if (length > 0) + insertTree(tree, nextCode[length]++, length, i); + } + } @finally { + OFFreeMemory(lengthCount); + OFFreeMemory(nextCode); + } + + return tree; +} + +OFHuffmanTree * +OFHuffmanTreeNewSingle(uint16_t value) +{ + OFHuffmanTree *tree = newTree(); + + tree->value = value; + + return tree; +} + +void +OFHuffmanTreeFree(OFHuffmanTree *tree) +{ + for (uint_fast8_t i = 0; i < 2; i++) + if OF_LIKELY (tree->leaves[i] != NULL) + OFHuffmanTreeFree(tree->leaves[i]); + + OFFreeMemory(tree); +} Index: src/OFIPXSocket.m ================================================================== --- src/OFIPXSocket.m +++ src/OFIPXSocket.m @@ -20,17 +20,16 @@ #ifdef HAVE_FCNTL_H # include #endif #import "OFIPXSocket.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFAlreadyConnectedException.h" #import "OFBindFailedException.h" -#import "socket.h" -#import "socket_helpers.h" - @implementation OFIPXSocket @dynamic delegate; - (OFSocketAddress)bindToPort: (uint16_t)port packetType: (uint8_t)packetType { Index: src/OFInflate64Stream.h ================================================================== --- src/OFInflate64Stream.h +++ src/OFInflate64Stream.h @@ -12,15 +12,16 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFStream.h" +#import "OFHuffmanTree.h" #import "OFKernelEventObserver.h" OF_ASSUME_NONNULL_BEGIN -#define OF_INFLATE64_STREAM_BUFFER_SIZE 4096 +#define OFInflate64StreamBufferSize 4096 /** * @class OFInflate64Stream OFInflate64Stream.h ObjFW/OFInflate64Stream.h * * @note This class only conforms to OFReadyForReadingObserving if the @@ -31,11 +32,11 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFInflate64Stream: OFStream { OFStream *_stream; - unsigned char _buffer[OF_INFLATE64_STREAM_BUFFER_SIZE]; + unsigned char _buffer[OFInflate64StreamBufferSize]; uint16_t _bufferIndex, _bufferLength; uint8_t _byte; uint8_t _bitIndex, _savedBitsLength; uint16_t _savedBits; unsigned char *_Nullable _slidingWindow; @@ -48,23 +49,23 @@ } uncompressedHeader; struct { uint16_t position, length; } uncompressed; struct { - struct of_huffman_tree *_Nullable litLenTree; - struct of_huffman_tree *_Nullable distTree; - struct of_huffman_tree *_Nullable codeLenTree; - struct of_huffman_tree *_Nullable treeIter; + OFHuffmanTree *_Nullable litLenTree; + OFHuffmanTree *_Nullable distTree; + OFHuffmanTree *_Nullable codeLenTree; + OFHuffmanTree *_Nullable treeIter; uint8_t *_Nullable lengths; uint16_t receivedCount; uint8_t value, litLenCodesCount, distCodesCount; uint8_t codeLenCodesCount; } huffmanTree; struct { - struct of_huffman_tree *_Nullable litLenTree; - struct of_huffman_tree *_Nullable distTree; - struct of_huffman_tree *_Nullable treeIter; + OFHuffmanTree *_Nullable litLenTree; + OFHuffmanTree *_Nullable distTree; + OFHuffmanTree *_Nullable treeIter; int state; uint16_t value, length, distance, extraBits; } huffman; } _context; bool _inLastBlock, _atEndOfStream; Index: src/OFInflateStream.h ================================================================== --- src/OFInflateStream.h +++ src/OFInflateStream.h @@ -12,15 +12,16 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFStream.h" +#import "OFHuffmanTree.h" #import "OFKernelEventObserver.h" OF_ASSUME_NONNULL_BEGIN -#define OF_INFLATE_STREAM_BUFFER_SIZE 4096 +#define OFInflateStreamBufferSize 4096 /** * @class OFInflateStream OFInflateStream.h ObjFW/OFInflateStream.h * * @note This class only conforms to OFReadyForReadingObserving if the @@ -31,11 +32,11 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFInflateStream: OFStream { OFStream *_stream; - unsigned char _buffer[OF_INFLATE_STREAM_BUFFER_SIZE]; + unsigned char _buffer[OFInflateStreamBufferSize]; uint16_t _bufferIndex, _bufferLength; uint8_t _byte; uint8_t _bitIndex, _savedBitsLength; uint16_t _savedBits; unsigned char *_Nullable _slidingWindow; @@ -48,23 +49,23 @@ } uncompressedHeader; struct { uint16_t position, length; } uncompressed; struct { - struct of_huffman_tree *_Nullable litLenTree; - struct of_huffman_tree *_Nullable distTree; - struct of_huffman_tree *_Nullable codeLenTree; - struct of_huffman_tree *_Nullable treeIter; + OFHuffmanTree *_Nullable litLenTree; + OFHuffmanTree *_Nullable distTree; + OFHuffmanTree *_Nullable codeLenTree; + OFHuffmanTree *_Nullable treeIter; uint8_t *_Nullable lengths; uint16_t receivedCount; uint8_t value, litLenCodesCount, distCodesCount; uint8_t codeLenCodesCount; } huffmanTree; struct { - struct of_huffman_tree *_Nullable litLenTree; - struct of_huffman_tree *_Nullable distTree; - struct of_huffman_tree *_Nullable treeIter; + OFHuffmanTree *_Nullable litLenTree; + OFHuffmanTree *_Nullable distTree; + OFHuffmanTree *_Nullable treeIter; int state; uint16_t value, length, distance, extraBits; } huffman; } _context; bool _inLastBlock, _atEndOfStream; Index: src/OFInflateStream.m ================================================================== --- src/OFInflateStream.m +++ src/OFInflateStream.m @@ -24,30 +24,29 @@ # import "OFInflateStream.h" #else # import "OFInflate64Stream.h" # define OFInflateStream OFInflate64Stream #endif - -#import "huffman_tree.h" +#import "OFHuffmanTree.h" #import "OFInitializationFailedException.h" #import "OFInvalidFormatException.h" #import "OFNotOpenException.h" #import "OFOutOfMemoryException.h" #ifndef OF_INFLATE64_STREAM_M -# define BUFFER_SIZE OF_INFLATE_STREAM_BUFFER_SIZE +# define bufferSize OFInflateStreamBufferSize #else -# define BUFFER_SIZE OF_INFLATE64_STREAM_BUFFER_SIZE +# define bufferSize OFInflate64StreamBufferSize #endif enum state { - BLOCK_HEADER, - UNCOMPRESSED_BLOCK_HEADER, - UNCOMPRESSED_BLOCK, - HUFFMAN_TREE, - HUFFMAN_BLOCK + StateBlockHeader, + StateUncompressedBlockHeader, + StateUncompressedBlock, + StateHuffmanTree, + StateHuffmanBlock }; enum huffman_state { WRITE_VALUE, AWAIT_CODE, @@ -98,11 +97,11 @@ }; #endif static const uint8_t codeLengthsOrder[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; -static struct of_huffman_tree *fixedLitLenTree, *fixedDistTree; +static OFHuffmanTree *fixedLitLenTree, *fixedDistTree; @implementation OFInflateStream static OF_INLINE bool tryReadBits(OFInflateStream *stream, uint16_t *bits, uint8_t count) { @@ -117,11 +116,11 @@ stream->_byte = stream->_buffer[stream->_bufferIndex++]; else { size_t length = [stream->_stream readIntoBuffer: stream->_buffer - length: BUFFER_SIZE]; + length: bufferSize]; if OF_UNLIKELY (length < 1) { stream->_savedBits = ret; stream->_savedBitsLength = i; return false; @@ -159,16 +158,16 @@ for (uint16_t i = 256; i <= 279; i++) lengths[i] = 7; for (uint16_t i = 280; i <= 287; i++) lengths[i] = 8; - fixedLitLenTree = of_huffman_tree_construct(lengths, 288); + fixedLitLenTree = OFHuffmanTreeNew(lengths, 288); for (uint16_t i = 0; i <= 31; i++) lengths[i] = 5; - fixedDistTree = of_huffman_tree_construct(lengths, 32); + fixedDistTree = OFHuffmanTreeNew(lengths, 32); } + (instancetype)streamWithStream: (OFStream *)stream { return [[[self alloc] initWithStream: stream] autorelease]; @@ -208,23 +207,22 @@ if (_stream != nil) [self close]; OFFreeMemory(_slidingWindow); - if (_state == HUFFMAN_TREE) { + if (_state == StateHuffmanTree) { OFFreeMemory(_context.huffmanTree.lengths); if (_context.huffmanTree.codeLenTree != NULL) - of_huffman_tree_release( - _context.huffmanTree.codeLenTree); + OFHuffmanTreeFree(_context.huffmanTree.codeLenTree); } - if (_state == HUFFMAN_TREE || _state == HUFFMAN_BLOCK) { + if (_state == StateHuffmanTree || _state == StateHuffmanBlock) { if (_context.huffman.litLenTree != fixedLitLenTree) - of_huffman_tree_release(_context.huffman.litLenTree); + OFHuffmanTreeFree(_context.huffman.litLenTree); if (_context.huffman.distTree != fixedDistTree) - of_huffman_tree_release(_context.huffman.distTree); + OFHuffmanTreeFree(_context.huffman.distTree); } [super dealloc]; } @@ -243,11 +241,11 @@ if (_atEndOfStream) return 0; start: switch ((enum state)_state) { - case BLOCK_HEADER: + case StateBlockHeader: if OF_UNLIKELY (_inLastBlock) { [_stream unreadFromBuffer: _buffer + _bufferIndex length: _bufferLength - _bufferIndex]; _bufferIndex = _bufferLength = 0; @@ -261,24 +259,24 @@ _inLastBlock = (bits & 1); switch (bits >> 1) { case 0: /* No compression */ - _state = UNCOMPRESSED_BLOCK_HEADER; + _state = StateUncompressedBlockHeader; _bitIndex = 8; _context.uncompressedHeader.position = 0; memset(_context.uncompressedHeader.length, 0, 4); break; case 1: /* Fixed Huffman */ - _state = HUFFMAN_BLOCK; + _state = StateHuffmanBlock; _context.huffman.state = AWAIT_CODE; _context.huffman.litLenTree = fixedLitLenTree; _context.huffman.distTree = fixedDistTree; _context.huffman.treeIter = fixedLitLenTree; break; case 2: /* Dynamic Huffman */ - _state = HUFFMAN_TREE; + _state = StateHuffmanTree; _context.huffmanTree.lengths = NULL; _context.huffmanTree.receivedCount = 0; _context.huffmanTree.value = 0xFE; _context.huffmanTree.litLenCodesCount = 0xFF; _context.huffmanTree.distCodesCount = 0xFF; @@ -287,11 +285,11 @@ default: @throw [OFInvalidFormatException exception]; } goto start; - case UNCOMPRESSED_BLOCK_HEADER: + case StateUncompressedBlockHeader: #define CTX _context.uncompressedHeader /* FIXME: This can be done more efficiently than unreading */ [_stream unreadFromBuffer: _buffer + _bufferIndex length: _bufferLength - _bufferIndex]; _bufferIndex = _bufferLength = 0; @@ -305,11 +303,11 @@ if OF_UNLIKELY ((CTX.length[0] | (CTX.length[1] << 8)) != (uint16_t)~(CTX.length[2] | (CTX.length[3] << 8))) @throw [OFInvalidFormatException exception]; - _state = UNCOMPRESSED_BLOCK; + _state = StateUncompressedBlock; /* * Do not reorder! _context.uncompressed.position and * _context.uncompressedHeader.length overlap! */ @@ -317,11 +315,11 @@ CTX.length[0] | (CTX.length[1] << 8); _context.uncompressed.position = 0; goto start; #undef CTX - case UNCOMPRESSED_BLOCK: + case StateUncompressedBlock: #define CTX _context.uncompressed if OF_UNLIKELY (length == 0) return bytesWritten; tmp = (length < (size_t)CTX.length - CTX.position @@ -343,15 +341,15 @@ length -= tmp; bytesWritten += tmp; CTX.position += tmp; if OF_UNLIKELY (CTX.position == CTX.length) - _state = BLOCK_HEADER; + _state = StateBlockHeader; goto start; #undef CTX - case HUFFMAN_TREE: + case StateHuffmanTree: #define CTX _context.huffmanTree if OF_LIKELY (CTX.value == 0xFE) { if OF_LIKELY (CTX.litLenCodesCount == 0xFF) { if OF_UNLIKELY (!tryReadBits(self, &bits, 5)) return bytesWritten; @@ -388,12 +386,11 @@ } CTX.lengths[codeLengthsOrder[i]] = bits; } - CTX.codeLenTree = of_huffman_tree_construct( - CTX.lengths, 19); + CTX.codeLenTree = OFHuffmanTreeNew(CTX.lengths, 19); CTX.treeIter = CTX.codeLenTree; OFFreeMemory(CTX.lengths); CTX.lengths = NULL; CTX.receivedCount = 0; @@ -407,11 +404,11 @@ for (uint16_t i = CTX.receivedCount; i < CTX.litLenCodesCount + CTX.distCodesCount + 258;) { uint8_t j, count; if OF_LIKELY (CTX.value == 0xFF) { - if OF_UNLIKELY (!of_huffman_tree_walk(self, + if OF_UNLIKELY (!OFHuffmanTreeWalk(self, tryReadBits, &CTX.treeIter, &value)) { CTX.receivedCount = i; return bytesWritten; } @@ -474,16 +471,16 @@ CTX.lengths[i++] = value; CTX.value = 0xFF; } - of_huffman_tree_release(CTX.codeLenTree); + OFHuffmanTreeFree(CTX.codeLenTree); CTX.codeLenTree = NULL; - CTX.litLenTree = of_huffman_tree_construct(CTX.lengths, + CTX.litLenTree = OFHuffmanTreeNew(CTX.lengths, CTX.litLenCodesCount + 257); - CTX.distTree = of_huffman_tree_construct( + CTX.distTree = OFHuffmanTreeNew( CTX.lengths + CTX.litLenCodesCount + 257, CTX.distCodesCount + 1); OFFreeMemory(CTX.lengths); @@ -490,17 +487,17 @@ /* * litLenTree and distTree are at the same location in * _context.huffman and _context.huffmanTree, thus no need to * set them. */ - _state = HUFFMAN_BLOCK; + _state = StateHuffmanBlock; _context.huffman.state = AWAIT_CODE; _context.huffman.treeIter = CTX.litLenTree; goto start; #undef CTX - case HUFFMAN_BLOCK: + case StateHuffmanBlock: #define CTX _context.huffman for (;;) { uint8_t extraBits, lengthCodeIndex; if OF_UNLIKELY (CTX.state == WRITE_VALUE) { @@ -530,11 +527,11 @@ CTX.treeIter = CTX.distTree; } /* Distance of length distance pair */ if (CTX.state == AWAIT_DISTANCE) { - if OF_UNLIKELY (!of_huffman_tree_walk(self, + if OF_UNLIKELY (!OFHuffmanTreeWalk(self, tryReadBits, &CTX.treeIter, &value)) return bytesWritten; if OF_UNLIKELY (value >= numDistanceCodes) @throw [OFInvalidFormatException @@ -592,22 +589,22 @@ CTX.state = AWAIT_CODE; CTX.treeIter = CTX.litLenTree; } - if OF_UNLIKELY (!of_huffman_tree_walk(self, tryReadBits, + if OF_UNLIKELY (!OFHuffmanTreeWalk(self, tryReadBits, &CTX.treeIter, &value)) return bytesWritten; /* End of block */ if OF_UNLIKELY (value == 256) { if (CTX.litLenTree != fixedLitLenTree) - of_huffman_tree_release(CTX.litLenTree); + OFHuffmanTreeFree(CTX.litLenTree); if (CTX.distTree != fixedDistTree) - of_huffman_tree_release(CTX.distTree); + OFHuffmanTreeFree(CTX.distTree); - _state = BLOCK_HEADER; + _state = StateBlockHeader; goto start; } /* Literal byte */ if OF_LIKELY (value < 256) { Index: src/OFKernelEventObserver.h ================================================================== --- src/OFKernelEventObserver.h +++ src/OFKernelEventObserver.h @@ -12,13 +12,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" - #ifdef OF_HAVE_SOCKETS -# import "socket.h" +# import "OFSocket.h" #endif #ifdef OF_AMIGAOS # include # include Index: src/OFKernelEventObserver.m ================================================================== --- src/OFKernelEventObserver.m +++ src/OFKernelEventObserver.m @@ -21,36 +21,34 @@ #import "OFKernelEventObserver.h" #import "OFArray.h" #import "OFData.h" #import "OFDate.h" -#import "OFStream.h" -#import "OFStream+Private.h" -#ifndef OF_HAVE_PIPE -# import "OFStreamSocket.h" +#ifdef HAVE_EPOLL +# import "OFEpollKernelEventObserver.h" #endif - #ifdef HAVE_KQUEUE # import "OFKqueueKernelEventObserver.h" #endif -#ifdef HAVE_EPOLL -# import "OFEpollKernelEventObserver.h" -#endif #ifdef HAVE_POLL # import "OFPollKernelEventObserver.h" #endif #ifdef HAVE_SELECT # import "OFSelectKernelEventObserver.h" #endif +#import "OFSocket.h" +#import "OFSocket+Private.h" +#import "OFStream.h" +#import "OFStream+Private.h" +#ifndef OF_HAVE_PIPE +# import "OFStreamSocket.h" +#endif #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" -#import "socket.h" -#import "socket_helpers.h" - #ifdef OF_AMIGAOS # include #endif enum { Index: src/OFLHAArchive.m ================================================================== --- src/OFLHAArchive.m +++ src/OFLHAArchive.m @@ -16,20 +16,19 @@ #include "config.h" #import "OFLHAArchive.h" #import "OFLHAArchiveEntry.h" #import "OFLHAArchiveEntry+Private.h" +#import "OFCRC16.h" #ifdef OF_HAVE_FILES # import "OFFile.h" #endif #import "OFLHADecompressingStream.h" #import "OFStream.h" #import "OFSeekableStream.h" #import "OFString.h" -#import "crc16.h" - #import "OFChecksumMismatchException.h" #import "OFInvalidArgumentException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" @@ -332,11 +331,11 @@ length = _toRead; ret = [_decompressedStream readIntoBuffer: buffer length: length]; _toRead -= ret; - _CRC16 = of_crc16(_CRC16, buffer, ret); + _CRC16 = OFCRC16(_CRC16, buffer, ret); if (_toRead == 0) { _atEndOfStream = true; if (_CRC16 != _entry.CRC16) { @@ -480,17 +479,17 @@ @try { bytesWritten = (uint32_t)[_stream writeBuffer: buffer length: length]; } @catch (OFWriteFailedException *e) { _bytesWritten += e.bytesWritten; - _CRC16 = of_crc16(_CRC16, buffer, e.bytesWritten); + _CRC16 = OFCRC16(_CRC16, buffer, e.bytesWritten); @throw e; } _bytesWritten += (uint32_t)bytesWritten; - _CRC16 = of_crc16(_CRC16, buffer, bytesWritten); + _CRC16 = OFCRC16(_CRC16, buffer, bytesWritten); return bytesWritten; } - (bool)lowlevelIsAtEndOfStream Index: src/OFLHAArchiveEntry.m ================================================================== --- src/OFLHAArchiveEntry.m +++ src/OFLHAArchiveEntry.m @@ -18,18 +18,17 @@ #include #import "OFLHAArchiveEntry.h" #import "OFLHAArchiveEntry+Private.h" #import "OFArray.h" +#import "OFCRC16.h" #import "OFData.h" #import "OFDate.h" #import "OFNumber.h" #import "OFStream.h" #import "OFString.h" -#import "crc16.h" - #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" #import "OFUnsupportedVersionException.h" @@ -722,11 +721,11 @@ /* Now fill in the size and CRC16 for the entire header */ tmp16 = OFToLittleEndian16(headerSize); memcpy([data mutableItemAtIndex: 0], &tmp16, sizeof(tmp16)); - tmp16 = of_crc16(0, data.items, data.count); + tmp16 = OFCRC16(0, data.items, data.count); tmp16 = OFToLittleEndian16(tmp16); memcpy([data mutableItemAtIndex: 27], &tmp16, sizeof(tmp16)); [stream writeData: data]; Index: src/OFLHADecompressingStream.h ================================================================== --- src/OFLHADecompressingStream.h +++ src/OFLHADecompressingStream.h @@ -12,10 +12,11 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFStream.h" +#import "OFHuffmanTree.h" OF_ASSUME_NONNULL_BEGIN #define OFLHADecompressingStreamBufferSize 4096 @@ -32,12 +33,12 @@ uint16_t _savedBits; unsigned char *_slidingWindow; uint32_t _slidingWindowIndex, _slidingWindowMask; int _state; uint16_t _symbolsLeft; - struct of_huffman_tree *_Nullable _codeLenTree, *_Nullable _litLenTree; - struct of_huffman_tree *_Nullable _distTree, *_Nullable _treeIter; + OFHuffmanTree *_Nullable _codeLenTree, *_Nullable _litLenTree; + OFHuffmanTree *_Nullable _distTree, *_Nullable _treeIter; uint16_t _codesCount, _codesReceived; bool _currentIsExtendedLength, _skip; uint8_t *_Nullable _codesLengths; uint16_t _length; uint32_t _distance; Index: src/OFLHADecompressingStream.m ================================================================== --- src/OFLHADecompressingStream.m +++ src/OFLHADecompressingStream.m @@ -18,30 +18,30 @@ #include #import "OFLHADecompressingStream.h" #import "OFKernelEventObserver.h" -#import "huffman_tree.h" +#import "OFHuffmanTree.h" #import "OFInvalidFormatException.h" #import "OFNotOpenException.h" enum state { - STATE_BLOCK_HEADER, - STATE_CODE_LEN_CODES_COUNT, - STATE_CODE_LEN_TREE, - STATE_CODE_LEN_TREE_SINGLE, - STATE_LITLEN_CODES_COUNT, - STATE_LITLEN_TREE, - STATE_LITLEN_TREE_SINGLE, - STATE_DIST_CODES_COUNT, - STATE_DIST_TREE, - STATE_DIST_TREE_SINGLE, - STATE_BLOCK_LITLEN, - STATE_BLOCK_DIST_LENGTH, - STATE_BLOCK_DIST_LENGTH_EXTRA, - STATE_BLOCK_LEN_DIST_PAIR + StateBlockHeader, + StateCodeLenCodesCount, + StateCodeLenTree, + StateCodeLenTreeSingle, + StateLitLenCodesCount, + StateLitLenTree, + StateLitLenTreeSingle, + StateDistCodesCount, + StateDistTree, + StateDistTreeSingle, + StateBlockLitLen, + StateBlockDistLength, + StateBlockDistLengthExtra, + StateBlockLenDistPair }; @implementation OFLHADecompressingStream @synthesize bytesConsumed = _bytesConsumed; @@ -124,15 +124,15 @@ [self close]; OFFreeMemory(_slidingWindow); if (_codeLenTree != NULL) - of_huffman_tree_release(_codeLenTree); + OFHuffmanTreeFree(_codeLenTree); if (_litLenTree != NULL) - of_huffman_tree_release(_litLenTree); + OFHuffmanTreeFree(_litLenTree); if (_distTree != NULL) - of_huffman_tree_release(_distTree); + OFHuffmanTreeFree(_distTree); OFFreeMemory(_codesLengths); [super dealloc]; } @@ -146,43 +146,43 @@ if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (_stream.atEndOfStream && _bufferLength - _bufferIndex == 0 && - _state == STATE_BLOCK_HEADER) + _state == StateBlockHeader) return 0; start: switch ((enum state)_state) { - case STATE_BLOCK_HEADER: + case StateBlockHeader: if OF_UNLIKELY (!tryReadBits(self, &bits, 16)) return bytesWritten; _symbolsLeft = bits; - _state = STATE_CODE_LEN_CODES_COUNT; + _state = StateCodeLenCodesCount; goto start; - case STATE_CODE_LEN_CODES_COUNT: + case StateCodeLenCodesCount: if OF_UNLIKELY (!tryReadBits(self, &bits, 5)) return bytesWritten; if OF_UNLIKELY (bits > 20) @throw [OFInvalidFormatException exception]; if OF_UNLIKELY (bits == 0) { - _state = STATE_CODE_LEN_TREE_SINGLE; + _state = StateCodeLenTreeSingle; goto start; } _codesCount = bits; _codesReceived = 0; _codesLengths = OFAllocZeroedMemory(bits, 1); _skip = true; - _state = STATE_CODE_LEN_TREE; + _state = StateCodeLenTree; goto start; - case STATE_CODE_LEN_TREE: + case StateCodeLenTree: while (_codesReceived < _codesCount) { if OF_UNLIKELY (_currentIsExtendedLength) { if OF_UNLIKELY (!tryReadBits(self, &bits, 1)) return bytesWritten; @@ -222,49 +222,48 @@ continue; } else _codesReceived++; } - _codeLenTree = of_huffman_tree_construct(_codesLengths, - _codesCount); + _codeLenTree = OFHuffmanTreeNew(_codesLengths, _codesCount); OFFreeMemory(_codesLengths); _codesLengths = NULL; - _state = STATE_LITLEN_CODES_COUNT; + _state = StateLitLenCodesCount; goto start; - case STATE_CODE_LEN_TREE_SINGLE: + case StateCodeLenTreeSingle: if OF_UNLIKELY (!tryReadBits(self, &bits, 5)) return bytesWritten; - _codeLenTree = of_huffman_tree_construct_single(bits); + _codeLenTree = OFHuffmanTreeNewSingle(bits); - _state = STATE_LITLEN_CODES_COUNT; + _state = StateLitLenCodesCount; goto start; - case STATE_LITLEN_CODES_COUNT: + case StateLitLenCodesCount: if OF_UNLIKELY (!tryReadBits(self, &bits, 9)) return bytesWritten; if OF_UNLIKELY (bits > 510) @throw [OFInvalidFormatException exception]; if OF_UNLIKELY (bits == 0) { - of_huffman_tree_release(_codeLenTree); + OFHuffmanTreeFree(_codeLenTree); _codeLenTree = NULL; - _state = STATE_LITLEN_TREE_SINGLE; + _state = StateLitLenTreeSingle; goto start; } _codesCount = bits; _codesReceived = 0; _codesLengths = OFAllocZeroedMemory(bits, 1); _skip = false; _treeIter = _codeLenTree; - _state = STATE_LITLEN_TREE; + _state = StateLitLenTree; goto start; - case STATE_LITLEN_TREE: + case StateLitLenTree: while (_codesReceived < _codesCount) { if OF_UNLIKELY (_skip) { uint16_t skipCount; switch (_codesLengths[_codesReceived]) { @@ -299,12 +298,12 @@ _skip = false; continue; } - if (!of_huffman_tree_walk(self, tryReadBits, - &_treeIter, &value)) + if (!OFHuffmanTreeWalk(self, tryReadBits, &_treeIter, + &value)) return bytesWritten; _treeIter = _codeLenTree; if (value < 3) { @@ -312,48 +311,47 @@ _skip = true; } else _codesLengths[_codesReceived++] = value - 2; } - _litLenTree = of_huffman_tree_construct(_codesLengths, - _codesCount); + _litLenTree = OFHuffmanTreeNew(_codesLengths, _codesCount); OFFreeMemory(_codesLengths); _codesLengths = NULL; - of_huffman_tree_release(_codeLenTree); + OFHuffmanTreeFree(_codeLenTree); _codeLenTree = NULL; - _state = STATE_DIST_CODES_COUNT; + _state = StateDistCodesCount; goto start; - case STATE_LITLEN_TREE_SINGLE: + case StateLitLenTreeSingle: if OF_UNLIKELY (!tryReadBits(self, &bits, 9)) return bytesWritten; - _litLenTree = of_huffman_tree_construct_single(bits); + _litLenTree = OFHuffmanTreeNewSingle(bits); - _state = STATE_DIST_CODES_COUNT; + _state = StateDistCodesCount; goto start; - case STATE_DIST_CODES_COUNT: + case StateDistCodesCount: if OF_UNLIKELY (!tryReadBits(self, &bits, _distanceBits)) return bytesWritten; if OF_UNLIKELY (bits > _dictionaryBits) @throw [OFInvalidFormatException exception]; if OF_UNLIKELY (bits == 0) { - _state = STATE_DIST_TREE_SINGLE; + _state = StateDistTreeSingle; goto start; } _codesCount = bits; _codesReceived = 0; _codesLengths = OFAllocZeroedMemory(bits, 1); _treeIter = _codeLenTree; - _state = STATE_DIST_TREE; + _state = StateDistTree; goto start; - case STATE_DIST_TREE: + case StateDistTree: while (_codesReceived < _codesCount) { if OF_UNLIKELY (_currentIsExtendedLength) { if OF_UNLIKELY (!tryReadBits(self, &bits, 1)) return bytesWritten; @@ -377,34 +375,33 @@ continue; } else _codesReceived++; } - _distTree = of_huffman_tree_construct(_codesLengths, - _codesCount); + _distTree = OFHuffmanTreeNew(_codesLengths, _codesCount); OFFreeMemory(_codesLengths); _codesLengths = NULL; _treeIter = _litLenTree; - _state = STATE_BLOCK_LITLEN; + _state = StateBlockLitLen; goto start; - case STATE_DIST_TREE_SINGLE: + case StateDistTreeSingle: if OF_UNLIKELY (!tryReadBits(self, &bits, _distanceBits)) return bytesWritten; - _distTree = of_huffman_tree_construct_single(bits); + _distTree = OFHuffmanTreeNewSingle(bits); _treeIter = _litLenTree; - _state = STATE_BLOCK_LITLEN; + _state = StateBlockLitLen; goto start; - case STATE_BLOCK_LITLEN: + case StateBlockLitLen: if OF_UNLIKELY (_symbolsLeft == 0) { - of_huffman_tree_release(_litLenTree); - of_huffman_tree_release(_distTree); + OFHuffmanTreeFree(_litLenTree); + OFHuffmanTreeFree(_distTree); _litLenTree = _distTree = NULL; - _state = STATE_BLOCK_HEADER; + _state = StateBlockHeader; /* * We must return here, as there is no indication * whether this was the last block. Whoever called this * method needs to check if everything has been read @@ -425,11 +422,11 @@ } if OF_UNLIKELY (length == 0) return bytesWritten; - if OF_UNLIKELY (!of_huffman_tree_walk(self, tryReadBits, + if OF_UNLIKELY (!OFHuffmanTreeWalk(self, tryReadBits, &_treeIter, &value)) return bytesWritten; if OF_LIKELY (value < 256) { buffer[bytesWritten++] = value; @@ -442,34 +439,33 @@ _symbolsLeft--; _treeIter = _litLenTree; } else { _length = value - 253; _treeIter = _distTree; - _state = STATE_BLOCK_DIST_LENGTH; + _state = StateBlockDistLength; } goto start; - case STATE_BLOCK_DIST_LENGTH: - if OF_UNLIKELY (!of_huffman_tree_walk(self, tryReadBits, + case StateBlockDistLength: + if OF_UNLIKELY (!OFHuffmanTreeWalk(self, tryReadBits, &_treeIter, &value)) return bytesWritten; _distance = value; _state = (value < 2 - ? STATE_BLOCK_LEN_DIST_PAIR - : STATE_BLOCK_DIST_LENGTH_EXTRA); + ? StateBlockLenDistPair : StateBlockDistLengthExtra); goto start; - case STATE_BLOCK_DIST_LENGTH_EXTRA: + case StateBlockDistLengthExtra: if OF_UNLIKELY (!tryReadBits(self, &bits, _distance - 1)) return bytesWritten; _distance = bits + (1u << (_distance - 1)); - _state = STATE_BLOCK_LEN_DIST_PAIR; + _state = StateBlockLenDistPair; goto start; - case STATE_BLOCK_LEN_DIST_PAIR: + case StateBlockLenDistPair: for (uint_fast16_t i = 0; i < _length; i++) { uint32_t idx; if OF_UNLIKELY (length == 0) { _length -= i; @@ -489,11 +485,11 @@ } _symbolsLeft--; _treeIter = _litLenTree; - _state = STATE_BLOCK_LITLEN; + _state = StateBlockLitLen; goto start; } OF_UNREACHABLE } @@ -502,11 +498,11 @@ { if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; return (_stream.atEndOfStream && - _bufferLength - _bufferIndex == 0 && _state == STATE_BLOCK_HEADER); + _bufferLength - _bufferIndex == 0 && _state == StateBlockHeader); } - (int)fileDescriptorForReading { return ((id )_stream) Index: src/OFMutableString.m ================================================================== --- src/OFMutableString.m +++ src/OFMutableString.m @@ -18,17 +18,17 @@ #include #include #include #import "OFString.h" +#import "OFASPrintF.h" #import "OFMutableUTF8String.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" -#import "of_asprintf.h" #import "unicode.h" static struct { Class isa; } placeholder; @@ -359,11 +359,11 @@ int UTF8StringLength; if (format == nil) @throw [OFInvalidArgumentException exception]; - if ((UTF8StringLength = of_vasprintf(&UTF8String, format.UTF8String, + if ((UTF8StringLength = OFVASPrintF(&UTF8String, format.UTF8String, arguments)) == -1) @throw [OFInvalidFormatException exception]; @try { [self appendUTF8String: UTF8String length: UTF8StringLength]; Index: src/OFMutableUTF8String.m ================================================================== --- src/OFMutableUTF8String.m +++ src/OFMutableUTF8String.m @@ -19,20 +19,20 @@ #include #include #include #import "OFMutableUTF8String.h" +#import "OFASPrintF.h" #import "OFString.h" #import "OFUTF8String.h" #import "OFInvalidArgumentException.h" #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#import "of_asprintf.h" #import "unicode.h" @implementation OFMutableUTF8String + (void)initialize { @@ -413,11 +413,11 @@ int UTF8StringLength; if (format == nil) @throw [OFInvalidArgumentException exception]; - if ((UTF8StringLength = of_vasprintf(&UTF8String, format.UTF8String, + if ((UTF8StringLength = OFVASPrintF(&UTF8String, format.UTF8String, arguments)) == -1) @throw [OFInvalidFormatException exception]; @try { [self appendUTF8String: UTF8String length: UTF8StringLength]; Index: src/OFMutex.h ================================================================== --- src/OFMutex.h +++ src/OFMutex.h @@ -13,12 +13,11 @@ * file. */ #import "OFObject.h" #import "OFLocking.h" - -#import "mutex.h" +#import "OFPlainMutex.h" OF_ASSUME_NONNULL_BEGIN /** * @class OFMutex OFMutex.h ObjFW/OFMutex.h Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -29,11 +29,12 @@ #include #include #include #include "macros.h" -#include "once.h" + +#include "OFOnce.h" /* * Some versions of MinGW require to be included before * . Do this here to make sure this is always done in the correct * order, even if another header includes just . Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -29,13 +29,20 @@ # include #endif #import "OFObject.h" #import "OFArray.h" +#ifdef OF_HAVE_ATOMIC_OPS +# import "OFAtomic.h" +#endif #import "OFLocale.h" #import "OFMethodSignature.h" #import "OFRunLoop.h" +#if !defined(OF_HAVE_ATOMIC_OPS) && defined(OF_HAVE_THREADS) +# import "OFPlainMutex.h" /* For OFSpinlock */ +#endif +#import "OFString.h" #import "OFThread.h" #import "OFTimer.h" #import "OFAllocFailedException.h" #import "OFEnumerationMutationException.h" @@ -58,18 +65,10 @@ #ifdef OF_AMIGAOS # include #endif -#import "OFString.h" - -#if defined(OF_HAVE_ATOMIC_OPS) -# import "atomic.h" -#elif defined(OF_HAVE_THREADS) -# import "mutex.h" -#endif - #ifdef OF_APPLE_RUNTIME extern id _Nullable _objc_rootAutorelease(id _Nullable object); #endif #if defined(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR) extern id OFForward(id, SEL, ...); ADDED src/OFOnce.h Index: src/OFOnce.h ================================================================== --- src/OFOnce.h +++ src/OFOnce.h @@ -0,0 +1,38 @@ +/* + * 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 "objfw-defs.h" + +#include "platform.h" + +#if defined(OF_HAVE_PTHREADS) +# include +typedef pthread_once_t OFOnceControl; +# define OFOnceControlInitValue PTHREAD_ONCE_INIT +#elif defined(OF_HAVE_ATOMIC_OPS) +typedef volatile int OFOnceControl; +# define OFOnceControlInitValue 0 +#elif defined(OF_AMIGAOS) || !defined(OF_HAVE_THREADS) +typedef int OFOnceControl; +# define OFOnceControlInitValue 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern void OFOnce(OFOnceControl *control, void (*func)(void)); +#ifdef __cplusplus +} +#endif ADDED src/OFOnce.m Index: src/OFOnce.m ================================================================== --- src/OFOnce.m +++ src/OFOnce.m @@ -0,0 +1,84 @@ +/* + * 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 "OFOnce.h" +#if defined(OF_HAVE_THREADS) && defined(OF_HAVE_ATOMIC_OPS) +# import "OFAtomic.h" +# import "OFPlainMutex.h" +#endif + +#ifdef OF_AMIGAOS +# include +#endif + +void +OFOnce(OFOnceControl *control, void (*func)(void)) +{ +#if !defined(OF_HAVE_THREADS) + if (*control == 0) { + func(); + *control = 1; + } +#elif defined(OF_HAVE_PTHREADS) + pthread_once(control, func); +#elif defined(OF_HAVE_ATOMIC_OPS) + /* Avoid atomic operations in case it's already done. */ + if (*control == 2) + return; + + if (OFAtomicIntCompareAndSwap(control, 0, 1)) { + func(); + + of_memory_barrier(); + + OFAtomicIntIncrease(control); + } else + while (*control == 1) + OFYieldThread(); +#elif defined(OF_AMIGAOS) + bool run = false; + + /* Avoid Forbid() in case it's already done. */ + if (*control == 2) + return; + + Forbid(); + + switch (*control) { + case 0: + *control = 1; + run = true; + break; + case 1: + while (*control == 1) { + Permit(); + Forbid(); + } + } + + Permit(); + + if (run) { + func(); + *control = 2; + } +#else +# error No OFOnce available +#endif +} ADDED src/OFPBKDF2.h Index: src/OFPBKDF2.h ================================================================== --- src/OFPBKDF2.h +++ src/OFPBKDF2.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +/** @file */ + +@class OFHMAC; + +/** + * @brief The parameters for @ref OFPBKDF2. + */ +typedef struct OFPBKDF2Parameters { + /** @brief The HMAC to use to derive a key. */ + __unsafe_unretained OFHMAC *HMAC; + /** @brief The number of iterations to perform. */ + size_t iterations; + /** @brief The salt to derive a key with. */ + const unsigned char *salt; + /** @brief The length of the salt. */ + size_t saltLength; + /** @brief The password to derive a key from. */ + const char *password; + /** @brief The length of the password. */ + size_t passwordLength; + /** @brief The buffer to write the key to. */ + unsigned char *key; + /** + * @brief The desired length for the derived key. + * + * @ref key needs to have enough storage. + */ + size_t keyLength; + /** @brief Whether data may be stored in swappable memory. */ + bool allowsSwappableMemory; +} OFPBKDF2Parameters; + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief Derives a key from a password and a salt using PBKDF2. + * + * @note This will call @ref OFHMAC::reset on the `HMAC` first, making it + * possible to reuse the `HMAC`, but also meaning all previous results + * from the `HMAC` get invalidated if they have not been copied. + * + * @param param The parameters to use + */ +extern void OFPBKDF2(OFPBKDF2Parameters param); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFPBKDF2.m Index: src/OFPBKDF2.m ================================================================== --- src/OFPBKDF2.m +++ src/OFPBKDF2.m @@ -0,0 +1,111 @@ +/* + * 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 "OFPBKDF2.h" +#import "OFHMAC.h" +#import "OFSecureData.h" + +#import "OFInvalidArgumentException.h" +#import "OFOutOfMemoryException.h" +#import "OFOutOfRangeException.h" + +void +OFPBKDF2(OFPBKDF2Parameters param) +{ + void *pool = objc_autoreleasePoolPush(); + size_t blocks, digestSize = param.HMAC.digestSize; + OFSecureData *buffer = [OFSecureData + dataWithCount: digestSize + allowsSwappableMemory: param.allowsSwappableMemory]; + OFSecureData *digest = [OFSecureData + dataWithCount: digestSize + allowsSwappableMemory: param.allowsSwappableMemory]; + unsigned char *bufferItems = buffer.mutableItems; + unsigned char *digestItems = digest.mutableItems; + OFSecureData *extendedSalt; + unsigned char *extendedSaltItems; + + if (param.HMAC == nil || param.iterations == 0 || param.salt == NULL || + param.password == NULL || param.key == NULL || param.keyLength == 0) + @throw [OFInvalidArgumentException exception]; + + blocks = param.keyLength / digestSize; + if (param.keyLength % digestSize != 0) + blocks++; + + if (param.saltLength > SIZE_MAX - 4 || blocks > UINT32_MAX) + @throw [OFOutOfRangeException exception]; + + extendedSalt = [OFSecureData + dataWithCount: param.saltLength + 4 + allowsSwappableMemory: param.allowsSwappableMemory]; + extendedSaltItems = extendedSalt.mutableItems; + + @try { + uint32_t i = OFToBigEndian32(1); + + [param.HMAC setKey: param.password + length: param.passwordLength]; + + memcpy(extendedSaltItems, param.salt, param.saltLength); + + while (param.keyLength > 0) { + size_t length; + + memcpy(extendedSaltItems + param.saltLength, &i, 4); + + [param.HMAC reset]; + [param.HMAC updateWithBuffer: extendedSaltItems + length: param.saltLength + 4]; + memcpy(bufferItems, param.HMAC.digest, digestSize); + memcpy(digestItems, param.HMAC.digest, digestSize); + + for (size_t j = 1; j < param.iterations; j++) { + [param.HMAC reset]; + [param.HMAC updateWithBuffer: digestItems + length: digestSize]; + memcpy(digestItems, param.HMAC.digest, + digestSize); + + for (size_t k = 0; k < digestSize; k++) + bufferItems[k] ^= digestItems[k]; + } + + length = digestSize; + if (length > param.keyLength) + length = param.keyLength; + + memcpy(param.key, bufferItems, length); + param.key += length; + param.keyLength -= length; + + i = OFToBigEndian32(OFFromBigEndian32(i) + 1); + } + } @catch (id e) { + [extendedSalt zero]; + [buffer zero]; + [digest zero]; + + @throw e; + } @finally { + [param.HMAC zero]; + } + + objc_autoreleasePoolPop(pool); +} ADDED src/OFPlainCondition.h Index: src/OFPlainCondition.h ================================================================== --- src/OFPlainCondition.h +++ src/OFPlainCondition.h @@ -0,0 +1,68 @@ +/* + * 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 "objfw-defs.h" + +#include "platform.h" + +#if !defined(OF_HAVE_THREADS) || \ + (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) +# error No conditions available! +#endif + +/* For OFTimeInterval */ +#import "OFObject.h" +#import "OFPlainMutex.h" + +#if defined(OF_HAVE_PTHREADS) +# include +typedef pthread_cond_t OFPlainCondition; +#elif defined(OF_WINDOWS) +# include +typedef struct { + HANDLE event; + volatile int count; +} OFPlainCondition; +#elif defined(OF_AMIGAOS) +# include +typedef struct { + struct OFPlainConditionWaitingTask { + struct Task *task; + unsigned char sigBit; + struct OFPlainConditionWaitingTask *next; + } *waitingTasks; +} OFPlainCondition; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern int OFPlainConditionNew(OFPlainCondition *condition); +extern int OFPlainConditionSignal(OFPlainCondition *condition); +extern int OFPlainConditionBroadcast(OFPlainCondition *condition); +extern int OFPlainConditionWait(OFPlainCondition *condition, + OFPlainMutex *mutex); +extern int OFPlainConditionTimedWait(OFPlainCondition *condition, + OFPlainMutex *mutex, OFTimeInterval timeout); +#ifdef OF_AMIGAOS +extern int OFPlainConditionWaitOrExecSignal(OFPlainCondition *condition, + OFPlainMutex *mutex, ULONG *signalMask); +extern int OFPlainConditionTimedWaitOrExecSignal(OFPlainCondition *condition, + OFPlainMutex *mutex, OFTimeInterval timeout, ULONG *signalMask); +#endif +extern int OFPlainConditionFree(OFPlainCondition *condition); +#ifdef __cplusplus +} +#endif ADDED src/OFPlainCondition.m Index: src/OFPlainCondition.m ================================================================== --- src/OFPlainCondition.m +++ src/OFPlainCondition.m @@ -0,0 +1,26 @@ +/* + * 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 "platform.h" + +#if defined(OF_HAVE_PTHREADS) +# include "platform/posix/OFPlainCondition.m" +#elif defined(OF_WINDOWS) +# include "platform/windows/OFPlainCondition.m" +#elif defined(OF_AMIGAOS) +# include "platform/amiga/OFPlainCondition.m" +#endif ADDED src/OFPlainMutex.h Index: src/OFPlainMutex.h ================================================================== --- src/OFPlainMutex.h +++ src/OFPlainMutex.h @@ -0,0 +1,171 @@ +/* + * 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 "objfw-defs.h" + +#include + +#include "platform.h" + +#if !defined(OF_HAVE_THREADS) || \ + (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) +# error No mutexes available! +#endif + +#import "macros.h" + +#if defined(OF_HAVE_PTHREADS) +# include +typedef pthread_mutex_t OFPlainMutex; +#elif defined(OF_WINDOWS) +# include +typedef CRITICAL_SECTION OFPlainMutex; +#elif defined(OF_AMIGAOS) +# include +typedef struct SignalSemaphore OFPlainMutex; +#endif + +#if defined(OF_HAVE_ATOMIC_OPS) +# import "OFAtomic.h" +typedef volatile int OFSpinlock; +# define OF_SPINCOUNT 10 +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) +typedef pthread_spinlock_t OFSpinlock; +#else +typedef OFPlainMutex OFSpinlock; +#endif + +#ifdef OF_HAVE_SCHED_YIELD +# include +#endif + +#if defined(OF_HAVE_RECURSIVE_PTHREAD_MUTEXES) || defined(OF_WINDOWS) || \ + defined(OF_AMIGAOS) +# define OFPlainRecursiveMutex OFPlainMutex +#else +# import "OFTLSKey.h" +typedef struct { + OFPlainMutex mutex; + OFTLSKey count; +} OFPlainRecursiveMutex; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern int OFPlainMutexNew(OFPlainMutex *mutex); +extern int OFPlainMutexLock(OFPlainMutex *mutex); +extern int OFPlainMutexTryLock(OFPlainMutex *mutex); +extern int OFPlainMutexUnlock(OFPlainMutex *mutex); +extern int OFPlainMutexFree(OFPlainMutex *mutex); +extern int OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex); +extern int OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex); +extern int OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex); +extern int OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex); +extern int OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex); +#ifdef __cplusplus +} +#endif + +/* Spinlocks are inlined for performance. */ + +static OF_INLINE void +OFYieldThread(void) +{ +#if defined(OF_HAVE_SCHED_YIELD) + sched_yield(); +#elif defined(OF_WINDOWS) + Sleep(0); +#endif +} + +static OF_INLINE int +OFSpinlockNew(OFSpinlock *spinlock) +{ +#if defined(OF_HAVE_ATOMIC_OPS) + *spinlock = 0; + return 0; +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) + return pthread_spin_init(spinlock, 0); +#else + return OFPlainMutexNew(spinlock); +#endif +} + +static OF_INLINE int +OFSpinlockTryLock(OFSpinlock *spinlock) +{ +#if defined(OF_HAVE_ATOMIC_OPS) + if (OFAtomicIntCompareAndSwap(spinlock, 0, 1)) { + of_memory_barrier_acquire(); + return 0; + } + + return EBUSY; +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) + return pthread_spin_trylock(spinlock); +#else + return OFPlainMutexTryLock(spinlock); +#endif +} + +static OF_INLINE int +OFSpinlockLock(OFSpinlock *spinlock) +{ +#if defined(OF_HAVE_ATOMIC_OPS) + size_t i; + + for (i = 0; i < OF_SPINCOUNT; i++) + if (OFSpinlockTryLock(spinlock) == 0) + return 0; + + while (OFSpinlockTryLock(spinlock) == EBUSY) + OFYieldThread(); + + return 0; +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) + return pthread_spin_lock(spinlock); +#else + return OFPlainMutexLock(spinlock); +#endif +} + +static OF_INLINE int +OFSpinlockUnlock(OFSpinlock *spinlock) +{ +#if defined(OF_HAVE_ATOMIC_OPS) + bool ret = OFAtomicIntCompareAndSwap(spinlock, 1, 0); + + of_memory_barrier_release(); + + return (ret ? 0 : EINVAL); +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) + return pthread_spin_unlock(spinlock); +#else + return OFPlainMutexUnlock(spinlock); +#endif +} + +static OF_INLINE int +OFSpinlockFree(OFSpinlock *spinlock) +{ +#if defined(OF_HAVE_ATOMIC_OPS) + return 0; +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) + return pthread_spin_destroy(spinlock); +#else + return OFPlainMutexFree(spinlock); +#endif +} ADDED src/OFPlainMutex.m Index: src/OFPlainMutex.m ================================================================== --- src/OFPlainMutex.m +++ src/OFPlainMutex.m @@ -0,0 +1,26 @@ +/* + * 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 "platform.h" + +#if defined(OF_HAVE_PTHREADS) +# include "platform/posix/OFPlainMutex.m" +#elif defined(OF_WINDOWS) +# include "platform/windows/OFPlainMutex.m" +#elif defined(OF_AMIGAOS) +# include "platform/amiga/OFPlainMutex.m" +#endif ADDED src/OFPlainThread.h Index: src/OFPlainThread.h ================================================================== --- src/OFPlainThread.h +++ src/OFPlainThread.h @@ -0,0 +1,97 @@ +/* + * 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 "objfw-defs.h" + +#include "platform.h" + +#if !defined(OF_HAVE_THREADS) || \ + (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) +# error No threads available! +#endif + +#import "macros.h" + +#if defined(OF_HAVE_PTHREADS) +# include +typedef pthread_t OFPlainThread; +#elif defined(OF_WINDOWS) +# include +typedef HANDLE OFPlainThread; +#elif defined(OF_AMIGAOS) +# include +# include +typedef struct { + struct Task *task; + void (*function)(id); + id object; + struct SignalSemaphore semaphore; + struct Task *joinTask; + unsigned char joinSigBit; + bool detached, done; +} *OFPlainThread; +#endif + +typedef struct OFPlainThreadAttributes { + float priority; + size_t stackSize; +} OFPlainThreadAttributes; + +#if defined(OF_HAVE_PTHREADS) +static OF_INLINE OFPlainThread +OFCurrentPlainThread(void) +{ + return pthread_self(); +} + +static OF_INLINE bool +OFPlainThreadIsCurrent(OFPlainThread thread) +{ + return pthread_equal(thread, pthread_self()); +} +#elif defined(OF_WINDOWS) +static OF_INLINE OFPlainThread +OFCurrentPlainThread(void) +{ + return GetCurrentThread(); +} + +static OF_INLINE bool +OFPlainThreadIsCurrent(OFPlainThread thread) +{ + return (thread == GetCurrentThread()); +} +#elif defined(OF_AMIGAOS) +extern OFPlainThread OFCurrentPlainThread(void); + +static OF_INLINE bool +OFPlainThreadIsCurrent(OFPlainThread thread) +{ + return (thread->thread == FindTask(NULL)); +} +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern int OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr); +extern int OFPlainThreadNew(OFPlainThread *thread, const char *name, + void (*function)(id), id object, const OFPlainThreadAttributes *attr); +extern void OFSetThreadName(const char *name); +extern int OFPlainThreadJoin(OFPlainThread thread); +extern int OFPlainThreadDetach(OFPlainThread thread); +#ifdef __cplusplus +} +#endif ADDED src/OFPlainThread.m Index: src/OFPlainThread.m ================================================================== --- src/OFPlainThread.m +++ src/OFPlainThread.m @@ -0,0 +1,26 @@ +/* + * 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 "platform.h" + +#if defined(OF_HAVE_PTHREADS) +# include "platform/posix/OFPlainThread.m" +#elif defined(OF_WINDOWS) +# include "platform/windows/OFPlainThread.m" +#elif defined(OF_AMIGAOS) +# include "platform/amiga/OFPlainThread.m" +#endif Index: src/OFPollKernelEventObserver.m ================================================================== --- src/OFPollKernelEventObserver.m +++ src/OFPollKernelEventObserver.m @@ -24,16 +24,15 @@ # include #endif #import "OFPollKernelEventObserver.h" #import "OFData.h" +#import "OFSocket+Private.h" #import "OFObserveFailedException.h" #import "OFOutOfRangeException.h" -#import "socket_helpers.h" - #ifdef OF_WII # define pollfd pollsd # define fd socket #endif Index: src/OFRecursiveMutex.h ================================================================== --- src/OFRecursiveMutex.h +++ src/OFRecursiveMutex.h @@ -13,12 +13,11 @@ * file. */ #import "OFObject.h" #import "OFLocking.h" - -#import "mutex.h" +#import "OFPlainMutex.h" OF_ASSUME_NONNULL_BEGIN /** * @class OFRecursiveMutex OFRecursiveMutex.h ObjFW/OFRecursiveMutex.h Index: src/OFSPXSocket.m ================================================================== --- src/OFSPXSocket.m +++ src/OFSPXSocket.m @@ -18,19 +18,18 @@ #include #import "OFSPXSocket.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFAlreadyConnectedException.h" #import "OFBindFailedException.h" #import "OFConnectionFailedException.h" #import "OFNotOpenException.h" -#import "socket.h" -#import "socket_helpers.h" - #ifndef NSPROTO_SPX # define NSPROTO_SPX 0 #endif #define SPX_PACKET_TYPE 5 Index: src/OFSPXStreamSocket.m ================================================================== --- src/OFSPXStreamSocket.m +++ src/OFSPXStreamSocket.m @@ -18,19 +18,18 @@ #include #import "OFSPXStreamSocket.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFAlreadyConnectedException.h" #import "OFBindFailedException.h" #import "OFConnectionFailedException.h" #import "OFNotOpenException.h" -#import "socket.h" -#import "socket_helpers.h" - #ifndef NSPROTO_SPX # define NSPROTO_SPX 0 #endif #define SPX_PACKET_TYPE 5 ADDED src/OFScrypt.h Index: src/OFScrypt.h ================================================================== --- src/OFScrypt.h +++ src/OFScrypt.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +/** @file */ + +@class OFHMAC; + +/** + * @brief The parameters for @ref OFScrypt. + */ +typedef struct OFScryptParameters { + /** @brief The block size to use. */ + size_t blockSize; + /** @brief The CPU/memory cost factor to use. */ + size_t costFactor; + /** @brief The parallelization to use. */ + size_t parallelization; + /** @brief The salt to derive a key with. */ + const unsigned char *salt; + /** @brief The length of the salt. */ + size_t saltLength; + /** @brief The password to derive a key from. */ + const char *password; + /** @brief The length of the password. */ + size_t passwordLength; + /** @brief The buffer to write the key to. */ + unsigned char *key; + /** + * @brief The desired length for the derived key. + * + * @ref key needs to have enough storage. + */ + size_t keyLength; + /** @brief Whether data may be stored in swappable memory. */ + bool allowsSwappableMemory; +} OFScryptParameters; + +#ifdef __cplusplus +extern "C" { +#endif +extern void OFSalsa20_8Core(uint32_t buffer[_Nonnull 16]); +extern void OFScryptBlockMix(uint32_t *output, const uint32_t *input, + size_t blockSize); +extern void OFScryptROMix(uint32_t *buffer, size_t blockSize, + size_t costFactor, uint32_t *tmp); + +/** + * @brief Derives a key from a password and a salt using scrypt. + * + * @param param The parameters to use + */ +extern void OFScrypt(OFScryptParameters param); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFScrypt.m Index: src/OFScrypt.m ================================================================== --- src/OFScrypt.m +++ src/OFScrypt.m @@ -0,0 +1,219 @@ +/* + * 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" + +#import "OFHMAC.h" +#import "OFSHA256Hash.h" +#import "OFSecureData.h" + +#import "OFInvalidArgumentException.h" +#import "OFOutOfMemoryException.h" +#import "OFOutOfRangeException.h" + +#import "OFScrypt.h" +#import "OFPBKDF2.h" + +void +OFSalsa20_8Core(uint32_t buffer[16]) +{ + uint32_t tmp[16]; + + for (uint_fast8_t i = 0; i < 16; i++) + tmp[i] = OFToLittleEndian32(buffer[i]); + + for (uint_fast8_t i = 0; i < 8; i += 2) { + tmp[ 4] ^= OFRotateLeft(tmp[ 0] + tmp[12], 7); + tmp[ 8] ^= OFRotateLeft(tmp[ 4] + tmp[ 0], 9); + tmp[12] ^= OFRotateLeft(tmp[ 8] + tmp[ 4], 13); + tmp[ 0] ^= OFRotateLeft(tmp[12] + tmp[ 8], 18); + tmp[ 9] ^= OFRotateLeft(tmp[ 5] + tmp[ 1], 7); + tmp[13] ^= OFRotateLeft(tmp[ 9] + tmp[ 5], 9); + tmp[ 1] ^= OFRotateLeft(tmp[13] + tmp[ 9], 13); + tmp[ 5] ^= OFRotateLeft(tmp[ 1] + tmp[13], 18); + tmp[14] ^= OFRotateLeft(tmp[10] + tmp[ 6], 7); + tmp[ 2] ^= OFRotateLeft(tmp[14] + tmp[10], 9); + tmp[ 6] ^= OFRotateLeft(tmp[ 2] + tmp[14], 13); + tmp[10] ^= OFRotateLeft(tmp[ 6] + tmp[ 2], 18); + tmp[ 3] ^= OFRotateLeft(tmp[15] + tmp[11], 7); + tmp[ 7] ^= OFRotateLeft(tmp[ 3] + tmp[15], 9); + tmp[11] ^= OFRotateLeft(tmp[ 7] + tmp[ 3], 13); + tmp[15] ^= OFRotateLeft(tmp[11] + tmp[ 7], 18); + tmp[ 1] ^= OFRotateLeft(tmp[ 0] + tmp[ 3], 7); + tmp[ 2] ^= OFRotateLeft(tmp[ 1] + tmp[ 0], 9); + tmp[ 3] ^= OFRotateLeft(tmp[ 2] + tmp[ 1], 13); + tmp[ 0] ^= OFRotateLeft(tmp[ 3] + tmp[ 2], 18); + tmp[ 6] ^= OFRotateLeft(tmp[ 5] + tmp[ 4], 7); + tmp[ 7] ^= OFRotateLeft(tmp[ 6] + tmp[ 5], 9); + tmp[ 4] ^= OFRotateLeft(tmp[ 7] + tmp[ 6], 13); + tmp[ 5] ^= OFRotateLeft(tmp[ 4] + tmp[ 7], 18); + tmp[11] ^= OFRotateLeft(tmp[10] + tmp[ 9], 7); + tmp[ 8] ^= OFRotateLeft(tmp[11] + tmp[10], 9); + tmp[ 9] ^= OFRotateLeft(tmp[ 8] + tmp[11], 13); + tmp[10] ^= OFRotateLeft(tmp[ 9] + tmp[ 8], 18); + tmp[12] ^= OFRotateLeft(tmp[15] + tmp[14], 7); + tmp[13] ^= OFRotateLeft(tmp[12] + tmp[15], 9); + tmp[14] ^= OFRotateLeft(tmp[13] + tmp[12], 13); + tmp[15] ^= OFRotateLeft(tmp[14] + tmp[13], 18); + } + + for (uint_fast8_t i = 0; i < 16; i++) + buffer[i] = OFToLittleEndian32(OFFromLittleEndian32(buffer[i]) + + tmp[i]); + + OFZeroMemory(tmp, sizeof(tmp)); +} + +void +OFScryptBlockMix(uint32_t *output, const uint32_t *input, size_t blockSize) +{ + uint32_t tmp[16]; + + /* Check defined here and executed in OFScrypt() */ +#define OVERFLOW_CHECK_1 \ + if (param.blockSize > SIZE_MAX / 2 || \ + 2 * param.blockSize - 1 > SIZE_MAX / 16) \ + @throw [OFOutOfRangeException exception]; + + memcpy(tmp, input + (2 * blockSize - 1) * 16, 64); + + for (size_t i = 0; i < 2 * blockSize; i++) { + for (size_t j = 0; j < 16; j++) + tmp[j] ^= input[i * 16 + j]; + + OFSalsa20_8Core(tmp); + + /* + * Even indices are stored in the first half and odd ones in + * the second. + */ + memcpy(output + ((i / 2) + (i & 1) * blockSize) * 16, tmp, 64); + } + + OFZeroMemory(tmp, sizeof(tmp)); +} + +void +OFScryptROMix(uint32_t *buffer, size_t blockSize, size_t costFactor, + uint32_t *tmp) +{ + /* Check defined here and executed in OFScrypt() */ +#define OVERFLOW_CHECK_2 \ + if (param.blockSize > SIZE_MAX / 128 / param.costFactor) \ + @throw [OFOutOfRangeException exception]; + + uint32_t *tmp2 = tmp + 32 * blockSize; + + memcpy(tmp, buffer, 128 * blockSize); + + for (size_t i = 0; i < costFactor; i++) { + memcpy(tmp2 + i * 32 * blockSize, tmp, 128 * blockSize); + OFScryptBlockMix(tmp, tmp2 + i * 32 * blockSize, blockSize); + } + + for (size_t i = 0; i < costFactor; i++) { + uint32_t j = OFFromLittleEndian32( + tmp[(2 * blockSize - 1) * 16]) & (costFactor - 1); + + for (size_t k = 0; k < 32 * blockSize; k++) + tmp[k] ^= tmp2[j * 32 * blockSize + k]; + + OFScryptBlockMix(buffer, tmp, blockSize); + + if (i < costFactor - 1) + memcpy(tmp, buffer, 128 * blockSize); + } +} + +void +OFScrypt(OFScryptParameters param) +{ + OFSecureData *tmp = nil, *buffer = nil; + OFHMAC *HMAC = nil; + + if (param.blockSize == 0 || param.costFactor <= 1 || + (param.costFactor & (param.costFactor - 1)) != 0 || + param.parallelization == 0) + @throw [OFInvalidArgumentException exception]; + + /* + * These are defined by the functions above. They are defined there so + * that the check is next to the code and easy to verify, but actually + * checked here for performance. + */ + OVERFLOW_CHECK_1 + OVERFLOW_CHECK_2 + + @try { + uint32_t *tmpItems, *bufferItems; + + if (param.costFactor > SIZE_MAX - 1 || + (param.costFactor + 1) > SIZE_MAX / 128) + @throw [OFOutOfRangeException exception]; + + tmp = [[OFSecureData alloc] + initWithCount: (param.costFactor + 1) * 128 + itemSize: param.blockSize + allowsSwappableMemory: param.allowsSwappableMemory]; + tmpItems = tmp.mutableItems; + + if (param.parallelization > SIZE_MAX / 128) + @throw [OFOutOfRangeException exception]; + + buffer = [[OFSecureData alloc] + initWithCount: param.parallelization * 128 + itemSize: param.blockSize + allowsSwappableMemory: param.allowsSwappableMemory]; + bufferItems = buffer.mutableItems; + + HMAC = [[OFHMAC alloc] + initWithHashClass: [OFSHA256Hash class] + allowsSwappableMemory: param.allowsSwappableMemory]; + + OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 1, + .salt = param.salt, + .saltLength = param.saltLength, + .password = param.password, + .passwordLength = param.passwordLength, + .key = (unsigned char *)bufferItems, + .keyLength = param.parallelization * 128 * + param.blockSize, + .allowsSwappableMemory = param.allowsSwappableMemory + }); + + for (size_t i = 0; i < param.parallelization; i++) + OFScryptROMix(bufferItems + i * 32 * param.blockSize, + param.blockSize, param.costFactor, tmpItems); + + OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 1, + .salt = (unsigned char *)bufferItems, + .saltLength = param.parallelization * 128 * + param.blockSize, + .password = param.password, + .passwordLength = param.passwordLength, + .key = param.key, + .keyLength = param.keyLength, + .allowsSwappableMemory = param.allowsSwappableMemory + }); + } @finally { + [tmp release]; + [buffer release]; + [HMAC release]; + } +} Index: src/OFSecureData.m ================================================================== --- src/OFSecureData.m +++ src/OFSecureData.m @@ -23,21 +23,20 @@ #endif #import "OFSecureData.h" #import "OFString.h" #import "OFSystemInfo.h" +#ifdef OF_HAVE_THREADS +# import "OFTLSKey.h" +#endif #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotImplementedException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#ifdef OF_HAVE_THREADS -# import "tlskey.h" -#endif - #define CHUNK_SIZE 16 #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) struct page { struct page *next, *previous; Index: src/OFSelectKernelEventObserver.m ================================================================== --- src/OFSelectKernelEventObserver.m +++ src/OFSelectKernelEventObserver.m @@ -29,17 +29,16 @@ #include #import "OFSelectKernelEventObserver.h" #import "OFArray.h" +#import "OFSocket+Private.h" #import "OFInitializationFailedException.h" #import "OFObserveFailedException.h" #import "OFOutOfRangeException.h" -#import "socket_helpers.h" - #ifdef OF_AMIGAOS # include #endif #ifdef OF_HPUX Index: src/OFSequencedPacketSocket.h ================================================================== --- src/OFSequencedPacketSocket.h +++ src/OFSequencedPacketSocket.h @@ -14,12 +14,11 @@ */ #import "OFObject.h" #import "OFKernelEventObserver.h" #import "OFRunLoop.h" - -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN /** @file */ Index: src/OFSequencedPacketSocket.m ================================================================== --- src/OFSequencedPacketSocket.m +++ src/OFSequencedPacketSocket.m @@ -30,10 +30,12 @@ #import "OFSequencedPacketSocket.h" #import "OFSequencedPacketSocket+Private.h" #import "OFData.h" #import "OFRunLoop+Private.h" #import "OFRunLoop.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFAcceptFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFListenFailedException.h" @@ -41,13 +43,10 @@ #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFSetOptionFailedException.h" #import "OFWriteFailedException.h" -#import "socket.h" -#import "socket_helpers.h" - @implementation OFSequencedPacketSocket @synthesize listening = _listening, delegate = _delegate; + (void)initialize { ADDED src/OFSocket+Private.h Index: src/OFSocket+Private.h ================================================================== --- src/OFSocket+Private.h +++ src/OFSocket+Private.h @@ -0,0 +1,97 @@ +/* + * 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 "unistd_wrapper.h" + +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif + +#include "OFSocket.h" + +#ifndef INVALID_SOCKET +# define INVALID_SOCKET -1 +#endif + +#ifndef INADDR_NONE +# define INADDR_NONE ((in_addr_t)-1) +#endif + +#ifndef SOMAXCONN +/* + * Use 16 as everything > 17 fails on Nintendo 3DS and 16 is a less arbitrary + * number than 17. + */ +# define SOMAXCONN 16 +#endif + +#ifndef SOCK_CLOEXEC +# define SOCK_CLOEXEC 0 +#endif + +#if defined(OF_AMIGAOS) +# ifdef OF_MORPHOS +# include +# else +# include +# endif +# include +# define closesocket(sock) CloseSocket(sock) +# define ioctlsocket(fd, req, arg) IoctlSocket(fd, req, arg) +# define hstrerror(err) "unknown (no hstrerror)" +# define SOCKET_ERROR -1 +# if defined(OF_HAVE_THREADS) && !defined(OF_MORPHOS) +# define SocketBase ((struct Library *)OFTLSKeyGet(of_socket_base_key)) +# ifdef OF_AMIGAOS4 +# define ISocket ((struct SocketIFace *)OFTLSKeyGet(of_socket_interface_key)) +# endif +# endif +# ifdef OF_MORPHOS +typedef uint32_t in_addr_t; +# endif +#elif !defined(OF_WINDOWS) && !defined(OF_WII) +# define closesocket(sock) close(sock) +#endif + +#ifdef OF_WII +# define accept(sock, addr, addrlen) net_accept(sock, addr, addrlen) +# define bind(sock, addr, addrlen) net_bind(sock, addr, addrlen) +# define closesocket(sock) net_close(sock) +# define connect(sock, addr, addrlen) \ + net_connect(sock, (struct sockaddr *)addr, addrlen) +# define fcntl(fd, cmd, flags) net_fcntl(fd, cmd, flags) +# define h_errno 0 +# define hstrerror(err) "unknown (no hstrerror)" +# define listen(sock, backlog) net_listen(sock, backlog) +# define poll(fds, nfds, timeout) net_poll(fds, nfds, timeout) +# define recv(sock, buf, len, flags) net_recv(sock, buf, len, flags) +# define recvfrom(sock, buf, len, flags, addr, addrlen) \ + net_recvfrom(sock, buf, len, flags, addr, addrlen) +# define select(nfds, readfds, writefds, errorfds, timeout) \ + net_select(nfds, readfds, writefds, errorfds, timeout) +# define send(sock, buf, len, flags) net_send(sock, buf, len, flags) +# define sendto(sock, buf, len, flags, addr, addrlen) \ + net_sendto(sock, buf, len, flags, (struct sockaddr *)(addr), addrlen) +# define setsockopt(sock, level, name, value, len) \ + net_setsockopt(sock, level, name, value, len) +# define socket(domain, type, proto) net_socket(domain, type, proto) +typedef u32 in_addr_t; +typedef u32 nfds_t; +#endif ADDED src/OFSocket.h Index: src/OFSocket.h ================================================================== --- src/OFSocket.h +++ src/OFSocket.h @@ -0,0 +1,295 @@ +/* + * 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 "objfw-defs.h" + +#ifndef OF_HAVE_SOCKETS +# error No sockets available! +#endif + +#include + +#import "OFString.h" +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) +# import "OFTLSKey.h" +#endif + +#ifdef OF_HAVE_SYS_SOCKET_H +# include +#endif +#ifdef OF_HAVE_NETINET_IN_H +# include +#endif +#ifdef OF_HAVE_NETINET_TCP_H +# include +#endif +#ifdef OF_HAVE_NETIPX_IPX_H +# include +#endif + +#ifdef OF_WINDOWS +# include +# include +# ifdef OF_HAVE_IPX +# include +# endif +#endif + +/** @file */ + +#ifdef OF_WII +# include +#endif + +#ifdef OF_PSP +# include +#endif + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifndef OF_WINDOWS +typedef int OFSocketHandle; +#else +typedef SOCKET OFSocketHandle; +#endif + +#ifdef OF_WII +typedef u8 sa_family_t; +#endif + +#ifdef OF_MORPHOS +typedef long socklen_t; +typedef u_char sa_family_t; +typedef u_short in_port_t; +#endif + +/** + * @brief A socket address family. + */ +typedef enum { + /** An unknown address family. */ + OFSocketAddressFamilyUnknown, + /** IPv4 */ + OFSocketAddressFamilyIPv4, + /** IPv6 */ + OFSocketAddressFamilyIPv6, + /** IPX */ + OFSocketAddressFamilyIPX, + /** Any address family */ + OFSocketAddressFamilyAny = 255 +} OFSocketAddressFamily; + +#ifndef OF_HAVE_IPV6 +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr { + uint8_t s6_addr[16]; + } sin6_addr; + uint32_t sin6_scope_id; +}; +#endif + +#ifndef OF_HAVE_IPX +# define IPX_NODE_LEN 6 +struct sockaddr_ipx { + sa_family_t sipx_family; + uint32_t sipx_network; + unsigned char sipx_node[IPX_NODE_LEN]; + uint16_t sipx_port; + uint8_t sipx_type; +}; +#endif +#ifdef OF_WINDOWS +# define IPX_NODE_LEN 6 +# define sipx_family sa_family +# define sipx_network sa_netnum +# define sipx_node sa_nodenum +# define sipx_port sa_socket +#endif + +/** + * @struct OFSocketAddress OFSocket.h ObjFW/OFSocket.h + * + * @brief A struct which represents a host / port pair for a socket. + */ +struct OF_BOXABLE OFSocketAddress { + /* + * Even though struct sockaddr contains the family, we need to use our + * own family, as we need to support storing an IPv6 address on systems + * that don't support IPv6. These may not have AF_INET6 defined and we + * can't just define it, as the value is system-dependent and might + * clash with an existing value. + */ + OFSocketAddressFamily family; + union { + struct sockaddr sockaddr; + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_ipx ipx; + } sockaddr; + socklen_t length; +}; +typedef struct OFSocketAddress OFSocketAddress; + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief Parses the specified IP (either v4 or v6) and port into an + * @ref OFSocketAddress. + * + * @param IP The IP to parse + * @param port The port to use + * @return The parsed IP and port as an OFSocketAddress + */ +extern OFSocketAddress OFSocketAddressParseIP(OFString *IP, uint16_t port); + +/** + * @brief Parses the specified IPv4 and port into an @ref OFSocketAddress. + * + * @param IP The IPv4 to parse + * @param port The port to use + * @return The parsed IPv4 and port as an OFSocketAddress + */ +extern OFSocketAddress OFSocketAddressParseIPv4(OFString *IP, uint16_t port); + +/** + * @brief Parses the specified IPv6 and port into an @ref OFSocketAddress. + * + * @param IP The IPv6 to parse + * @param port The port to use + * @return The parsed IPv6 and port as an OFSocketAddress + */ +extern OFSocketAddress OFSocketAddressParseIPv6(OFString *IP, uint16_t port); + +/** + * @brief Creates an IPX address for the specified network, node and port. + * + * @param node The node in the IPX network + * @param network The IPX network + * @param port The IPX port (sometimes called socket number) on the node + */ +extern OFSocketAddress OFSocketAddressMakeIPX( + const unsigned char node[_Nonnull IPX_NODE_LEN], uint32_t network, + uint16_t port); + +/** + * @brief Compares two OFSocketAddress for equality. + * + * @param address1 The address to compare with the second address + * @param address2 The second address + * @return Whether the two addresses are equal + */ +extern bool OFSocketAddressEqual(const OFSocketAddress *_Nonnull address1, + const OFSocketAddress *_Nonnull address2); + +/** + * @brief Returns the hash for the specified @ref OFSocketAddress. + * + * @param address The address to hash + * @return The hash for the specified OFSocketAddress + */ +extern unsigned long OFSocketAddressHash( + const OFSocketAddress *_Nonnull address); + +/** + * @brief Converts the specified @ref OFSocketAddress to a string. + * + * @param address The address to convert to a string + * @return The address as an IP string + */ +extern OFString *_Nonnull OFSocketAddressString( + const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the port of the specified @ref OFSocketAddress, independent of + * the address family used. + * + * @param address The address on which to set the port + * @param port The port to set on the address + */ +extern void OFSocketAddressSetPort(OFSocketAddress *_Nonnull address, + uint16_t port); + +/** + * @brief Returns the port of the specified @ref OFSocketAddress, independent of + * the address family used. + * + * @param address The address on which to get the port + * @return The port of the address + */ +extern uint16_t OFSocketAddressPort(const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the IPX network of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the IPX network + * @param network The IPX network to set on the address + */ +extern void OFSocketAddressSetIPXNetwork(OFSocketAddress *_Nonnull address, + uint32_t network); + +/** + * @brief Returns the IPX network of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the IPX network + * @return The IPX network of the address + */ +extern uint32_t OFSocketAddressIPXNetwork( + const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the IPX node of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the IPX node + * @param node The IPX node to set on the address + */ +extern void OFSocketAddressSetIPXNode(OFSocketAddress *_Nonnull address, + const unsigned char node[_Nonnull IPX_NODE_LEN]); + +/** + * @brief Gets the IPX node of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the IPX node + * @param node A byte array to store the IPX node of the address + */ +extern void OFSocketAddressIPXNode(const OFSocketAddress *_Nonnull address, + unsigned char node[_Nonnull IPX_NODE_LEN]); + +extern bool of_socket_init(void); +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) +extern void of_socket_deinit(void); +#endif +extern int of_socket_errno(void); +#if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) +extern int of_getsockname(OFSocketHandle sock, struct sockaddr *restrict addr, + socklen_t *restrict addrLen); +#endif + +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) +extern OFTLSKey of_socket_base_key; +# ifdef OF_AMIGAOS4 +extern OFTLSKey of_socket_interface_key; +# endif +#endif +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFSocket.m Index: src/OFSocket.m ================================================================== --- src/OFSocket.m +++ src/OFSocket.m @@ -0,0 +1,850 @@ +/* + * 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" + +#ifndef _XOPEN_SOURCE_EXTENDED +# define _XOPEN_SOURCE_EXTENDED +#endif +#define _HPUX_ALT_XOPEN_SOCKET_API + +#ifdef OF_NINTENDO_3DS +# include /* For memalign() */ +#endif + +#include + +#import "OFArray.h" +#import "OFCharacterSet.h" +#import "OFLocale.h" +#ifdef OF_HAVE_THREADS +# import "OFMutex.h" +#endif +#import "OFOnce.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" +#import "OFString.h" +#ifdef OF_HAVE_THREADS +# import "OFTLSKey.h" +#endif + +#import "OFException.h" /* For some E* -> WSAE* defines */ +#import "OFInitializationFailedException.h" +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" +#import "OFLockFailedException.h" +#import "OFUnlockFailedException.h" + +#ifdef OF_AMIGAOS +# include +#endif + +#ifdef OF_NINTENDO_3DS +# include <3ds/types.h> +# include <3ds/services/soc.h> +#endif + +#if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) +static OFMutex *mutex; + +static void +releaseMutex(void) +{ + [mutex release]; +} +#endif +#if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) || !defined(OF_HAVE_THREADS) +static bool initSuccessful = false; +#endif + +#ifdef OF_AMIGAOS +# if defined(OF_HAVE_THREADS) && !defined(OF_MORPHOS) +OFTLSKey of_socket_base_key; +# ifdef OF_AMIGAOS4 +OFTLSKey of_socket_interface_key; +# endif +# else +struct Library *SocketBase; +# ifdef OF_AMIGAOS4 +struct SocketIFace *ISocket = NULL; +# endif +# endif +#endif + +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) +OF_CONSTRUCTOR() +{ + if (OFTLSKeyNew(&of_socket_base_key) != 0) + @throw [OFInitializationFailedException exception]; + +# ifdef OF_AMIGAOS4 + if (OFTLSKeyNew(&of_socket_interface_key) != 0) + @throw [OFInitializationFailedException exception]; +# endif +} +#endif + +#if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) || !defined(OF_HAVE_THREADS) +static void +init(void) +{ +# if defined(OF_WINDOWS) + WSADATA wsa; + + if (WSAStartup(MAKEWORD(2, 0), &wsa)) + return; +# elif defined(OF_AMIGAOS) + if ((SocketBase = OpenLibrary("bsdsocket.library", 4)) == NULL) + return; + +# ifdef OF_AMIGAOS4 + if ((ISocket = (struct SocketIFace *) + GetInterface(SocketBase, "main", 1, NULL)) == NULL) { + CloseLibrary(SocketBase); + return; + } +# endif +# elif defined(OF_WII) + if (net_init() < 0) + return; +# elif defined(OF_NINTENDO_3DS) + void *ctx; + + if ((ctx = memalign(0x1000, 0x100000)) == NULL) + return; + + if (socInit(ctx, 0x100000) != 0) + return; + + atexit((void (*)(void))socExit); +# endif + +# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) + mutex = [[OFMutex alloc] init]; + atexit(releaseMutex); + +# ifdef OF_WII + if (OFSpinlockNew(&spinlock) != 0) + return; +# endif +# endif + + initSuccessful = true; +} + +OF_DESTRUCTOR() +{ +# ifdef OF_AMIGAOS +# ifdef OF_AMIGAOS4 + if (ISocket != NULL) + DropInterface((struct Interface *)ISocket); +# endif + + if (SocketBase != NULL) + CloseLibrary(SocketBase); +# endif +} +#endif + +bool +of_socket_init(void) +{ +#if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) || !defined(OF_HAVE_THREADS) + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, init); + + return initSuccessful; +#else + struct Library *socketBase; +# ifdef OF_AMIGAOS4 + struct SocketIFace *socketInterface; +# endif + +# ifdef OF_AMIGAOS4 + if ((socketInterface = OFTLSKeyGet(of_socket_interface_key)) != NULL) +# else + if ((socketBase = OFTLSKeyGet(of_socket_base_key)) != NULL) +# endif + return true; + + if ((socketBase = OpenLibrary("bsdsocket.library", 4)) == NULL) + return false; + +# ifdef OF_AMIGAOS4 + if ((socketInterface = (struct SocketIFace *) + GetInterface(socketBase, "main", 1, NULL)) == NULL) { + CloseLibrary(socketBase); + return false; + } +# endif + + if (OFTLSKeySet(of_socket_base_key, socketBase) != 0) { + CloseLibrary(socketBase); +# ifdef OF_AMIGAOS4 + DropInterface((struct Interface *)socketInterface); +# endif + return false; + } + +# ifdef OF_AMIGAOS4 + if (OFTLSKeySet(of_socket_interface_key, socketInterface) != 0) { + CloseLibrary(socketBase); + DropInterface((struct Interface *)socketInterface); + return false; + } +# endif + + return true; +#endif +} + +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) +void +of_socket_deinit(void) +{ + struct Library *socketBase = OFTLSKeyGet(of_socket_base_key); +# ifdef OF_AMIGAOS4 + struct SocketIFace *socketInterface = + OFTLSKeyGet(of_socket_interface_key); + + if (socketInterface != NULL) + DropInterface((struct Interface *)socketInterface); +# endif + if (socketBase != NULL) + CloseLibrary(socketBase); +} +#endif + +int +of_socket_errno() +{ +#if defined(OF_WINDOWS) + switch (WSAGetLastError()) { + case WSAEACCES: + return EACCES; + case WSAEADDRINUSE: + return EADDRINUSE; + case WSAEADDRNOTAVAIL: + return EADDRNOTAVAIL; + case WSAEAFNOSUPPORT: + return EAFNOSUPPORT; + case WSAEALREADY: + return EALREADY; + case WSAEBADF: + return EBADF; + case WSAECONNABORTED: + return ECONNABORTED; + case WSAECONNREFUSED: + return ECONNREFUSED; + case WSAECONNRESET: + return ECONNRESET; + case WSAEDESTADDRREQ: + return EDESTADDRREQ; + case WSAEDISCON: + return EPIPE; + case WSAEDQUOT: + return EDQUOT; + case WSAEFAULT: + return EFAULT; + case WSAEHOSTDOWN: + return EHOSTDOWN; + case WSAEHOSTUNREACH: + return EHOSTUNREACH; + case WSAEINPROGRESS: + return EINPROGRESS; + case WSAEINTR: + return EINTR; + case WSAEINVAL: + return EINVAL; + case WSAEISCONN: + return EISCONN; + case WSAELOOP: + return ELOOP; + case WSAEMSGSIZE: + return EMSGSIZE; + case WSAENAMETOOLONG: + return ENAMETOOLONG; + case WSAENETDOWN: + return ENETDOWN; + case WSAENETRESET: + return ENETRESET; + case WSAENETUNREACH: + return ENETUNREACH; + case WSAENOBUFS: + return ENOBUFS; + case WSAENOPROTOOPT: + return ENOPROTOOPT; + case WSAENOTCONN: + return ENOTCONN; + case WSAENOTEMPTY: + return ENOTEMPTY; + case WSAENOTSOCK: + return ENOTSOCK; + case WSAEOPNOTSUPP: + return EOPNOTSUPP; + case WSAEPFNOSUPPORT: + return EPFNOSUPPORT; + case WSAEPROCLIM: + return EPROCLIM; + case WSAEPROTONOSUPPORT: + return EPROTONOSUPPORT; + case WSAEPROTOTYPE: + return EPROTOTYPE; + case WSAEREMOTE: + return EREMOTE; + case WSAESHUTDOWN: + return ESHUTDOWN; + case WSAESOCKTNOSUPPORT: + return ESOCKTNOSUPPORT; + case WSAESTALE: + return ESTALE; + case WSAETIMEDOUT: + return ETIMEDOUT; + case WSAETOOMANYREFS: + return ETOOMANYREFS; + case WSAEUSERS: + return EUSERS; + case WSAEWOULDBLOCK: + return EWOULDBLOCK; + } + + return 0; +#elif defined(OF_AMIGAOS) + return Errno(); +#else + return errno; +#endif +} + +#ifndef OF_WII +int +of_getsockname(OFSocketHandle sock, struct sockaddr *restrict addr, + socklen_t *restrict addrLen) +{ + int ret; + +# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) + [mutex lock]; +# endif + ret = getsockname(sock, addr, addrLen); +# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) + [mutex unlock]; +# endif + + return ret; +} +#endif + +OFSocketAddress +OFSocketAddressParseIPv4(OFString *IPv4, uint16_t port) +{ + void *pool = objc_autoreleasePoolPush(); + OFCharacterSet *whitespaceCharacterSet = + [OFCharacterSet whitespaceCharacterSet]; + OFSocketAddress ret; + struct sockaddr_in *addrIn = &ret.sockaddr.in; + OFArray OF_GENERIC(OFString *) *components; + uint32_t addr; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyIPv4; +#if defined(OF_WII) || defined(OF_NINTENDO_3DS) + ret.length = 8; +#else + ret.length = sizeof(ret.sockaddr.in); +#endif + + addrIn->sin_family = AF_INET; + addrIn->sin_port = OFToBigEndian16(port); +#ifdef OF_WII + addrIn->sin_len = ret.length; +#endif + + components = [IPv4 componentsSeparatedByString: @"."]; + + if (components.count != 4) + @throw [OFInvalidFormatException exception]; + + addr = 0; + + for (OFString *component in components) { + unsigned long long number; + + if (component.length == 0) + @throw [OFInvalidFormatException exception]; + + if ([component indexOfCharacterFromSet: + whitespaceCharacterSet] != OFNotFound) + @throw [OFInvalidFormatException exception]; + + number = component.unsignedLongLongValue; + + if (number > UINT8_MAX) + @throw [OFInvalidFormatException exception]; + + addr = (addr << 8) | ((uint32_t)number & 0xFF); + } + + addrIn->sin_addr.s_addr = OFToBigEndian32(addr); + + objc_autoreleasePoolPop(pool); + + return ret; +} + +static uint16_t +parseIPv6Component(OFString *component) +{ + unsigned long long number; + + if ([component indexOfCharacterFromSet: + [OFCharacterSet whitespaceCharacterSet]] != OFNotFound) + @throw [OFInvalidFormatException exception]; + + number = [component unsignedLongLongValueWithBase: 16]; + + if (number > UINT16_MAX) + @throw [OFInvalidFormatException exception]; + + return (uint16_t)number; +} + +OFSocketAddress +OFSocketAddressParseIPv6(OFString *IPv6, uint16_t port) +{ + void *pool = objc_autoreleasePoolPush(); + OFSocketAddress ret; + struct sockaddr_in6 *addrIn6 = &ret.sockaddr.in6; + size_t doubleColon; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyIPv6; + ret.length = sizeof(ret.sockaddr.in6); + +#ifdef AF_INET6 + addrIn6->sin6_family = AF_INET6; +#else + addrIn6->sin6_family = AF_UNSPEC; +#endif + addrIn6->sin6_port = OFToBigEndian16(port); + + doubleColon = [IPv6 rangeOfString: @"::"].location; + + if (doubleColon != OFNotFound) { + OFString *left = [IPv6 substringToIndex: doubleColon]; + OFString *right = [IPv6 substringFromIndex: doubleColon + 2]; + OFArray OF_GENERIC(OFString *) *leftComponents; + OFArray OF_GENERIC(OFString *) *rightComponents; + size_t i; + + if ([right hasPrefix: @":"] || [right containsString: @"::"]) + @throw [OFInvalidFormatException exception]; + + leftComponents = [left componentsSeparatedByString: @":"]; + rightComponents = [right componentsSeparatedByString: @":"]; + + if (leftComponents.count + rightComponents.count > 7) + @throw [OFInvalidFormatException exception]; + + i = 0; + for (OFString *component in leftComponents) { + uint16_t number = parseIPv6Component(component); + + addrIn6->sin6_addr.s6_addr[i++] = number >> 8; + addrIn6->sin6_addr.s6_addr[i++] = number; + } + + i = 16; + for (OFString *component in rightComponents.reversedArray) { + uint16_t number = parseIPv6Component(component); + + addrIn6->sin6_addr.s6_addr[--i] = number; + addrIn6->sin6_addr.s6_addr[--i] = number >> 8; + } + } else { + OFArray OF_GENERIC(OFString *) *components = + [IPv6 componentsSeparatedByString: @":"]; + size_t i; + + if (components.count != 8) + @throw [OFInvalidFormatException exception]; + + i = 0; + for (OFString *component in components) { + uint16_t number; + + if (component.length == 0) + @throw [OFInvalidFormatException exception]; + + number = parseIPv6Component(component); + + addrIn6->sin6_addr.s6_addr[i++] = number >> 8; + addrIn6->sin6_addr.s6_addr[i++] = number; + } + } + + objc_autoreleasePoolPop(pool); + + return ret; +} + +OFSocketAddress +OFSocketAddressParseIP(OFString *IP, uint16_t port) +{ + OFSocketAddress ret; + + @try { + ret = OFSocketAddressParseIPv6(IP, port); + } @catch (OFInvalidFormatException *e) { + ret = OFSocketAddressParseIPv4(IP, port); + } + + return ret; +} + +OFSocketAddress +OFSocketAddressMakeIPX(const unsigned char node[IPX_NODE_LEN], uint32_t network, + uint16_t port) +{ + OFSocketAddress ret; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyIPX; + ret.length = sizeof(ret.sockaddr.ipx); + +#ifdef AF_IPX + ret.sockaddr.ipx.sipx_family = AF_IPX; +#else + ret.sockaddr.ipx.sipx_family = AF_UNSPEC; +#endif + memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); + network = OFToBigEndian32(network); + memcpy(&ret.sockaddr.ipx.sipx_network, &network, + sizeof(ret.sockaddr.ipx.sipx_network)); + ret.sockaddr.ipx.sipx_port = OFToBigEndian16(port); + + return ret; +} + +bool +OFSocketAddressEqual(const OFSocketAddress *address1, + const OFSocketAddress *address2) +{ + const struct sockaddr_in *addrIn1, *addrIn2; + const struct sockaddr_in6 *addrIn6_1, *addrIn6_2; + const struct sockaddr_ipx *addrIPX1, *addrIPX2; + + if (address1->family != address2->family) + return false; + + switch (address1->family) { + case OFSocketAddressFamilyIPv4: +#if defined(OF_WII) || defined(OF_NINTENDO_3DS) + if (address1->length < 8 || address2->length < 8) + @throw [OFInvalidArgumentException exception]; +#else + if (address1->length < (socklen_t)sizeof(struct sockaddr_in) || + address2->length < (socklen_t)sizeof(struct sockaddr_in)) + @throw [OFInvalidArgumentException exception]; +#endif + + addrIn1 = &address1->sockaddr.in; + addrIn2 = &address2->sockaddr.in; + + if (addrIn1->sin_port != addrIn2->sin_port) + return false; + if (addrIn1->sin_addr.s_addr != addrIn2->sin_addr.s_addr) + return false; + + break; + case OFSocketAddressFamilyIPv6: + if (address1->length < (socklen_t)sizeof(struct sockaddr_in6) || + address2->length < (socklen_t)sizeof(struct sockaddr_in6)) + @throw [OFInvalidArgumentException exception]; + + addrIn6_1 = &address1->sockaddr.in6; + addrIn6_2 = &address2->sockaddr.in6; + + if (addrIn6_1->sin6_port != addrIn6_2->sin6_port) + return false; + if (memcmp(addrIn6_1->sin6_addr.s6_addr, + addrIn6_2->sin6_addr.s6_addr, + sizeof(addrIn6_1->sin6_addr.s6_addr)) != 0) + return false; + + break; + case OFSocketAddressFamilyIPX: + if (address1->length < (socklen_t)sizeof(struct sockaddr_ipx) || + address2->length < (socklen_t)sizeof(struct sockaddr_ipx)) + @throw [OFInvalidArgumentException exception]; + + addrIPX1 = &address1->sockaddr.ipx; + addrIPX2 = &address2->sockaddr.ipx; + + if (addrIPX1->sipx_port != addrIPX2->sipx_port) + return false; + if (memcmp(&addrIPX1->sipx_network, &addrIPX2->sipx_network, + 4) != 0) + return false; + if (memcmp(addrIPX1->sipx_node, addrIPX2->sipx_node, + IPX_NODE_LEN) != 0) + return false; + + break; + default: + @throw [OFInvalidArgumentException exception]; + } + + return true; +} + +unsigned long +OFSocketAddressHash(const OFSocketAddress *address) +{ + unsigned long hash; + + OFHashInit(&hash); + OFHashAdd(&hash, address->family); + + switch (address->family) { + case OFSocketAddressFamilyIPv4: +#if defined(OF_WII) || defined(OF_NINTENDO_3DS) + if (address->length < 8) + @throw [OFInvalidArgumentException exception]; +#else + if (address->length < (socklen_t)sizeof(struct sockaddr_in)) + @throw [OFInvalidArgumentException exception]; +#endif + + OFHashAdd(&hash, address->sockaddr.in.sin_port >> 8); + OFHashAdd(&hash, address->sockaddr.in.sin_port); + OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 24); + OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 16); + OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 8); + OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr); + + break; + case OFSocketAddressFamilyIPv6: + if (address->length < (socklen_t)sizeof(struct sockaddr_in6)) + @throw [OFInvalidArgumentException exception]; + + OFHashAdd(&hash, address->sockaddr.in6.sin6_port >> 8); + OFHashAdd(&hash, address->sockaddr.in6.sin6_port); + + for (size_t i = 0; + i < sizeof(address->sockaddr.in6.sin6_addr.s6_addr); i++) + OFHashAdd(&hash, + address->sockaddr.in6.sin6_addr.s6_addr[i]); + + break; + case OFSocketAddressFamilyIPX:; + unsigned char network[ + sizeof(address->sockaddr.ipx.sipx_network)]; + + if (address->length < (socklen_t)sizeof(struct sockaddr_ipx)) + @throw [OFInvalidArgumentException exception]; + + OFHashAdd(&hash, address->sockaddr.ipx.sipx_port >> 8); + OFHashAdd(&hash, address->sockaddr.ipx.sipx_port); + + memcpy(network, &address->sockaddr.ipx.sipx_network, + sizeof(network)); + + for (size_t i = 0; i < sizeof(network); i++) + OFHashAdd(&hash, network[i]); + + for (size_t i = 0; i < IPX_NODE_LEN; i++) + OFHashAdd(&hash, address->sockaddr.ipx.sipx_node[i]); + + break; + default: + @throw [OFInvalidArgumentException exception]; + } + + OFHashFinalize(&hash); + + return hash; +} + +static OFString * +IPv4String(const OFSocketAddress *address) +{ + const struct sockaddr_in *addrIn = &address->sockaddr.in; + uint32_t addr = OFFromBigEndian32(addrIn->sin_addr.s_addr); + OFString *string; + + string = [OFString stringWithFormat: @"%u.%u.%u.%u", + (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, + (addr & 0x0000FF00) >> 8, addr & 0x000000FF]; + + return string; +} + +static OFString * +IPv6String(const OFSocketAddress *address) +{ + OFMutableString *string = [OFMutableString string]; + const struct sockaddr_in6 *addrIn6 = &address->sockaddr.in6; + int_fast8_t zerosStart = -1, maxZerosStart = -1; + uint_fast8_t zerosCount = 0, maxZerosCount = 0; + bool first = true; + + for (uint_fast8_t i = 0; i < 16; i += 2) { + if (addrIn6->sin6_addr.s6_addr[i] == 0 && + addrIn6->sin6_addr.s6_addr[i + 1] == 0) { + if (zerosStart >= 0) + zerosCount++; + else { + zerosStart = i; + zerosCount = 1; + } + } else { + if (zerosCount > maxZerosCount) { + maxZerosStart = zerosStart; + maxZerosCount = zerosCount; + } + + zerosStart = -1; + } + } + if (zerosCount > maxZerosCount) { + maxZerosStart = zerosStart; + maxZerosCount = zerosCount; + } + + if (maxZerosCount >= 2) { + for (int_fast8_t i = 0; i < maxZerosStart; i += 2) { + [string appendFormat: + (first ? @"%x" : @":%x"), + (addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i] << 8) | + addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i + 1]]; + first = false; + } + + [string appendString: @"::"]; + first = true; + + for (int_fast8_t i = maxZerosStart + (maxZerosCount * 2); + i < 16; i += 2) { + [string appendFormat: + (first ? @"%x" : @":%x"), + (addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i] << 8) | + addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i + 1]]; + first = false; + } + } else { + for (uint_fast8_t i = 0; i < 16; i += 2) { + [string appendFormat: + (first ? @"%x" : @":%x"), + (addrIn6->sin6_addr.s6_addr[i] << 8) | + addrIn6->sin6_addr.s6_addr[i + 1]]; + first = false; + } + } + + [string makeImmutable]; + + return string; +} + +OFString * +OFSocketAddressString(const OFSocketAddress *address) +{ + switch (address->family) { + case OFSocketAddressFamilyIPv4: + return IPv4String(address); + case OFSocketAddressFamilyIPv6: + return IPv6String(address); + default: + @throw [OFInvalidArgumentException exception]; + } +} + +void +OFSocketAddressSetPort(OFSocketAddress *address, uint16_t port) +{ + switch (address->family) { + case OFSocketAddressFamilyIPv4: + address->sockaddr.in.sin_port = OFToBigEndian16(port); + break; + case OFSocketAddressFamilyIPv6: + address->sockaddr.in6.sin6_port = OFToBigEndian16(port); + break; + case OFSocketAddressFamilyIPX: + address->sockaddr.ipx.sipx_port = OFToBigEndian16(port); + break; + default: + @throw [OFInvalidArgumentException exception]; + } +} + +uint16_t +OFSocketAddressPort(const OFSocketAddress *address) +{ + switch (address->family) { + case OFSocketAddressFamilyIPv4: + return OFFromBigEndian16(address->sockaddr.in.sin_port); + case OFSocketAddressFamilyIPv6: + return OFFromBigEndian16(address->sockaddr.in6.sin6_port); + case OFSocketAddressFamilyIPX: + return OFFromBigEndian16(address->sockaddr.ipx.sipx_port); + default: + @throw [OFInvalidArgumentException exception]; + } +} + +void +OFSocketAddressSetIPXNetwork(OFSocketAddress *address, uint32_t network) +{ + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + network = OFToBigEndian32(network); + memcpy(&address->sockaddr.ipx.sipx_network, &network, + sizeof(address->sockaddr.ipx.sipx_network)); +} + +uint32_t +OFSocketAddressIPXNetwork(const OFSocketAddress *address) +{ + uint32_t network; + + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + memcpy(&network, &address->sockaddr.ipx.sipx_network, sizeof(network)); + + return OFFromBigEndian32(network); +} + +void +OFSocketAddressSetIPXNode(OFSocketAddress *address, + const unsigned char node[IPX_NODE_LEN]) +{ + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + memcpy(address->sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); +} + +void +OFSocketAddressIPXNode(const OFSocketAddress *address, + unsigned char node[IPX_NODE_LEN]) +{ + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + memcpy(node, address->sockaddr.ipx.sipx_node, IPX_NODE_LEN); +} ADDED src/OFStrPTime.h Index: src/OFStrPTime.h ================================================================== --- src/OFStrPTime.h +++ src/OFStrPTime.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#include + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifdef __cplusplus +extern "C" { +#endif +extern const char *OFStrPTime(const char *buf, const char *fmt, struct tm *tm, + short *tz); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFStrPTime.m Index: src/OFStrPTime.m ================================================================== --- src/OFStrPTime.m +++ src/OFStrPTime.m @@ -0,0 +1,231 @@ +/* + * 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 + +#include + +#import "macros.h" + +const char * +OFStrPTime(const char *buffer, const char *format, struct tm *tm, short *tz) +{ + enum { + StateSearchConversionSpecifier, + StateInConversionSpecifier + } state = StateSearchConversionSpecifier; + size_t j, bufferLen, formatLen; + + bufferLen = strlen(buffer); + formatLen = strlen(format); + + j = 0; + for (size_t i = 0; i < formatLen; i++) { + if (j >= bufferLen) + return NULL; + + switch (state) { + case StateSearchConversionSpecifier: + if (format[i] == '%') + state = StateInConversionSpecifier; + else if (format[i] != buffer[j++]) + return NULL; + + break; + + case StateInConversionSpecifier:; + int k, maxLen, number = 0; + + switch (format[i]) { + case 'd': + case 'e': + case 'H': + case 'm': + case 'M': + case 'S': + case 'y': + maxLen = 2; + break; + case 'Y': + maxLen = 4; + break; + case '%': + case 'a': + case 'b': + case 'n': + case 't': + case 'z': + maxLen = 0; + break; + default: + return NULL; + } + + if (maxLen > 0 && (buffer[j] < '0' || buffer[j] > '9')) + return NULL; + + for (k = 0; k < maxLen && j < bufferLen && + buffer[j] >= '0' && buffer[j] <= '9'; k++, j++) { + number *= 10; + number += buffer[j] - '0'; + } + + switch (format[i]) { + case 'a': + if (bufferLen < j + 3) + return NULL; + + if (memcmp(buffer + j, "Sun", 3) == 0) + tm->tm_wday = 0; + else if (memcmp(buffer + j, "Mon", 3) == 0) + tm->tm_wday = 1; + else if (memcmp(buffer + j, "Tue", 3) == 0) + tm->tm_wday = 2; + else if (memcmp(buffer + j, "Wed", 3) == 0) + tm->tm_wday = 3; + else if (memcmp(buffer + j, "Thu", 3) == 0) + tm->tm_wday = 4; + else if (memcmp(buffer + j, "Fri", 3) == 0) + tm->tm_wday = 5; + else if (memcmp(buffer + j, "Sat", 3) == 0) + tm->tm_wday = 6; + else + return NULL; + + j += 3; + break; + case 'b': + if (bufferLen < j + 3) + return NULL; + + if (memcmp(buffer + j, "Jan", 3) == 0) + tm->tm_mon = 0; + else if (memcmp(buffer + j, "Feb", 3) == 0) + tm->tm_mon = 1; + else if (memcmp(buffer + j, "Mar", 3) == 0) + tm->tm_mon = 2; + else if (memcmp(buffer + j, "Apr", 3) == 0) + tm->tm_mon = 3; + else if (memcmp(buffer + j, "May", 3) == 0) + tm->tm_mon = 4; + else if (memcmp(buffer + j, "Jun", 3) == 0) + tm->tm_mon = 5; + else if (memcmp(buffer + j, "Jul", 3) == 0) + tm->tm_mon = 6; + else if (memcmp(buffer + j, "Aug", 3) == 0) + tm->tm_mon = 7; + else if (memcmp(buffer + j, "Sep", 3) == 0) + tm->tm_mon = 8; + else if (memcmp(buffer + j, "Oct", 3) == 0) + tm->tm_mon = 9; + else if (memcmp(buffer + j, "Nov", 3) == 0) + tm->tm_mon = 10; + else if (memcmp(buffer + j, "Dec", 3) == 0) + tm->tm_mon = 11; + else + return NULL; + + j += 3; + break; + case 'd': + case 'e': + tm->tm_mday = number; + break; + case 'H': + tm->tm_hour = number; + break; + case 'm': + tm->tm_mon = number - 1; + break; + case 'M': + tm->tm_min = number; + break; + case 'S': + tm->tm_sec = number; + break; + case 'y': + if (number <= 68) + number += 100; + + tm->tm_year = number; + break; + case 'Y': + if (number < 1900) + return NULL; + + tm->tm_year = number - 1900; + break; + case 'z': + if (buffer[j] == '-' || buffer[j] == '+') { + const char *b = buffer + j; + + if (bufferLen < j + 5) + return NULL; + + if (tz == NULL) + break; + + *tz = (((short)b[1] - '0') * 600 + + ((short)b[2] - '0') * 60 + + ((short)b[3] - '0') * 10 + + ((short)b[4] - '0')) * + (b[0] == '-' ? -1 : 1); + + j += 5; + } else if (buffer[j] == 'Z') { + if (tz != NULL) + *tz = 0; + + j++; + } else if (buffer[j] == 'G') { + if (bufferLen < j + 3) + return NULL; + + if (buffer[j + 1] != 'M' || + buffer[j + 2] != 'T') + return NULL; + + if (tz != NULL) + *tz = 0; + + j += 3; + } else + return NULL; + + break; + case '%': + if (buffer[j++] != '%') + return NULL; + break; + case 'n': + if (buffer[j++] != '\n') + return NULL; + break; + case 't': + if (buffer[j++] != '\t') + return NULL; + break; + } + + state = StateSearchConversionSpecifier; + + break; + } + } + + return buffer + j; +} Index: src/OFStream.m ================================================================== --- src/OFStream.m +++ src/OFStream.m @@ -26,26 +26,26 @@ #ifdef HAVE_FCNTL_H # include #endif -#ifdef OF_HAVE_SOCKETS -# import "socket_helpers.h" -#endif - #include "platform.h" #if !defined(OF_WINDOWS) && !defined(OF_MORPHOS) # include #endif #import "OFStream.h" #import "OFStream+Private.h" +#import "OFASPrintF.h" #import "OFData.h" #import "OFKernelEventObserver.h" #import "OFRunLoop+Private.h" #import "OFRunLoop.h" +#ifdef OF_HAVE_SOCKETS +# import "OFSocket+Private.h" +#endif #import "OFString.h" #import "OFSystemInfo.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" @@ -54,12 +54,10 @@ #import "OFOutOfRangeException.h" #import "OFSetOptionFailedException.h" #import "OFTruncatedDataException.h" #import "OFWriteFailedException.h" -#import "of_asprintf.h" - #define MIN_READ_SIZE 512 @implementation OFStream @synthesize buffersWrites = _buffersWrites; @synthesize of_waitingForDelimiter = _waitingForDelimiter, delegate = _delegate; @@ -1627,11 +1625,11 @@ int length; if (format == nil) @throw [OFInvalidArgumentException exception]; - if ((length = of_vasprintf(&UTF8String, format.UTF8String, + if ((length = OFVASPrintF(&UTF8String, format.UTF8String, arguments)) == -1) @throw [OFInvalidFormatException exception]; @try { [self writeBuffer: UTF8String length: length]; Index: src/OFStreamSocket.h ================================================================== --- src/OFStreamSocket.h +++ src/OFStreamSocket.h @@ -12,12 +12,11 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFStream.h" - -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN /** @file */ Index: src/OFStreamSocket.m ================================================================== --- src/OFStreamSocket.m +++ src/OFStreamSocket.m @@ -27,10 +27,11 @@ #import "OFStreamSocket.h" #import "OFStreamSocket+Private.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" +#import "OFSocket+Private.h" #import "OFAcceptFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFListenFailedException.h" @@ -39,12 +40,10 @@ #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFSetOptionFailedException.h" #import "OFWriteFailedException.h" -#import "socket_helpers.h" - @implementation OFStreamSocket @dynamic delegate; @synthesize listening = _listening; + (void)initialize Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -28,10 +28,11 @@ #ifdef HAVE_XLOCALE_H # include #endif #import "OFString.h" +#import "OFASPrintF.h" #import "OFArray.h" #import "OFCharacterSet.h" #import "OFData.h" #import "OFDictionary.h" #ifdef OF_HAVE_FILES @@ -57,11 +58,10 @@ #import "OFOutOfRangeException.h" #import "OFRetrieveItemAttributesFailedException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" -#import "of_asprintf.h" #import "unicode.h" /* * It seems strtod is buggy on Win32. * However, the MinGW version __strtod seems to be ok. Index: src/OFSystemInfo.m ================================================================== --- src/OFSystemInfo.m +++ src/OFSystemInfo.m @@ -41,16 +41,15 @@ #import "OFSystemInfo.h" #import "OFApplication.h" #import "OFArray.h" #import "OFDictionary.h" #import "OFLocale.h" +#import "OFOnce.h" #import "OFString.h" #import "OFNotImplementedException.h" -#import "once.h" - #if defined(OF_MACOS) || defined(OF_IOS) # ifdef HAVE_SYSDIR_H # include # endif #endif Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -35,10 +35,12 @@ #import "OFData.h" #import "OFDate.h" #import "OFIPSocketAsyncConnector.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFString.h" #import "OFTCPSocketSOCKS5Connector.h" #import "OFThread.h" #import "OFAlreadyConnectedException.h" @@ -46,13 +48,10 @@ #import "OFGetOptionFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #import "OFSetOptionFailedException.h" -#import "socket.h" -#import "socket_helpers.h" - static const OFRunLoopMode connectRunLoopMode = @"OFTCPSocketConnectRunLoopMode"; Class of_tls_socket_class = Nil; ADDED src/OFTLSKey.h Index: src/OFTLSKey.h ================================================================== --- src/OFTLSKey.h +++ src/OFTLSKey.h @@ -0,0 +1,102 @@ +/* + * 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 "objfw-defs.h" + +#include + +#include "platform.h" + +#if !defined(OF_HAVE_THREADS) || \ + (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) +# error No thread-local storage available! +#endif + +#import "macros.h" + +#if defined(OF_HAVE_PTHREADS) +# include +typedef pthread_key_t OFTLSKey; +#elif defined(OF_WINDOWS) +# include +typedef DWORD OFTLSKey; +#elif defined(OF_MORPHOS) +# include +typedef ULONG OFTLSKey; +#elif defined(OF_AMIGAOS) +typedef struct OFTLSKey { + struct objc_hashtable *table; + struct OFTLSKey *next, *previous; +} *OFTLSKey; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern int OFTLSKeyNew(OFTLSKey *key); +extern int OFTLSKeyFree(OFTLSKey key); +#ifdef __cplusplus +} +#endif + +/* TLS keys are inlined for performance. */ + +#if defined(OF_HAVE_PTHREADS) +static OF_INLINE void * +OFTLSKeyGet(OFTLSKey key) +{ + return pthread_getspecific(key); +} + +static OF_INLINE int +OFTLSKeySet(OFTLSKey key, void *ptr) +{ + return pthread_setspecific(key, ptr); +} +#elif defined(OF_WINDOWS) +static OF_INLINE void * +OFTLSKeyGet(OFTLSKey key) +{ + return TlsGetValue(key); +} + +static OF_INLINE int +OFTLSKeySet(OFTLSKey key, void *ptr) +{ + return (TlsSetValue(key, ptr) ? 0 : EINVAL); +} +#elif defined(OF_MORPHOS) +static OF_INLINE void * +OFTLSKeyGet(OFTLSKey key) +{ + return (void *)TLSGetValue(key); +} + +static OF_INLINE int +OFTLSKeySet(OFTLSKey key, void *ptr) +{ + return (TLSSetValue(key, (APTR)ptr) ? 0 : EINVAL); +} +#elif defined(OF_AMIGAOS) +/* Those are too big too inline. */ +# ifdef __cplusplus +extern "C" { +# endif +extern void *OFTLSKeyGet(OFTLSKey key); +extern int OFTLSKeySet(OFTLSKey key, void *ptr); +# ifdef __cplusplus +} +# endif +#endif ADDED src/OFTLSKey.m Index: src/OFTLSKey.m ================================================================== --- src/OFTLSKey.m +++ src/OFTLSKey.m @@ -0,0 +1,28 @@ +/* + * 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 "platform.h" + +#if defined(OF_HAVE_PTHREADS) +# include "platform/posix/OFTLSKey.m" +#elif defined(OF_WINDOWS) +# include "platform/windows/OFTLSKey.m" +#elif defined(OF_MORPHOS) +# include "platform/morphos/OFTLSKey.m" +#elif defined(OF_AMIGAOS) +# include "platform/amiga/OFTLSKey.m" +#endif Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -14,13 +14,12 @@ */ #include #import "OFObject.h" - #ifdef OF_HAVE_THREADS -# import "thread.h" +# import "OFPlainThread.h" #endif OF_ASSUME_NONNULL_BEGIN /** @file */ Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -46,10 +46,13 @@ # include <3ds/svc.h> #endif #import "OFThread.h" #import "OFThread+Private.h" +#ifdef OF_HAVE_ATOMIC_OPS +# import "OFAtomic.h" +#endif #import "OFDate.h" #import "OFDictionary.h" #ifdef OF_HAVE_SOCKETS # import "OFDNSResolver.h" #endif @@ -75,18 +78,14 @@ # import "OFThreadJoinFailedException.h" # import "OFThreadStartFailedException.h" # import "OFThreadStillRunningException.h" #endif -#ifdef OF_HAVE_ATOMIC_OPS -# import "atomic.h" -#endif - #if defined(OF_HAVE_THREADS) -# import "tlskey.h" +# import "OFTLSKey.h" # if defined(OF_AMIGAOS) && defined(OF_HAVE_SOCKETS) -# import "socket.h" +# import "OFSocket.h" # endif static OFTLSKey threadSelfKey; static OFThread *mainThread; #elif defined(OF_HAVE_SOCKETS) Index: src/OFUDPSocket.m ================================================================== --- src/OFUDPSocket.m +++ src/OFUDPSocket.m @@ -28,18 +28,17 @@ #import "OFUDPSocket.h" #import "OFUDPSocket+Private.h" #import "OFDNSResolver.h" #import "OFData.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFThread.h" #import "OFAlreadyConnectedException.h" #import "OFBindFailedException.h" -#import "socket.h" -#import "socket_helpers.h" - @implementation OFUDPSocket @dynamic delegate; - (uint16_t)of_bindToAddress: (OFSocketAddress *)address extraType: (int)extraType OF_DIRECT Index: src/OFURL.m ================================================================== --- src/OFURL.m +++ src/OFURL.m @@ -19,25 +19,23 @@ #include #import "OFURL.h" #import "OFArray.h" #import "OFDictionary.h" -#import "OFNumber.h" -#import "OFString.h" -#import "OFXMLElement.h" - #ifdef OF_HAVE_FILES # import "OFFileManager.h" # import "OFFileURLHandler.h" #endif +#import "OFNumber.h" +#import "OFOnce.h" +#import "OFString.h" +#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" -#import "once.h" - @interface OFURLAllowedCharacterSetBase: OFCharacterSet @end @interface OFURLAllowedCharacterSet: OFURLAllowedCharacterSetBase @end Index: src/OFUTF8String.m ================================================================== --- src/OFUTF8String.m +++ src/OFUTF8String.m @@ -23,10 +23,11 @@ # include #endif #import "OFUTF8String.h" #import "OFUTF8String+Private.h" +#import "OFASPrintF.h" #import "OFArray.h" #import "OFData.h" #import "OFMutableUTF8String.h" #import "OFInitializationFailedException.h" @@ -34,11 +35,10 @@ #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#import "of_asprintf.h" #import "unicode.h" extern const OFChar16 of_iso_8859_2_table[]; extern const size_t of_iso_8859_2_table_offset; extern const OFChar16 of_iso_8859_3_table[]; @@ -670,11 +670,11 @@ if (format == nil) @throw [OFInvalidArgumentException exception]; _s = &_storage; - if ((cStringLength = of_vasprintf(&tmp, format.UTF8String, + if ((cStringLength = OFVASPrintF(&tmp, format.UTF8String, arguments)) == -1) @throw [OFInvalidFormatException exception]; _s->cStringLength = cStringLength; Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -18,10 +18,11 @@ #include #import "OFZIPArchive.h" #import "OFZIPArchiveEntry.h" #import "OFZIPArchiveEntry+Private.h" +#import "OFCRC32.h" #import "OFData.h" #import "OFArray.h" #import "OFDictionary.h" #import "OFStream.h" #import "OFSeekableStream.h" @@ -29,12 +30,10 @@ # import "OFFile.h" #endif #import "OFInflateStream.h" #import "OFInflate64Stream.h" -#import "crc32.h" - #import "OFChecksumMismatchException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" @@ -799,11 +798,11 @@ length = (size_t)_toRead; ret = [_decompressedStream readIntoBuffer: buffer length: length]; _toRead -= ret; - _CRC32 = of_crc32(_CRC32, buffer, ret); + _CRC32 = OFCRC32(_CRC32, buffer, ret); if (_toRead == 0) { _atEndOfStream = true; if (~_CRC32 != _entry.CRC32) { @@ -884,11 +883,11 @@ @throw [OFOutOfRangeException exception]; bytesWritten = [_stream writeBuffer: buffer length: length]; _bytesWritten += (int64_t)bytesWritten; - _CRC32 = of_crc32(_CRC32, buffer, length); + _CRC32 = OFCRC32(_CRC32, buffer, length); return bytesWritten; } - (void)close Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -236,33 +236,29 @@ #ifdef OF_HAVE_PLUGINS # import "OFPlugin.h" #endif #ifdef OF_HAVE_ATOMIC_OPS -# import "atomic.h" -#endif - -#import "OFLocking.h" -#import "OFThread.h" -#import "once.h" -#ifdef OF_HAVE_THREADS -# import "thread.h" -# import "tlskey.h" -# import "mutex.h" -# import "condition.h" -# import "OFThreadPool.h" -# import "OFMutex.h" -# import "OFRecursiveMutex.h" -# import "OFCondition.h" -#endif - -#import "base64.h" -#import "crc16.h" -#import "crc32.h" -#import "huffman_tree.h" -#import "of_asprintf.h" -#import "of_strptime.h" -#import "pbkdf2.h" -#import "scrypt.h" -#ifdef OF_HAVE_UNICODE_TABLES -# import "unicode.h" -#endif +# import "OFAtomic.h" +#endif +#import "OFLocking.h" +#import "OFOnce.h" +#import "OFThread.h" +#ifdef OF_HAVE_THREADS +# import "OFCondition.h" +# import "OFMutex.h" +# import "OFPlainCondition.h" +# import "OFPlainMutex.h" +# import "OFPlainThread.h" +# import "OFRecursiveMutex.h" +# import "OFTLSKey.h" +# import "OFThreadPool.h" +#endif + +#import "OFASPrintF.h" +#import "OFBase64.h" +#import "OFCRC16.h" +#import "OFCRC32.h" +#import "OFHuffmanTree.h" +#import "OFPBKDF2.h" +#import "OFScrypt.h" +#import "OFStrPTime.h" DELETED src/atomic.h Index: src/atomic.h ================================================================== --- src/atomic.h +++ src/atomic.h @@ -1,39 +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 - -#import "macros.h" - -#ifndef OF_HAVE_ATOMIC_OPS -# error No atomic operations available! -#endif - -#if !defined(OF_HAVE_THREADS) -# import "atomic_no_threads.h" -#elif (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) -# import "atomic_x86.h" -#elif defined(OF_POWERPC) && defined(__GNUC__) && !defined(__APPLE_CC__) && \ - !defined(OF_AIX) -# import "atomic_powerpc.h" -#elif defined(OF_HAVE_ATOMIC_BUILTINS) -# import "atomic_builtins.h" -#elif defined(OF_HAVE_SYNC_BUILTINS) -# import "atomic_sync_builtins.h" -#elif defined(OF_HAVE_OSATOMIC) -# import "atomic_osatomic.h" -#else -# error No atomic operations available! -#endif DELETED src/atomic_builtins.h Index: src/atomic_builtins.h ================================================================== --- src/atomic_builtins.h +++ src/atomic_builtins.h @@ -1,150 +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. - */ - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE bool -OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) -{ - return __atomic_compare_exchange(p, &o, &n, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); -} - -static OF_INLINE bool -OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - return __atomic_compare_exchange(p, &o, &n, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - return __atomic_compare_exchange(p, &o, &n, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); -} - -static OF_INLINE void -of_memory_barrier_full(void) -{ - __atomic_thread_fence(__ATOMIC_SEQ_CST); -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - __atomic_thread_fence(__ATOMIC_ACQUIRE); -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - __atomic_thread_fence(__ATOMIC_RELEASE); -} DELETED src/atomic_no_threads.h Index: src/atomic_no_threads.h ================================================================== --- src/atomic_no_threads.h +++ src/atomic_no_threads.h @@ -1,162 +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. - */ - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - return (*p += i); -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - return (*p += i); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return (*(char *volatile *)p += i); -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - return (*p -= i); -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - return (*p -= i); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return (*(char *volatile *)p -= i); -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - return ++*p; -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - return ++*p; -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - return --*p; -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - return --*p; -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return (*p |= i); -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return (*p |= i); -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return (*p &= i); -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return (*p &= i); -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return (*p ^= i); -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return (*p ^= i); -} - -static OF_INLINE bool -OFAtomicIntCompareSwap(volatile int *_Nonnull p, int o, int n) -{ - if (*p == o) { - *p = n; - return true; - } - - return false; -} - -static OF_INLINE bool -OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - if (*p == o) { - *p = n; - return true; - } - - return false; -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - if (*p == o) { - *p = n; - return true; - } - - return false; -} - -static OF_INLINE void -of_memory_barrier(void) -{ - /* nop */ -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - /* nop */ -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - /* nop */ -} DELETED src/atomic_osatomic.h Index: src/atomic_osatomic.h ================================================================== --- src/atomic_osatomic.h +++ src/atomic_osatomic.h @@ -1,157 +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 - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - return OSAtomicAdd32(i, p); -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - return OSAtomicAdd32(i, p); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#ifdef __LP64__ - return (void *)OSAtomicAdd64(i, (int64_t *)p); -#else - return (void *)OSAtomicAdd32(i, (int32_t *)p); -#endif -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - return OSAtomicAdd32(-i, p); -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - return OSAtomicAdd32(-i, p); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#ifdef __LP64__ - return (void *)OSAtomicAdd64(-i, (int64_t *)p); -#else - return (void *)OSAtomicAdd32(-i, (int32_t *)p); -#endif -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - return OSAtomicIncrement32(p); -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - return OSAtomicIncrement32(p); -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - return OSAtomicDecrement32(p); -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - return OSAtomicDecrement32(p); -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return OSAtomicOr32(i, p); -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return OSAtomicOr32(i, p); -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return OSAtomicAnd32(i, p); -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return OSAtomicAnd32(i, p); -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return OSAtomicXor32(i, p); -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return OSAtomicXor32(i, p); -} - -static OF_INLINE bool -OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) -{ - return OSAtomicCompareAndSwapInt(o, n, p); -} - -static OF_INLINE bool -OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - return OSAtomicCompareAndSwap32(o, n, p); -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - return OSAtomicCompareAndSwapPtr(o, n, p); -} - -static OF_INLINE void -of_memory_barrier(void) -{ - OSMemoryBarrier(); -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - OSMemoryBarrier(); -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - OSMemoryBarrier(); -} DELETED src/atomic_powerpc.h Index: src/atomic_powerpc.h ================================================================== --- src/atomic_powerpc.h +++ src/atomic_powerpc.h @@ -1,397 +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. - */ - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "add %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "add %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "add %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return (void *)i; -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "sub %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "sub %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "sub %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return (void *)i; -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - int i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "addi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "addi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - int i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "subi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "subi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "or %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "or %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "and %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "and %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "xor %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "xor %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE bool -OFAtomicIntCompAndSwap(volatile int *_Nonnull p, int o, int n) -{ - int r; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %3\n\t" - "cmpw %0, %1\n\t" - "bne 1f\n\t" - "stwcx. %2, 0, %3\n\t" - "bne- 0b\n\t" - "li %0, 1\n\t" - "b 2f\n\t" - "1:\n\t" - "stwcx. %0, 0, %3\n\t" - "li %0, 0\n\t" - "2:" - : "=&r"(r) - : "r"(o), "r"(n), "r"(p) - : "cc", "memory" - ); - - return r; -} - -static OF_INLINE bool -OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - int r; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %3\n\t" - "cmpw %0, %1\n\t" - "bne 1f\n\t" - "stwcx. %2, 0, %3\n\t" - "bne- 0b\n\t" - "li %0, 1\n\t" - "b 2f\n\t" - "1:\n\t" - "stwcx. %0, 0, %3\n\t" - "li %0, 0\n\t" - "2:" - : "=&r"(r) - : "r"(o), "r"(n), "r"(p) - : "cc", "memory" - ); - - return r; -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - int r; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %3\n\t" - "cmpw %0, %1\n\t" - "bne 1f\n\t" - "stwcx. %2, 0, %3\n\t" - "bne- 0b\n\t" - "li %0, 1\n\t" - "b 2f\n\t" - "1:\n\t" - "stwcx. %0, 0, %3\n\t" - "li %0, 0\n\t" - "2:" - : "=&r"(r) - : "r"(o), "r"(n), "r"(p) - : "cc", "memory" - ); - - return r; -} - -static OF_INLINE void -of_memory_barrier(void) -{ - __asm__ __volatile__ ( - ".long 0x7C2004AC /* lwsync */" ::: "memory" - ); -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - __asm__ __volatile__ ( - ".long 0x7C2004AC /* lwsync */" ::: "memory" - ); -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - __asm__ __volatile__ ( - ".long 0x7C2004AC /* lwsync */" ::: "memory" - ); -} DELETED src/atomic_sync_builtins.h Index: src/atomic_sync_builtins.h ================================================================== --- src/atomic_sync_builtins.h +++ src/atomic_sync_builtins.h @@ -1,147 +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. - */ - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - return __sync_add_and_fetch(p, i); -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - return __sync_add_and_fetch(p, i); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __sync_add_and_fetch(p, (void *)i); -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - return __sync_sub_and_fetch(p, i); -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - return __sync_sub_and_fetch(p, i); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __sync_sub_and_fetch(p, (void *)i); -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - return __sync_add_and_fetch(p, 1); -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - return __sync_add_and_fetch(p, 1); -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - return __sync_sub_and_fetch(p, 1); -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - return __sync_sub_and_fetch(p, 1); -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __sync_or_and_fetch(p, i); -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __sync_or_and_fetch(p, i); -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __sync_and_and_fetch(p, i); -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __sync_and_and_fetch(p, i); -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __sync_xor_and_fetch(p, i); -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __sync_xor_and_fetch(p, i); -} - -static OF_INLINE bool -OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) -{ - return __sync_bool_compare_and_swap(p, o, n); -} - -static OF_INLINE bool -OFAtomicInt32CompAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - return __sync_bool_compare_and_swap(p, o, n); -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - return __sync_bool_compare_and_swap(p, o, n); -} - -static OF_INLINE void -of_memory_barrier(void) -{ - __sync_synchronize(); -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - __sync_synchronize(); -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - __sync_synchronize(); -} DELETED src/atomic_x86.h Index: src/atomic_x86.h ================================================================== --- src/atomic_x86.h +++ src/atomic_x86.h @@ -1,502 +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. - */ - -OF_ASSUME_NONNULL_BEGIN - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "lock\n\t" - "xaddl %0, %2\n\t" - "addl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "lock\n\t" - "xaddq %0, %2\n\t" - "addq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "lock\n\t" - "xaddl %0, %2\n\t" - "addl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return i; -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#if defined(OF_X86_64) - __asm__ __volatile__ ( - "lock\n\t" - "xaddq %0, %2\n\t" - "addq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#elif defined(OF_X86) - __asm__ __volatile__ ( - "lock\n\t" - "xaddl %0, %2\n\t" - "addl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#endif -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "negl %0\n\t" - "lock\n\t" - "xaddl %0, %2\n\t" - "subl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "negq %0\n\t" - "lock\n\t" - "xaddq %0, %2\n\t" - "subq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "negl %0\n\t" - "lock\n\t" - "xaddl %0, %2\n\t" - "subl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return i; -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#if defined(OF_X86_64) - __asm__ __volatile__ ( - "negq %0\n\t" - "lock\n\t" - "xaddq %0, %2\n\t" - "subq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#elif defined(OF_X86) - __asm__ __volatile__ ( - "negl %0\n\t" - "lock\n\t" - "xaddl %0, %2\n\t" - "subl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#endif -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - int i; - - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "xorl %0, %0\n\t" - "incl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "incl %0" - : "=&r"(i) - : "m"(*p) - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "xorq %0, %0\n\t" - "incq %0\n\t" - "lock\n\t" - "xaddq %0, %1\n\t" - "incq %0" - : "=&r"(i) - : "m"(*p) - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "xorl %0, %0\n\t" - "incl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "incl %0" - : "=&r"(i) - : "m"(*p) - ); - - return i; -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - int i; - - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "xorl %0, %0\n\t" - "decl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "decl %0" - : "=&r"(i) - : "m"(*p) - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "xorq %0, %0\n\t" - "decq %0\n\t" - "lock\n\t" - "xaddq %0, %1\n\t" - "decq %0" - : "=&r"(i) - : "m"(*p) - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "xorl %0, %0\n\t" - "decl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "decl %0" - : "=&r"(i) - : "m"(*p) - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "orl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "0:\n\t" - "movq %2, %0\n\t" - "movq %0, %%rax\n\t" - "orq %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "rax", "cc" - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "orl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "andl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "0:\n\t" - "movq %2, %0\n\t" - "movq %0, %%rax\n\t" - "andq %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "rax", "cc" - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "andl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "xorl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "0:\n\t" - "movq %2, %0\n\t" - "movq %0, %%rax\n\t" - "xorq %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "rax", "cc" - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "xorl %1, %0\n\t" - "lock\n\t" - "cmpxchgl %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); - - return i; -} - -static OF_INLINE bool -OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) -{ - int r; - - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchg %2, %3\n\t" - "sete %b0\n\t" - "movzbl %b0, %0" - : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ - : "r"(n), "m"(*p) - : "cc" - ); - - return r; -} - -static OF_INLINE bool -OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - int r; - - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchg %2, %3\n\t" - "sete %b0\n\t" - "movzbl %b0, %0" - : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ - : "r"(n), "m"(*p) - : "cc" - ); - - return r; -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - int r; - - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchg %2, %3\n\t" - "sete %b0\n\t" - "movzbl %b0, %0" - : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ - : "r"(n), "m"(*p) - : "cc" - ); - - return r; -} - -static OF_INLINE void -of_memory_barrier(void) -{ - __asm__ __volatile__ ( - "mfence" ::: "memory" - ); -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - __asm__ __volatile__ ("" ::: "memory"); -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - __asm__ __volatile__ ("" ::: "memory"); -} - -OF_ASSUME_NONNULL_END DELETED src/base64.h Index: src/base64.h ================================================================== --- src/base64.h +++ src/base64.h @@ -1,39 +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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#import "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFString; -@class OFMutableData; - -#ifdef __cplusplus -extern "C" { -#endif -extern OFString *of_base64_encode(const void *, size_t); -extern bool of_base64_decode(OFMutableData *, const char *, size_t); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/base64.m Index: src/base64.m ================================================================== --- src/base64.m +++ src/base64.m @@ -1,156 +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" - -#import "OFString.h" -#import "OFData.h" -#import "base64.h" - -const uint8_t of_base64_encode_table[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', - 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/' -}; - -const int8_t of_base64_decode_table[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, -1, -1, -1, -1, -1 -}; - -OFString * -of_base64_encode(const void *data, size_t length) -{ - OFMutableString *ret = [OFMutableString string]; - uint8_t *buffer = (uint8_t *)data; - size_t i; - uint8_t rest; - char tb[4]; - uint32_t sb; - - rest = length % 3; - - for (i = 0; i < length - rest; i += 3) { - sb = (buffer[i] << 16) | (buffer[i + 1] << 8) | buffer[i + 2]; - - tb[0] = of_base64_encode_table[(sb & 0xFC0000) >> 18]; - tb[1] = of_base64_encode_table[(sb & 0x03F000) >> 12]; - tb[2] = of_base64_encode_table[(sb & 0x000FC0) >> 6]; - tb[3] = of_base64_encode_table[sb & 0x00003F]; - - [ret appendCString: tb - encoding: OFStringEncodingASCII - length: 4]; - } - - switch (rest) { - case 1: - tb[0] = of_base64_encode_table[buffer[i] >> 2]; - tb[1] = of_base64_encode_table[(buffer[i] & 3) << 4]; - tb[2] = tb[3] = '='; - - [ret appendCString: tb - encoding: OFStringEncodingASCII - length: 4]; - - break; - case 2: - sb = (buffer[i] << 16) | (buffer[i + 1] << 8); - - tb[0] = of_base64_encode_table[(sb & 0xFC0000) >> 18]; - tb[1] = of_base64_encode_table[(sb & 0x03F000) >> 12]; - tb[2] = of_base64_encode_table[(sb & 0x000FC0) >> 6]; - tb[3] = '='; - - [ret appendCString: tb - encoding: OFStringEncodingASCII - length: 4]; - - break; - } - - [ret makeImmutable]; - - return ret; -} - -bool -of_base64_decode(OFMutableData *data, const char *string, size_t length) -{ - const uint8_t *buffer = (const uint8_t *)string; - size_t i; - - if ((length & 3) != 0) - return false; - - if (data.itemSize != 1) - return false; - - for (i = 0; i < length; i += 4) { - uint32_t sb = 0; - uint8_t count = 3; - char db[3]; - int8_t tmp; - - if (buffer[i] > 0x7F || buffer[i + 1] > 0x7F || - buffer[i + 2] > 0x7F || buffer[i + 3] > 0x7F) - return false; - - if (buffer[i] == '=' || buffer[i + 1] == '=' || - (buffer[i + 2] == '=' && buffer[i + 3] != '=')) - return false; - - if (buffer[i + 2] == '=') - count--; - if (buffer[i + 3] == '=') - count--; - - if ((tmp = of_base64_decode_table[buffer[i]]) == -1) - return false; - - sb |= tmp << 18; - - if ((tmp = of_base64_decode_table[buffer[i + 1]]) == -1) - return false; - - sb |= tmp << 12; - - if ((tmp = of_base64_decode_table[buffer[i + 2]]) == -1) - return false; - - sb |= tmp << 6; - - if ((tmp = of_base64_decode_table[buffer[i + 3]]) == -1) - return false; - - sb |= tmp; - - db[0] = (sb & 0xFF0000) >> 16; - db[1] = (sb & 0x00FF00) >> 8; - db[2] = sb & 0x0000FF; - - [data addItems: db count: count]; - } - - return true; -} DELETED src/condition.h Index: src/condition.h ================================================================== --- src/condition.h +++ src/condition.h @@ -1,69 +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 "objfw-defs.h" - -#include "platform.h" - -#if !defined(OF_HAVE_THREADS) || \ - (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) -# error No conditions available! -#endif - -/* For OFTimeInterval */ -#import "OFObject.h" - -#import "mutex.h" - -#if defined(OF_HAVE_PTHREADS) -# include -typedef pthread_cond_t OFPlainCondition; -#elif defined(OF_WINDOWS) -# include -typedef struct { - HANDLE event; - volatile int count; -} OFPlainCondition; -#elif defined(OF_AMIGAOS) -# include -typedef struct { - struct OFPlainConditionWaitingTask { - struct Task *task; - unsigned char sigBit; - struct OFPlainConditionWaitingTask *next; - } *waitingTasks; -} OFPlainCondition; -#endif - -#ifdef __cplusplus -extern "C" { -#endif -extern int OFPlainConditionNew(OFPlainCondition *condition); -extern int OFPlainConditionSignal(OFPlainCondition *condition); -extern int OFPlainConditionBroadcast(OFPlainCondition *condition); -extern int OFPlainConditionWait(OFPlainCondition *condition, - OFPlainMutex *mutex); -extern int OFPlainConditionTimedWait(OFPlainCondition *condition, - OFPlainMutex *mutex, OFTimeInterval timeout); -#ifdef OF_AMIGAOS -extern int OFPlainConditionWaitOrExecSignal(OFPlainCondition *condition, - OFPlainMutex *mutex, ULONG *signalMask); -extern int OFPlainConditionTimedWaitOrExecSignal(OFPlainCondition *condition, - OFPlainMutex *mutex, OFTimeInterval timeout, ULONG *signalMask); -#endif -extern int OFPlainConditionFree(OFPlainCondition *condition); -#ifdef __cplusplus -} -#endif DELETED src/condition.m Index: src/condition.m ================================================================== --- src/condition.m +++ src/condition.m @@ -1,26 +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 "platform.h" - -#if defined(OF_HAVE_PTHREADS) -# include "platform/posix/condition.m" -#elif defined(OF_WINDOWS) -# include "platform/windows/condition.m" -#elif defined(OF_AMIGAOS) -# include "platform/amiga/condition.m" -#endif DELETED src/crc16.h Index: src/crc16.h ================================================================== --- src/crc16.h +++ src/crc16.h @@ -1,32 +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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#import "macros.h" - -#ifdef __cplusplus -extern "C" { -#endif -extern uint16_t of_crc16(uint16_t crc, const void *_Nonnull bytes, - size_t length); -#ifdef __cplusplus -} -#endif DELETED src/crc16.m Index: src/crc16.m ================================================================== --- src/crc16.m +++ src/crc16.m @@ -1,35 +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" - -#import "crc16.h" - -#define CRC16_MAGIC 0xA001 - -uint16_t -of_crc16(uint16_t crc, const void *bytes_, size_t length) -{ - const unsigned char *bytes = bytes_; - - for (size_t i = 0; i < length; i++) { - crc ^= bytes[i]; - - for (uint8_t j = 0; j < 8; j++) - crc = (crc >> 1) ^ (CRC16_MAGIC & (~(crc & 1) + 1)); - } - - return crc; -} DELETED src/crc32.h Index: src/crc32.h ================================================================== --- src/crc32.h +++ src/crc32.h @@ -1,32 +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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#import "macros.h" - -#ifdef __cplusplus -extern "C" { -#endif -extern uint32_t of_crc32(uint32_t crc, const void *_Nonnull bytes, - size_t length); -#ifdef __cplusplus -} -#endif DELETED src/crc32.m Index: src/crc32.m ================================================================== --- src/crc32.m +++ src/crc32.m @@ -1,35 +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" - -#import "crc32.h" - -#define CRC32_MAGIC 0xEDB88320 - -uint32_t -of_crc32(uint32_t crc, const void *bytes_, size_t length) -{ - const unsigned char *bytes = bytes_; - - for (size_t i = 0; i < length; i++) { - crc ^= bytes[i]; - - for (uint8_t j = 0; j < 8; j++) - crc = (crc >> 1) ^ (CRC32_MAGIC & (~(crc & 1) + 1)); - } - - return crc; -} Index: src/exceptions/OFBindFailedException.h ================================================================== --- src/exceptions/OFBindFailedException.h +++ src/exceptions/OFBindFailedException.h @@ -17,11 +17,11 @@ #ifndef OF_HAVE_SOCKETS # error No sockets available! #endif -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN /** * @class OFBindFailedException \ Index: src/exceptions/OFConnectionFailedException.h ================================================================== --- src/exceptions/OFConnectionFailedException.h +++ src/exceptions/OFConnectionFailedException.h @@ -17,11 +17,11 @@ #ifndef OF_HAVE_SOCKETS # error No sockets available! #endif -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN /** * @class OFConnectionFailedException \ Index: src/exceptions/OFException.m ================================================================== --- src/exceptions/OFException.m +++ src/exceptions/OFException.m @@ -25,21 +25,20 @@ #endif #import "OFException.h" #import "OFArray.h" #import "OFLocale.h" +#ifdef OF_HAVE_THREADS +# import "OFPlainMutex.h" +#endif #import "OFString.h" #import "OFSystemInfo.h" #import "OFInitializationFailedException.h" #import "OFLockFailedException.h" #import "OFUnlockFailedException.h" -#ifdef OF_HAVE_THREADS -# import "mutex.h" -#endif - #if defined(OF_WINDOWS) && defined(OF_HAVE_SOCKETS) # include #endif #if defined(OF_ARM) && !defined(__ARM_DWARF_EH__) DELETED src/huffman_tree.h Index: src/huffman_tree.h ================================================================== --- src/huffman_tree.h +++ src/huffman_tree.h @@ -1,66 +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 -#include - -#import "macros.h" - -#import "OFInvalidFormatException.h" - -OF_ASSUME_NONNULL_BEGIN - -struct of_huffman_tree { - struct of_huffman_tree *_Nullable leaves[2]; - uint16_t value; -}; - -static OF_INLINE bool -of_huffman_tree_walk(id _Nullable stream, - bool (*bitReader)(id _Nullable, uint16_t *_Nonnull, uint8_t), - struct of_huffman_tree *_Nonnull *_Nonnull tree, uint16_t *_Nonnull value) -{ - struct of_huffman_tree *iter = *tree; - uint16_t bits; - - while (iter->value == 0xFFFF) { - if OF_UNLIKELY (!bitReader(stream, &bits, 1)) { - *tree = iter; - return false; - } - - if OF_UNLIKELY (iter->leaves[bits] == NULL) - @throw [OFInvalidFormatException exception]; - - iter = iter->leaves[bits]; - } - - *value = iter->value; - return true; -} - -#ifdef __cplusplus -extern "C" { -#endif -extern struct of_huffman_tree *_Nonnull of_huffman_tree_construct( - uint8_t lengths[_Nonnull], uint16_t count); -extern struct of_huffman_tree *_Nonnull of_huffman_tree_construct_single( - uint16_t value); -extern void of_huffman_tree_release(struct of_huffman_tree *_Nonnull tree); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/huffman_tree.m Index: src/huffman_tree.m ================================================================== --- src/huffman_tree.m +++ src/huffman_tree.m @@ -1,130 +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 -#include - -#import "huffman_tree.h" - -#import "OFInvalidFormatException.h" -#import "OFOutOfMemoryException.h" - -static struct of_huffman_tree * -newTree(void) -{ - struct of_huffman_tree *tree; - - tree = OFAllocMemory(1, sizeof(*tree)); - tree->leaves[0] = tree->leaves[1] = NULL; - tree->value = 0xFFFF; - - return tree; -} - -static void -insertTree(struct of_huffman_tree *tree, uint16_t code, uint8_t length, - uint16_t value) -{ - while (length > 0) { - uint8_t bit; - - length--; - bit = (code & (1u << length)) >> length; - - if (tree->leaves[bit] == NULL) - tree->leaves[bit] = newTree(); - - tree = tree->leaves[bit]; - } - - tree->value = value; -} - -struct of_huffman_tree * -of_huffman_tree_construct(uint8_t lengths[], uint16_t count) -{ - struct of_huffman_tree *tree; - uint16_t *lengthCount = NULL; - uint16_t code, maxCode = 0, *nextCode = NULL; - uint_fast8_t maxBit = 0; - - @try { - for (uint16_t i = 0; i < count; i++) { - uint_fast8_t length = lengths[i]; - - if OF_UNLIKELY (length > maxBit) { - lengthCount = OFResizeMemory(lengthCount, - length + 1, sizeof(uint16_t)); - nextCode = OFResizeMemory(nextCode, - length + 1, sizeof(uint16_t)); - - for (uint_fast8_t j = maxBit + 1; j <= length; - j++) { - lengthCount[j] = 0; - nextCode[j] = 0; - } - - maxBit = length; - } - - if (length > 0) { - lengthCount[length]++; - maxCode = i; - } - } - - code = 0; - for (size_t i = 1; i <= maxBit; i++) { - code = (code + lengthCount[i - 1]) << 1; - nextCode[i] = code; - } - - tree = newTree(); - - for (uint16_t i = 0; i <= maxCode; i++) { - uint8_t length = lengths[i]; - - if (length > 0) - insertTree(tree, nextCode[length]++, length, i); - } - } @finally { - OFFreeMemory(lengthCount); - OFFreeMemory(nextCode); - } - - return tree; -} - -struct of_huffman_tree * -of_huffman_tree_construct_single(uint16_t value) -{ - struct of_huffman_tree *tree = newTree(); - - tree->value = value; - - return tree; -} - -void -of_huffman_tree_release(struct of_huffman_tree *tree) -{ - for (uint_fast8_t i = 0; i < 2; i++) - if OF_LIKELY (tree->leaves[i] != NULL) - of_huffman_tree_release(tree->leaves[i]); - - OFFreeMemory(tree); -} Index: src/module.modulemap ================================================================== --- src/module.modulemap +++ src/module.modulemap @@ -1,16 +1,16 @@ framework module ObjFW { umbrella header "ObjFW.h" /* - * These are included by atomic.h, but should never be included + * These are included by OFAtomic.h, but should never be included * directly. */ - exclude header "atomic_builtins.h" - exclude header "atomic_no_threads.h" - exclude header "atomic_osatomic.h" - exclude header "atomic_powerpc.h" - exclude header "atomic_sync_builtins.h" - exclude header "atomic_x86.h" + exclude header "OFAtomic_builtins.h" + exclude header "OFAtomic_no_threads.h" + exclude header "OFAtomic_osatomic.h" + exclude header "OFAtomic_powerpc.h" + exclude header "OFAtomic_sync_builtins.h" + exclude header "OFAtomic_x86.h" export * } DELETED src/mutex.h Index: src/mutex.h ================================================================== --- src/mutex.h +++ src/mutex.h @@ -1,171 +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 "objfw-defs.h" - -#include - -#include "platform.h" - -#if !defined(OF_HAVE_THREADS) || \ - (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) -# error No mutexes available! -#endif - -#import "macros.h" - -#if defined(OF_HAVE_PTHREADS) -# include -typedef pthread_mutex_t OFPlainMutex; -#elif defined(OF_WINDOWS) -# include -typedef CRITICAL_SECTION OFPlainMutex; -#elif defined(OF_AMIGAOS) -# include -typedef struct SignalSemaphore OFPlainMutex; -#endif - -#if defined(OF_HAVE_ATOMIC_OPS) -# import "atomic.h" -typedef volatile int OFSpinlock; -# define OF_SPINCOUNT 10 -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) -typedef pthread_spinlock_t OFSpinlock; -#else -typedef OFPlainMutex OFSpinlock; -#endif - -#ifdef OF_HAVE_SCHED_YIELD -# include -#endif - -#if defined(OF_HAVE_RECURSIVE_PTHREAD_MUTEXES) || defined(OF_WINDOWS) || \ - defined(OF_AMIGAOS) -# define OFPlainRecursiveMutex OFPlainMutex -#else -# import "tlskey.h" -typedef struct { - OFPlainMutex mutex; - OFTLSKey count; -} OFPlainRecursiveMutex; -#endif - -#ifdef __cplusplus -extern "C" { -#endif -extern int OFPlainMutexNew(OFPlainMutex *mutex); -extern int OFPlainMutexLock(OFPlainMutex *mutex); -extern int OFPlainMutexTryLock(OFPlainMutex *mutex); -extern int OFPlainMutexUnlock(OFPlainMutex *mutex); -extern int OFPlainMutexFree(OFPlainMutex *mutex); -extern int OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex); -extern int OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex); -extern int OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex); -extern int OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex); -extern int OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex); -#ifdef __cplusplus -} -#endif - -/* Spinlocks are inlined for performance. */ - -static OF_INLINE void -OFYieldThread(void) -{ -#if defined(OF_HAVE_SCHED_YIELD) - sched_yield(); -#elif defined(OF_WINDOWS) - Sleep(0); -#endif -} - -static OF_INLINE int -OFSpinlockNew(OFSpinlock *spinlock) -{ -#if defined(OF_HAVE_ATOMIC_OPS) - *spinlock = 0; - return 0; -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) - return pthread_spin_init(spinlock, 0); -#else - return OFPlainMutexNew(spinlock); -#endif -} - -static OF_INLINE int -OFSpinlockTryLock(OFSpinlock *spinlock) -{ -#if defined(OF_HAVE_ATOMIC_OPS) - if (OFAtomicIntCompareAndSwap(spinlock, 0, 1)) { - of_memory_barrier_acquire(); - return 0; - } - - return EBUSY; -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) - return pthread_spin_trylock(spinlock); -#else - return OFPlainMutexTryLock(spinlock); -#endif -} - -static OF_INLINE int -OFSpinlockLock(OFSpinlock *spinlock) -{ -#if defined(OF_HAVE_ATOMIC_OPS) - size_t i; - - for (i = 0; i < OF_SPINCOUNT; i++) - if (OFSpinlockTryLock(spinlock) == 0) - return 0; - - while (OFSpinlockTryLock(spinlock) == EBUSY) - OFYieldThread(); - - return 0; -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) - return pthread_spin_lock(spinlock); -#else - return OFPlainMutexLock(spinlock); -#endif -} - -static OF_INLINE int -OFSpinlockUnlock(OFSpinlock *spinlock) -{ -#if defined(OF_HAVE_ATOMIC_OPS) - bool ret = OFAtomicIntCompareAndSwap(spinlock, 1, 0); - - of_memory_barrier_release(); - - return (ret ? 0 : EINVAL); -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) - return pthread_spin_unlock(spinlock); -#else - return OFPlainMutexUnlock(spinlock); -#endif -} - -static OF_INLINE int -OFSpinlockFree(OFSpinlock *spinlock) -{ -#if defined(OF_HAVE_ATOMIC_OPS) - return 0; -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) - return pthread_spin_destroy(spinlock); -#else - return OFPlainMutexFree(spinlock); -#endif -} DELETED src/mutex.m Index: src/mutex.m ================================================================== --- src/mutex.m +++ src/mutex.m @@ -1,26 +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 "platform.h" - -#if defined(OF_HAVE_PTHREADS) -# include "platform/posix/mutex.m" -#elif defined(OF_WINDOWS) -# include "platform/windows/mutex.m" -#elif defined(OF_AMIGAOS) -# include "platform/amiga/mutex.m" -#endif DELETED src/of_asprintf.h Index: src/of_asprintf.h ================================================================== --- src/of_asprintf.h +++ src/of_asprintf.h @@ -1,40 +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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#include - -#import "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern int of_asprintf( - char *_Nullable *_Nonnull, const char *_Nonnull, ...); -extern int of_vasprintf( - char *_Nullable *_Nonnull, const char *_Nonnull, va_list); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/of_asprintf.m Index: src/of_asprintf.m ================================================================== --- src/of_asprintf.m +++ src/of_asprintf.m @@ -1,796 +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 -#include -#include -#include -#include - -#ifdef HAVE_WCHAR_H -# include -#endif - -#ifdef HAVE_ASPRINTF_L -# include -#endif -#ifdef HAVE_XLOCALE_H -# include -#endif - -#ifdef OF_HAVE_SYS_TYPES_H -# include -#endif - -#import "OFString.h" -#import "OFLocale.h" - -#import "OFInitializationFailedException.h" - -#define MAX_SUBFORMAT_LEN 64 - -#ifndef HAVE_ASPRINTF -/* - * (v)asprintf might be declared, but HAVE_ASPRINTF not defined because - * configure determined it is broken. In this case, we must make sure there is - * no name clash. - */ -# define asprintf asprintf_ -# define vasprintf vasprintf_ -#endif - -struct context { - const char *format; - size_t formatLen; - char subformat[MAX_SUBFORMAT_LEN + 1]; - size_t subformatLen; - va_list arguments; - char *buffer; - size_t bufferLen; - size_t i, last; - enum { - STATE_STRING, - STATE_FORMAT_FLAGS, - STATE_FORMAT_FIELD_WIDTH, - STATE_FORMAT_LENGTH_MODIFIER, - STATE_FORMAT_CONVERSION_SPECIFIER - } state; - enum { - LENGTH_MODIFIER_NONE, - LENGTH_MODIFIER_HH, - LENGTH_MODIFIER_H, - LENGTH_MODIFIER_L, - LENGTH_MODIFIER_LL, - LENGTH_MODIFIER_J, - LENGTH_MODIFIER_Z, - LENGTH_MODIFIER_T, - LENGTH_MODIFIER_CAPITAL_L - } lengthModifier; - bool useLocale; -}; - -#ifdef HAVE_ASPRINTF_L -static locale_t cLocale; - -OF_CONSTRUCTOR() -{ - if ((cLocale = newlocale(LC_ALL_MASK, "C", NULL)) == NULL) - @throw [OFInitializationFailedException exception]; -} -#endif - -#ifndef HAVE_ASPRINTF -static int -vasprintf(char **string, const char *format, va_list arguments) -{ - int length; - size_t bufferLength = 128; - - *string = NULL; - - for (;;) { - free(*string); - - if ((*string = malloc(bufferLength)) == NULL) - return -1; - - length = vsnprintf(*string, bufferLength - 1, format, - arguments); - - if (length >= 0 && (size_t)length < bufferLength - 1) - break; - - if (bufferLength > INT_MAX / 2) { - free(*string); - return -1; - } - - bufferLength <<= 1; - } - - if (length > 0 && (size_t)length != bufferLength - 1) { - char *resized = realloc(*string, length + 1); - - /* Ignore if making it smaller failed. */ - if (resized != NULL) - *string = resized; - } - - return length; -} - -static int -asprintf(char **string, const char *format, ...) -{ - int ret; - va_list arguments; - - va_start(arguments, format); - ret = vasprintf(string, format, arguments); - va_end(arguments); - - return ret; -} -#endif - -static bool -appendString(struct context *ctx, const char *append, size_t appendLen) -{ - char *newBuf; - - if (appendLen == 0) - return true; - - if ((newBuf = realloc(ctx->buffer, - ctx->bufferLen + appendLen + 1)) == NULL) - return false; - - memcpy(newBuf + ctx->bufferLen, append, appendLen); - - ctx->buffer = newBuf; - ctx->bufferLen += appendLen; - - return true; -} - -static bool -appendSubformat(struct context *ctx, const char *subformat, - size_t subformatLen) -{ - if (ctx->subformatLen + subformatLen > MAX_SUBFORMAT_LEN) - return false; - - memcpy(ctx->subformat + ctx->subformatLen, subformat, subformatLen); - ctx->subformatLen += subformatLen; - ctx->subformat[ctx->subformatLen] = 0; - - return true; -} - -static bool -stringState(struct context *ctx) -{ - if (ctx->format[ctx->i] == '%') { - if (ctx->i > 0) - if (!appendString(ctx, ctx->format + ctx->last, - ctx->i - ctx->last)) - return false; - - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - ctx->last = ctx->i + 1; - ctx->state = STATE_FORMAT_FLAGS; - } - - return true; -} - -static bool -formatFlagsState(struct context *ctx) -{ - switch (ctx->format[ctx->i]) { - case '-': - case '+': - case ' ': - case '#': - case '0': - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - break; - case ',': - /* ObjFW extension: Use decimal point from locale */ - ctx->useLocale = true; - break; - default: - ctx->state = STATE_FORMAT_FIELD_WIDTH; - ctx->i--; - - break; - } - - return true; -} - -static bool -formatFieldWidthState(struct context *ctx) -{ - if ((ctx->format[ctx->i] >= '0' && ctx->format[ctx->i] <= '9') || - ctx->format[ctx->i] == '*' || ctx->format[ctx->i] == '.') { - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - } else { - ctx->state = STATE_FORMAT_LENGTH_MODIFIER; - ctx->i--; - } - - return true; -} - -static bool -formatLengthModifierState(struct context *ctx) -{ - /* Only one allowed */ - switch (ctx->format[ctx->i]) { - case 'h': /* and also hh */ - if (ctx->formatLen > ctx->i + 1 && - ctx->format[ctx->i + 1] == 'h') { - if (!appendSubformat(ctx, ctx->format + ctx->i, 2)) - return false; - - ctx->i++; - ctx->lengthModifier = LENGTH_MODIFIER_HH; - } else { - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - ctx->lengthModifier = LENGTH_MODIFIER_H; - } - - break; - case 'l': /* and also ll */ - if (ctx->formatLen > ctx->i + 1 && - ctx->format[ctx->i + 1] == 'l') { -#ifndef OF_WINDOWS - if (!appendSubformat(ctx, ctx->format + ctx->i, 2)) - return false; -#else - if (!appendSubformat(ctx, "I64", 3)) - return false; -#endif - - ctx->i++; - ctx->lengthModifier = LENGTH_MODIFIER_LL; - } else { - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - ctx->lengthModifier = LENGTH_MODIFIER_L; - } - - break; - case 'j': -#if defined(OF_WINDOWS) - if (!appendSubformat(ctx, "I64", 3)) - return false; -#elif defined(_NEWLIB_VERSION) || defined(OF_HPUX) - if (!appendSubformat(ctx, "ll", 2)) - return false; -#else - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; -#endif - - ctx->lengthModifier = LENGTH_MODIFIER_J; - - break; - case 'z': -#if defined(OF_WINDOWS) - if (sizeof(size_t) == 8) - if (!appendSubformat(ctx, "I64", 3)) - return false; -#elif defined(_NEWLIB_VERSION) || defined(OF_HPUX) - if (!appendSubformat(ctx, "l", 1)) - return false; -#else - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; -#endif - - ctx->lengthModifier = LENGTH_MODIFIER_Z; - - break; - case 't': -#if defined(OF_WINDOWS) - if (sizeof(ptrdiff_t) == 8) - if (!appendSubformat(ctx, "I64", 3)) - return false; -#elif defined(_NEWLIB_VERSION) || defined(OF_HPUX) - if (!appendSubformat(ctx, "l", 1)) - return false; -#else - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; -#endif - - ctx->lengthModifier = LENGTH_MODIFIER_T; - - break; - case 'L': - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - ctx->lengthModifier = LENGTH_MODIFIER_CAPITAL_L; - - break; -#ifdef OF_WINDOWS - case 'I': /* win32 strangeness (I64 instead of ll or j) */ - if (ctx->formatLen > ctx->i + 2 && - ctx->format[ctx->i + 1] == '6' && - ctx->format[ctx->i + 2] == '4') { - if (!appendSubformat(ctx, ctx->format + ctx->i, 3)) - return false; - - ctx->i += 2; - ctx->lengthModifier = LENGTH_MODIFIER_LL; - } else - ctx->i--; - - break; -#endif -#ifdef OF_IOS - case 'q': /* iOS uses this for PRI?64 */ - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - ctx->lengthModifier = LENGTH_MODIFIER_LL; - - break; -#endif - default: - ctx->i--; - - break; - } - - ctx->state = STATE_FORMAT_CONVERSION_SPECIFIER; - return true; -} - -static bool -formatConversionSpecifierState(struct context *ctx) -{ - char *tmp = NULL; - int tmpLen = 0; -#ifndef HAVE_ASPRINTF_L - OFString *point; -#endif - - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - switch (ctx->format[ctx->i]) { - case '@': - if (ctx->lengthModifier != LENGTH_MODIFIER_NONE) - return false; - - ctx->subformat[ctx->subformatLen - 1] = 's'; - - @try { - id object; - - if ((object = va_arg(ctx->arguments, id)) != nil) { - void *pool = objc_autoreleasePoolPush(); - - tmpLen = asprintf(&tmp, ctx->subformat, - [object description].UTF8String); - - objc_autoreleasePoolPop(pool); - } else - tmpLen = asprintf(&tmp, ctx->subformat, - "(nil)"); - } @catch (id e) { - free(ctx->buffer); - @throw e; - } - - break; - case 'C': - if (ctx->lengthModifier != LENGTH_MODIFIER_NONE) - return false; - - ctx->subformat[ctx->subformatLen - 1] = 's'; - - { - char buffer[5]; - size_t len = of_string_utf8_encode( - va_arg(ctx->arguments, OFUnichar), buffer); - - if (len == 0) - return false; - - buffer[len] = 0; - tmpLen = asprintf(&tmp, ctx->subformat, buffer); - } - - break; - case 'S': - if (ctx->lengthModifier != LENGTH_MODIFIER_NONE) - return false; - - ctx->subformat[ctx->subformatLen - 1] = 's'; - - { - const OFUnichar *arg = - va_arg(ctx->arguments, const OFUnichar *); - size_t j, len = of_string_utf32_length(arg); - char *buffer; - - if (SIZE_MAX / 4 < len || (SIZE_MAX / 4) - len < 1) - return false; - - if ((buffer = malloc((len * 4) + 1)) == NULL) - return false; - - j = 0; - for (size_t i = 0; i < len; i++) { - size_t clen = of_string_utf8_encode(arg[i], - buffer + j); - - if (clen == 0) { - free(buffer); - return false; - } - - j += clen; - } - buffer[j] = 0; - - tmpLen = asprintf(&tmp, ctx->subformat, buffer); - - free(buffer); - } - - break; - case 'd': - case 'i': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - case LENGTH_MODIFIER_HH: - case LENGTH_MODIFIER_H: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, int)); - break; - case LENGTH_MODIFIER_L: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, long)); - break; - case LENGTH_MODIFIER_LL: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, long long)); - break; - case LENGTH_MODIFIER_J: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, intmax_t)); - break; - case LENGTH_MODIFIER_Z: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, ssize_t)); - break; - case LENGTH_MODIFIER_T: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, ptrdiff_t)); - break; - default: - return false; - } - - break; - case 'o': - case 'u': - case 'x': - case 'X': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - case LENGTH_MODIFIER_HH: - case LENGTH_MODIFIER_H: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, unsigned int)); - break; - case LENGTH_MODIFIER_L: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, unsigned long)); - break; - case LENGTH_MODIFIER_LL: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, unsigned long long)); - break; - case LENGTH_MODIFIER_J: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, uintmax_t)); - break; - case LENGTH_MODIFIER_Z: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, size_t)); - break; - case LENGTH_MODIFIER_T: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, ptrdiff_t)); - break; - default: - return false; - } - - break; - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - case 'a': - case 'A': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - case LENGTH_MODIFIER_L: -#ifdef HAVE_ASPRINTF_L - if (!ctx->useLocale) - tmpLen = asprintf_l(&tmp, cLocale, - ctx->subformat, - va_arg(ctx->arguments, double)); - else -#endif - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, double)); - break; - case LENGTH_MODIFIER_CAPITAL_L: -#ifdef HAVE_ASPRINTF_L - if (!ctx->useLocale) - tmpLen = asprintf_l(&tmp, cLocale, - ctx->subformat, - va_arg(ctx->arguments, long double)); - else -#endif - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, long double)); - break; - default: - return false; - } - -#ifndef HAVE_ASPRINTF_L - if (tmpLen == -1) - return false; - - /* - * If there's no asprintf_l, we have no other choice than to - * use this ugly hack to replace the locale's decimal point - * back to ".". - */ - point = [OFLocale decimalPoint]; - - if (!ctx->useLocale && point != nil && ![point isEqual: @"."]) { - void *pool = objc_autoreleasePoolPush(); - char *tmp2; - - @try { - OFMutableString *tmpStr = [OFMutableString - stringWithUTF8String: tmp - length: tmpLen]; - [tmpStr replaceOccurrencesOfString: point - withString: @"."]; - - if (tmpStr.UTF8StringLength > INT_MAX) - return false; - - tmpLen = (int)tmpStr.UTF8StringLength; - tmp2 = malloc(tmpLen); - memcpy(tmp2, tmpStr.UTF8String, tmpLen); - } @finally { - free(tmp); - objc_autoreleasePoolPop(pool); - } - - tmp = tmp2; - } -#endif - - break; - case 'c': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, int)); - break; - case LENGTH_MODIFIER_L: -#ifdef HAVE_WCHAR_H -# if WINT_MAX >= INT_MAX - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, wint_t)); -# else - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, int)); -# endif - break; -#endif - default: - return false; - } - - break; - case 's': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, const char *)); - break; -#ifdef HAVE_WCHAR_T - case LENGTH_MODIFIER_L: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, const wchar_t *)); - break; -#endif - default: - return false; - } - - break; - case 'p': - if (ctx->lengthModifier != LENGTH_MODIFIER_NONE) - return false; - - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, void *)); - - break; - case 'n': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - *va_arg(ctx->arguments, int *) = (int)ctx->bufferLen; - break; - case LENGTH_MODIFIER_HH: - *va_arg(ctx->arguments, signed char *) = - (signed char)ctx->bufferLen; - break; - case LENGTH_MODIFIER_H: - *va_arg(ctx->arguments, short *) = - (short)ctx->bufferLen; - break; - case LENGTH_MODIFIER_L: - *va_arg(ctx->arguments, long *) = - (long)ctx->bufferLen; - break; - case LENGTH_MODIFIER_LL: - *va_arg(ctx->arguments, long long *) = - (long long)ctx->bufferLen; - break; - case LENGTH_MODIFIER_J: - *va_arg(ctx->arguments, intmax_t *) = - (intmax_t)ctx->bufferLen; - break; - case LENGTH_MODIFIER_Z: - *va_arg(ctx->arguments, size_t *) = - (size_t)ctx->bufferLen; - break; - case LENGTH_MODIFIER_T: - *va_arg(ctx->arguments, ptrdiff_t *) = - (ptrdiff_t)ctx->bufferLen; - break; - default: - return false; - } - - break; - case '%': - if (ctx->lengthModifier != LENGTH_MODIFIER_NONE) - return false; - - if (!appendString(ctx, "%", 1)) - return false; - - break; - default: - return false; - } - - if (tmpLen == -1) - return false; - - if (tmp != NULL) { - if (!appendString(ctx, tmp, tmpLen)) { - free(tmp); - return false; - } - - free(tmp); - } - - memset(ctx->subformat, 0, MAX_SUBFORMAT_LEN); - ctx->subformatLen = 0; - ctx->lengthModifier = LENGTH_MODIFIER_NONE; - ctx->useLocale = false; - - ctx->last = ctx->i + 1; - ctx->state = STATE_STRING; - - return true; -} - -static bool (*states[])(struct context *) = { - stringState, - formatFlagsState, - formatFieldWidthState, - formatLengthModifierState, - formatConversionSpecifierState -}; - -int -of_vasprintf(char **string, const char *format, va_list arguments) -{ - struct context ctx; - - ctx.format = format; - ctx.formatLen = strlen(format); - memset(ctx.subformat, 0, MAX_SUBFORMAT_LEN + 1); - ctx.subformatLen = 0; - va_copy(ctx.arguments, arguments); - ctx.bufferLen = 0; - ctx.last = 0; - ctx.state = STATE_STRING; - ctx.lengthModifier = LENGTH_MODIFIER_NONE; - ctx.useLocale = false; - - if ((ctx.buffer = malloc(1)) == NULL) - return -1; - - for (ctx.i = 0; ctx.i < ctx.formatLen; ctx.i++) { - if (!states[ctx.state](&ctx)) { - free(ctx.buffer); - return -1; - } - } - - if (ctx.state != STATE_STRING) { - free(ctx.buffer); - return -1; - } - - if (!appendString(&ctx, ctx.format + ctx.last, - ctx.formatLen - ctx.last)) { - free(ctx.buffer); - return -1; - } - - ctx.buffer[ctx.bufferLen] = 0; - - *string = ctx.buffer; - return (ctx.bufferLen <= INT_MAX ? (int)ctx.bufferLen : -1); -} - -int -of_asprintf(char **string, const char *format, ...) -{ - va_list arguments; - int ret; - - va_start(arguments, format); - ret = of_vasprintf(string, format, arguments); - va_end(arguments); - - return ret; -} DELETED src/of_strptime.h Index: src/of_strptime.h ================================================================== --- src/of_strptime.h +++ src/of_strptime.h @@ -1,38 +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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#include - -#import "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern const char *of_strptime(const char *buf, const char *fmt, struct tm *tm, - short *tz); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/of_strptime.m Index: src/of_strptime.m ================================================================== --- src/of_strptime.m +++ src/of_strptime.m @@ -1,231 +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 - -#include - -#import "macros.h" - -const char * -of_strptime(const char *buffer, const char *format, struct tm *tm, short *tz) -{ - enum { - SEARCH_CONVERSION_SPECIFIER, - IN_CONVERSION_SPECIFIER - } state = SEARCH_CONVERSION_SPECIFIER; - size_t j, bufferLen, formatLen; - - bufferLen = strlen(buffer); - formatLen = strlen(format); - - j = 0; - for (size_t i = 0; i < formatLen; i++) { - if (j >= bufferLen) - return NULL; - - switch (state) { - case SEARCH_CONVERSION_SPECIFIER: - if (format[i] == '%') - state = IN_CONVERSION_SPECIFIER; - else if (format[i] != buffer[j++]) - return NULL; - - break; - - case IN_CONVERSION_SPECIFIER:; - int k, maxLen, number = 0; - - switch (format[i]) { - case 'd': - case 'e': - case 'H': - case 'm': - case 'M': - case 'S': - case 'y': - maxLen = 2; - break; - case 'Y': - maxLen = 4; - break; - case '%': - case 'a': - case 'b': - case 'n': - case 't': - case 'z': - maxLen = 0; - break; - default: - return NULL; - } - - if (maxLen > 0 && (buffer[j] < '0' || buffer[j] > '9')) - return NULL; - - for (k = 0; k < maxLen && j < bufferLen && - buffer[j] >= '0' && buffer[j] <= '9'; k++, j++) { - number *= 10; - number += buffer[j] - '0'; - } - - switch (format[i]) { - case 'a': - if (bufferLen < j + 3) - return NULL; - - if (memcmp(buffer + j, "Sun", 3) == 0) - tm->tm_wday = 0; - else if (memcmp(buffer + j, "Mon", 3) == 0) - tm->tm_wday = 1; - else if (memcmp(buffer + j, "Tue", 3) == 0) - tm->tm_wday = 2; - else if (memcmp(buffer + j, "Wed", 3) == 0) - tm->tm_wday = 3; - else if (memcmp(buffer + j, "Thu", 3) == 0) - tm->tm_wday = 4; - else if (memcmp(buffer + j, "Fri", 3) == 0) - tm->tm_wday = 5; - else if (memcmp(buffer + j, "Sat", 3) == 0) - tm->tm_wday = 6; - else - return NULL; - - j += 3; - break; - case 'b': - if (bufferLen < j + 3) - return NULL; - - if (memcmp(buffer + j, "Jan", 3) == 0) - tm->tm_mon = 0; - else if (memcmp(buffer + j, "Feb", 3) == 0) - tm->tm_mon = 1; - else if (memcmp(buffer + j, "Mar", 3) == 0) - tm->tm_mon = 2; - else if (memcmp(buffer + j, "Apr", 3) == 0) - tm->tm_mon = 3; - else if (memcmp(buffer + j, "May", 3) == 0) - tm->tm_mon = 4; - else if (memcmp(buffer + j, "Jun", 3) == 0) - tm->tm_mon = 5; - else if (memcmp(buffer + j, "Jul", 3) == 0) - tm->tm_mon = 6; - else if (memcmp(buffer + j, "Aug", 3) == 0) - tm->tm_mon = 7; - else if (memcmp(buffer + j, "Sep", 3) == 0) - tm->tm_mon = 8; - else if (memcmp(buffer + j, "Oct", 3) == 0) - tm->tm_mon = 9; - else if (memcmp(buffer + j, "Nov", 3) == 0) - tm->tm_mon = 10; - else if (memcmp(buffer + j, "Dec", 3) == 0) - tm->tm_mon = 11; - else - return NULL; - - j += 3; - break; - case 'd': - case 'e': - tm->tm_mday = number; - break; - case 'H': - tm->tm_hour = number; - break; - case 'm': - tm->tm_mon = number - 1; - break; - case 'M': - tm->tm_min = number; - break; - case 'S': - tm->tm_sec = number; - break; - case 'y': - if (number <= 68) - number += 100; - - tm->tm_year = number; - break; - case 'Y': - if (number < 1900) - return NULL; - - tm->tm_year = number - 1900; - break; - case 'z': - if (buffer[j] == '-' || buffer[j] == '+') { - const char *b = buffer + j; - - if (bufferLen < j + 5) - return NULL; - - if (tz == NULL) - break; - - *tz = (((short)b[1] - '0') * 600 + - ((short)b[2] - '0') * 60 + - ((short)b[3] - '0') * 10 + - ((short)b[4] - '0')) * - (b[0] == '-' ? -1 : 1); - - j += 5; - } else if (buffer[j] == 'Z') { - if (tz != NULL) - *tz = 0; - - j++; - } else if (buffer[j] == 'G') { - if (bufferLen < j + 3) - return NULL; - - if (buffer[j + 1] != 'M' || - buffer[j + 2] != 'T') - return NULL; - - if (tz != NULL) - *tz = 0; - - j += 3; - } else - return NULL; - - break; - case '%': - if (buffer[j++] != '%') - return NULL; - break; - case 'n': - if (buffer[j++] != '\n') - return NULL; - break; - case 't': - if (buffer[j++] != '\t') - return NULL; - break; - } - - state = SEARCH_CONVERSION_SPECIFIER; - - break; - } - } - - return buffer + j; -} DELETED src/once.h Index: src/once.h ================================================================== --- src/once.h +++ src/once.h @@ -1,38 +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 "objfw-defs.h" - -#include "platform.h" - -#if defined(OF_HAVE_PTHREADS) -# include -typedef pthread_once_t OFOnceControl; -# define OFOnceControlInitValue PTHREAD_ONCE_INIT -#elif defined(OF_HAVE_ATOMIC_OPS) -typedef volatile int OFOnceControl; -# define OFOnceControlInitValue 0 -#elif defined(OF_AMIGAOS) || !defined(OF_HAVE_THREADS) -typedef int OFOnceControl; -# define OFOnceControlInitValue 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif -extern void OFOnce(OFOnceControl *control, void (*func)(void)); -#ifdef __cplusplus -} -#endif DELETED src/once.m Index: src/once.m ================================================================== --- src/once.m +++ src/once.m @@ -1,85 +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 "once.h" - -#ifdef OF_AMIGAOS -# include -#endif - -#if defined(OF_HAVE_THREADS) && defined(OF_HAVE_ATOMIC_OPS) -# import "atomic.h" -# import "mutex.h" -#endif - -void -OFOnce(OFOnceControl *control, void (*func)(void)) -{ -#if !defined(OF_HAVE_THREADS) - if (*control == 0) { - func(); - *control = 1; - } -#elif defined(OF_HAVE_PTHREADS) - pthread_once(control, func); -#elif defined(OF_HAVE_ATOMIC_OPS) - /* Avoid atomic operations in case it's already done. */ - if (*control == 2) - return; - - if (OFAtomicIntCompareAndSwap(control, 0, 1)) { - func(); - - of_memory_barrier(); - - OFAtomicIntIncrease(control); - } else - while (*control == 1) - OFYieldThread(); -#elif defined(OF_AMIGAOS) - bool run = false; - - /* Avoid Forbid() in case it's already done. */ - if (*control == 2) - return; - - Forbid(); - - switch (*control) { - case 0: - *control = 1; - run = true; - break; - case 1: - while (*control == 1) { - Permit(); - Forbid(); - } - } - - Permit(); - - if (run) { - func(); - *control = 2; - } -#else -# error No OFOnce available -#endif -} DELETED src/pbkdf2.h Index: src/pbkdf2.h ================================================================== --- src/pbkdf2.h +++ src/pbkdf2.h @@ -1,76 +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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#import "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -/** @file */ - -@class OFHMAC; - -/** - * @brief The parameters for @ref OFPBKDF2. - */ -typedef struct OFPBKDF2Parameters { - /** @brief The HMAC to use to derive a key. */ - __unsafe_unretained OFHMAC *HMAC; - /** @brief The number of iterations to perform. */ - size_t iterations; - /** @brief The salt to derive a key with. */ - const unsigned char *salt; - /** @brief The length of the salt. */ - size_t saltLength; - /** @brief The password to derive a key from. */ - const char *password; - /** @brief The length of the password. */ - size_t passwordLength; - /** @brief The buffer to write the key to. */ - unsigned char *key; - /** - * @brief The desired length for the derived key. - * - * @ref key needs to have enough storage. - */ - size_t keyLength; - /** @brief Whether data may be stored in swappable memory. */ - bool allowsSwappableMemory; -} OFPBKDF2Parameters; - -#ifdef __cplusplus -extern "C" { -#endif -/** - * @brief Derives a key from a password and a salt using PBKDF2. - * - * @note This will call @ref OFHMAC::reset on the `HMAC` first, making it - * possible to reuse the `HMAC`, but also meaning all previous results - * from the `HMAC` get invalidated if they have not been copied. - * - * @param param The parameters to use - */ -extern void OFPBKDF2(OFPBKDF2Parameters param); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/pbkdf2.m Index: src/pbkdf2.m ================================================================== --- src/pbkdf2.m +++ src/pbkdf2.m @@ -1,112 +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 "OFHMAC.h" -#import "OFSecureData.h" - -#import "OFInvalidArgumentException.h" -#import "OFOutOfMemoryException.h" -#import "OFOutOfRangeException.h" - -#import "pbkdf2.h" - -void -OFPBKDF2(OFPBKDF2Parameters param) -{ - void *pool = objc_autoreleasePoolPush(); - size_t blocks, digestSize = param.HMAC.digestSize; - OFSecureData *buffer = [OFSecureData - dataWithCount: digestSize - allowsSwappableMemory: param.allowsSwappableMemory]; - OFSecureData *digest = [OFSecureData - dataWithCount: digestSize - allowsSwappableMemory: param.allowsSwappableMemory]; - unsigned char *bufferItems = buffer.mutableItems; - unsigned char *digestItems = digest.mutableItems; - OFSecureData *extendedSalt; - unsigned char *extendedSaltItems; - - if (param.HMAC == nil || param.iterations == 0 || param.salt == NULL || - param.password == NULL || param.key == NULL || param.keyLength == 0) - @throw [OFInvalidArgumentException exception]; - - blocks = param.keyLength / digestSize; - if (param.keyLength % digestSize != 0) - blocks++; - - if (param.saltLength > SIZE_MAX - 4 || blocks > UINT32_MAX) - @throw [OFOutOfRangeException exception]; - - extendedSalt = [OFSecureData - dataWithCount: param.saltLength + 4 - allowsSwappableMemory: param.allowsSwappableMemory]; - extendedSaltItems = extendedSalt.mutableItems; - - @try { - uint32_t i = OFToBigEndian32(1); - - [param.HMAC setKey: param.password - length: param.passwordLength]; - - memcpy(extendedSaltItems, param.salt, param.saltLength); - - while (param.keyLength > 0) { - size_t length; - - memcpy(extendedSaltItems + param.saltLength, &i, 4); - - [param.HMAC reset]; - [param.HMAC updateWithBuffer: extendedSaltItems - length: param.saltLength + 4]; - memcpy(bufferItems, param.HMAC.digest, digestSize); - memcpy(digestItems, param.HMAC.digest, digestSize); - - for (size_t j = 1; j < param.iterations; j++) { - [param.HMAC reset]; - [param.HMAC updateWithBuffer: digestItems - length: digestSize]; - memcpy(digestItems, param.HMAC.digest, - digestSize); - - for (size_t k = 0; k < digestSize; k++) - bufferItems[k] ^= digestItems[k]; - } - - length = digestSize; - if (length > param.keyLength) - length = param.keyLength; - - memcpy(param.key, bufferItems, length); - param.key += length; - param.keyLength -= length; - - i = OFToBigEndian32(OFFromBigEndian32(i) + 1); - } - } @catch (id e) { - [extendedSalt zero]; - [buffer zero]; - [digest zero]; - - @throw e; - } @finally { - [param.HMAC zero]; - } - - objc_autoreleasePoolPop(pool); -} ADDED src/platform/amiga/OFPlainCondition.m Index: src/platform/amiga/OFPlainCondition.m ================================================================== --- src/platform/amiga/OFPlainCondition.m +++ src/platform/amiga/OFPlainCondition.m @@ -0,0 +1,251 @@ +/* + * 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 "OFPlainCondition.h" + +#include +#include +#ifndef OF_AMIGAOS4 +# include +#endif + +int +OFPlainConditionNew(OFPlainCondition *condition) +{ + condition->waitingTasks = NULL; + + return 0; +} + +int +OFPlainConditionSignal(OFPlainCondition *condition) +{ + Forbid(); + @try { + if (condition->waitingTasks == NULL) + return 0; + + Signal(condition->waitingTasks->task, + (1ul << condition->waitingTasks->sigBit)); + + condition->waitingTasks = condition->waitingTasks->next; + } @finally { + Permit(); + } + + return 0; +} + +int +OFPlainConditionBroadcast(OFPlainCondition *condition) +{ + Forbid(); + @try { + if (condition->waitingTasks == NULL) + return 0; + + while (condition->waitingTasks != NULL) { + Signal(condition->waitingTasks->task, + (1ul << condition->waitingTasks->sigBit)); + + condition->waitingTasks = condition->waitingTasks->next; + } + } @finally { + Permit(); + } + + return 0; +} + +int +OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) +{ + ULONG signalMask = 0; + + return OFPlainConditionWaitOrExecSignal(condition, mutex, &signalMask); +} + +int +OFPlainConditionWaitOrExecSignal(OFPlainCondition *condition, + OFPlainMutex *mutex, ULONG *signalMask) +{ + struct OFPlainConditionWaitingTask waitingTask = { + .task = FindTask(NULL), + .sigBit = AllocSignal(-1) + }; + int error = 0; + ULONG mask; + + if (waitingTask.sigBit == -1) + return EAGAIN; + + Forbid(); + + if ((error = OFPlainMutexUnlock(mutex)) != 0) { + FreeSignal(waitingTask.sigBit); + return error; + } + + waitingTask.next = condition->waitingTasks; + condition->waitingTasks = &waitingTask; + + mask = Wait((1ul << waitingTask.sigBit) | *signalMask); + if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) + error = OFPlainMutexLock(mutex); + else + /* + * This should not happen - it means something interrupted the + * Wait(), so the best we can do is return EINTR. + */ + error = EINTR; + + FreeSignal(waitingTask.sigBit); + + Permit(); + + return error; +} + +int +OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, + OFTimeInterval timeout) +{ + ULONG signalMask = 0; + + return OFPlainConditionTimedWaitOrExecSignal(condition, mutex, timeout, + &signalMask); +} + +int +OFPlainConditionTimedWaitOrExecSignal(OFPlainCondition *condition, + OFPlainMutex *mutex, OFTimeInterval timeout, ULONG *signalMask) +{ + struct OFPlainConditionWaitingTask waitingTask = { + .task = FindTask(NULL), + .sigBit = AllocSignal(-1) + }; + struct MsgPort port = { + .mp_Node = { + .ln_Type = NT_MSGPORT + }, + .mp_Flags = PA_SIGNAL, + .mp_SigTask = waitingTask.task, + .mp_SigBit = AllocSignal(-1) + }; +#ifdef OF_AMIGAOS4 + struct TimeRequest request = { + .Request = { +#else + struct timerequest request = { + .tr_node = { +#endif + .io_Message = { + .mn_Node = { + .ln_Type = NT_MESSAGE + }, + .mn_ReplyPort = &port, + .mn_Length = sizeof(request) + }, + .io_Command = TR_ADDREQUEST + }, +#ifdef OF_AMIGAOS4 + .Time = { + .Seconds = (ULONG)timeout, + .Microseconds = + (timeout - request.Time.Seconds) * 1000000 +#else + .tr_time = { + .tv_sec = (ULONG)timeout, + .tv_micro = (timeout - request.tr_time.tv_sec) * 1000000 +#endif + } + }; + int error = 0; + ULONG mask; + + NewList(&port.mp_MsgList); + + if (waitingTask.sigBit == -1 || port.mp_SigBit == -1) { + error = EAGAIN; + goto fail; + } + + if (OpenDevice("timer.device", UNIT_MICROHZ, + (struct IORequest *)&request, 0) != 0) { + error = EAGAIN; + goto fail; + } + + Forbid(); + + if ((error = OFPlainMutexUnlock(mutex)) != 0) { + Permit(); + goto fail; + } + + waitingTask.next = condition->waitingTasks; + condition->waitingTasks = &waitingTask; + + SendIO((struct IORequest *)&request); + + mask = Wait((1ul << waitingTask.sigBit) | (1ul << port.mp_SigBit) | + *signalMask); + if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) + error = OFPlainMutexLock(mutex); + else if (mask & (1ul << port.mp_SigBit)) + error = ETIMEDOUT; + else + /* + * This should not happen - it means something interrupted the + * Wait(), so the best we can do is return EINTR. + */ + error = EINTR; + + condition->waitingTasks = waitingTask.next; + + if (!CheckIO((struct IORequest *)&request)) { + AbortIO((struct IORequest *)&request); + WaitIO((struct IORequest *)&request); + } + CloseDevice((struct IORequest *)&request); + + Permit(); + +fail: + if (waitingTask.sigBit != -1) + FreeSignal(waitingTask.sigBit); + if (port.mp_SigBit != -1) + FreeSignal(port.mp_SigBit); + + return error; +} + +int +OFPlainConditionFree(OFPlainCondition *condition) +{ + Forbid(); + @try { + if (condition->waitingTasks != NULL) + return EBUSY; + } @finally { + Permit(); + } + + return 0; +} ADDED src/platform/amiga/OFPlainMutex.m Index: src/platform/amiga/OFPlainMutex.m ================================================================== --- src/platform/amiga/OFPlainMutex.m +++ src/platform/amiga/OFPlainMutex.m @@ -0,0 +1,91 @@ +/* + * 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 "OFPlainMutex.h" + +#include + +int +OFPlainMutexNew(OFPlainMutex *mutex) +{ + InitSemaphore(mutex); + + return 0; +} + +int +OFPlainMutexLock(OFPlainMutex *mutex) +{ + ObtainSemaphore(mutex); + + return 0; +} + +int +OFPlainMutexTryLock(OFPlainMutex *mutex) +{ + if (!AttemptSemaphore(mutex)) + return EBUSY; + + return 0; +} + +int +OFPlainMutexUnlock(OFPlainMutex *mutex) +{ + ReleaseSemaphore(mutex); + + return 0; +} + +int +OFPlainMutexFree(OFPlainMutex *mutex) +{ + return 0; +} + +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexNew(rmutex); +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexLock(rmutex); +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexTryLock(rmutex); +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexUnlock(rmutex); +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexFree(rmutex); +} ADDED src/platform/amiga/OFPlainThread.m Index: src/platform/amiga/OFPlainThread.m ================================================================== --- src/platform/amiga/OFPlainThread.m +++ src/platform/amiga/OFPlainThread.m @@ -0,0 +1,214 @@ +/* + * 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 +#include + +#import "OFPlainThread.h" +#import "OFData.h" +#import "OFTLSKey.h" + +#include +#include +#include + +#ifndef OF_MORPHOS +extern void OFTLSKeyThreadExited(void); +#endif +static OFTLSKey threadKey; + +OF_CONSTRUCTOR() +{ + OFEnsure(OFTLSKeyNew(&threadKey) == 0); +} + +static void +functionWrapper(void) +{ + bool detached = false; + OFPlainThread thread = + (OFPlainThread)((struct Process *)FindTask(NULL))->pr_ExitData; + OFEnsure(OFTLSKeySet(threadKey, thread) == 0); + + thread->function(thread->object); + + ObtainSemaphore(&thread->semaphore); + @try { + thread->done = true; + +#ifndef OF_MORPHOS + OFTLSKeyThreadExited(); +#endif + + if (thread->detached) + detached = true; + else if (thread->joinTask != NULL) + Signal(thread->joinTask, (1ul << thread->joinSigBit)); + } @finally { + ReleaseSemaphore(&thread->semaphore); + } + + if (detached) + free(thread); +} + +int +OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) +{ + attr->priority = 0; + attr->stackSize = 0; + + return 0; +} + +int +OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), + id object, const OFPlainThreadAttributes *attr) +{ + OFMutableData *tags = nil; + + if ((*thread = calloc(1, sizeof(**thread))) == NULL) + return ENOMEM; + + @try { + (*thread)->function = function; + (*thread)->object = object; + InitSemaphore(&(*thread)->semaphore); + + tags = [[OFMutableData alloc] + initWithItemSize: sizeof(struct TagItem) + capacity: 12]; +#define ADD_TAG(tag, data) \ + { \ + struct TagItem t = { \ + .ti_Tag = tag, \ + .ti_Data = data \ + }; \ + [tags addItem: &t]; \ + } + ADD_TAG(NP_Entry, (ULONG)functionWrapper) + ADD_TAG(NP_ExitData, (ULONG)*thread) +#ifdef OF_AMIGAOS4 + ADD_TAG(NP_Child, TRUE) +#endif +#ifdef OF_MORPHOS + ADD_TAG(NP_CodeType, CODETYPE_PPC); +#endif + if (name != NULL) + ADD_TAG(NP_Name, (ULONG)name); + + ADD_TAG(NP_Input, ((struct Process *)FindTask(NULL))->pr_CIS) + ADD_TAG(NP_Output, ((struct Process *)FindTask(NULL))->pr_COS) + ADD_TAG(NP_Error, ((struct Process *)FindTask(NULL))->pr_CES) + ADD_TAG(NP_CloseInput, FALSE) + ADD_TAG(NP_CloseOutput, FALSE) + ADD_TAG(NP_CloseError, FALSE) + + if (attr != NULL && attr->priority != 0) { + if (attr->priority < 1 || attr->priority > 1) + return EINVAL; + + /* + * -1 should be -128 (lowest possible priority) while + * +1 should be +127 (highest possible priority). + */ + ADD_TAG(NP_Priority, (attr->priority > 0 + ? attr->priority * 127 : attr->priority * 128)) + } + + if (attr != NULL && attr->stackSize != 0) + ADD_TAG(NP_StackSize, attr->stackSize) + else + ADD_TAG(NP_StackSize, + ((struct Process *)FindTask(NULL))->pr_StackSize) + + ADD_TAG(TAG_DONE, 0) +#undef ADD_TAG + + (*thread)->task = (struct Task *)CreateNewProc(tags.items); + if ((*thread)->task == NULL) { + free(*thread); + return EAGAIN; + } + } @catch (id e) { + free(*thread); + @throw e; + } @finally { + [tags release]; + } + + return 0; +} + +OFPlainThread +OFCurrentPlainThread(void) +{ + return OFTLSKeyGet(threadKey); +} + +int +OFPlainThreadJoin(OFPlainThread thread) +{ + ObtainSemaphore(&thread->semaphore); + + if (thread->done) { + ReleaseSemaphore(&thread->semaphore); + + free(thread); + return 0; + } + + @try { + if (thread->detached || thread->joinTask != NULL) + return EINVAL; + + if ((thread->joinSigBit = AllocSignal(-1)) == -1) + return EAGAIN; + + thread->joinTask = FindTask(NULL); + } @finally { + ReleaseSemaphore(&thread->semaphore); + } + + Wait(1ul << thread->joinSigBit); + FreeSignal(thread->joinSigBit); + + assert(thread->done); + free(thread); + + return 0; +} + +int +OFPlainThreadDetach(OFPlainThread thread) +{ + ObtainSemaphore(&thread->semaphore); + + if (thread->done) + free(thread); + else + thread->detached = true; + + ReleaseSemaphore(&thread->semaphore); + + return 0; +} + +void +OFSetThreadName(const char *name) +{ +} ADDED src/platform/amiga/OFTLSKey.m Index: src/platform/amiga/OFTLSKey.m ================================================================== --- src/platform/amiga/OFTLSKey.m +++ src/platform/amiga/OFTLSKey.m @@ -0,0 +1,167 @@ +/* + * 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" + +#import "OFTLSKey.h" + +#include +#include + +/* + * As we use this file in both the runtime and ObjFW, and since AmigaOS always + * has the runtime, use the hashtable from the runtime. + */ +#import "runtime/private.h" + +static OFTLSKey firstKey = NULL, lastKey = NULL; +static struct SignalSemaphore semaphore; +static bool semaphoreInitialized = false; + +static uint32_t +hashFunc(const void *ptr) +{ + return (uint32_t)(uintptr_t)ptr; +} + +static bool +equalFunc(const void *ptr1, const void *ptr2) +{ + return (ptr1 == ptr2); +} + +OF_CONSTRUCTOR() +{ + if (!semaphoreInitialized) { + InitSemaphore(&semaphore); + semaphoreInitialized = true; + } +} + +int +OFTLSKeyNew(OFTLSKey *key) +{ + if (!semaphoreInitialized) { + /* + * We might be called from another constructor, while ours has + * not run yet. This is safe, as the constructor is definitely + * run before a thread is spawned. + */ + InitSemaphore(&semaphore); + semaphoreInitialized = true; + } + + if ((*key = malloc(sizeof(**key))) == NULL) + return ENOMEM; + + (*key)->table = NULL; + + ObtainSemaphore(&semaphore); + @try { + (*key)->next = NULL; + (*key)->previous = lastKey; + + if (lastKey != NULL) + lastKey->next = *key; + + lastKey = *key; + + if (firstKey == NULL) + firstKey = *key; + } @finally { + ReleaseSemaphore(&semaphore); + } + + /* We create the hash table lazily. */ + return 0; +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + ObtainSemaphore(&semaphore); + @try { + if (key->previous != NULL) + key->previous->next = key->next; + if (key->next != NULL) + key->next->previous = key->previous; + + if (firstKey == key) + firstKey = key->next; + if (lastKey == key) + lastKey = key->previous; + + objc_hashtable_free(key->table); + free(key); + } @finally { + ReleaseSemaphore(&semaphore); + } + + return 0; +} + +void * +OFTLSKeyGet(OFTLSKey key) +{ + void *ret; + + ObtainSemaphore(&semaphore); + @try { + if (key->table == NULL) + return NULL; + + ret = objc_hashtable_get(key->table, FindTask(NULL)); + } @finally { + ReleaseSemaphore(&semaphore); + } + + return ret; +} + +int +OFTLSKeySet(OFTLSKey key, void *ptr) +{ + ObtainSemaphore(&semaphore); + @try { + struct Task *task = FindTask(NULL); + + if (key->table == NULL) + key->table = objc_hashtable_new(hashFunc, equalFunc, 2); + + if (ptr == NULL) + objc_hashtable_delete(key->table, task); + else + objc_hashtable_set(key->table, task, ptr); + } @finally { + ReleaseSemaphore(&semaphore); + } + + return 0; +} + +void +OFTLSKeyThreadExited(void) +{ + ObtainSemaphore(&semaphore); + @try { + struct Task *task = FindTask(NULL); + + for (OFTLSKey iter = firstKey; iter != NULL; iter = iter->next) + if (iter->table != NULL) + objc_hashtable_delete(iter->table, task); + } @finally { + ReleaseSemaphore(&semaphore); + } +} DELETED src/platform/amiga/condition.m Index: src/platform/amiga/condition.m ================================================================== --- src/platform/amiga/condition.m +++ src/platform/amiga/condition.m @@ -1,251 +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 "condition.h" - -#include -#include -#ifndef OF_AMIGAOS4 -# include -#endif - -int -OFPlainConditionNew(OFPlainCondition *condition) -{ - condition->waitingTasks = NULL; - - return 0; -} - -int -OFPlainConditionSignal(OFPlainCondition *condition) -{ - Forbid(); - @try { - if (condition->waitingTasks == NULL) - return 0; - - Signal(condition->waitingTasks->task, - (1ul << condition->waitingTasks->sigBit)); - - condition->waitingTasks = condition->waitingTasks->next; - } @finally { - Permit(); - } - - return 0; -} - -int -OFPlainConditionBroadcast(OFPlainCondition *condition) -{ - Forbid(); - @try { - if (condition->waitingTasks == NULL) - return 0; - - while (condition->waitingTasks != NULL) { - Signal(condition->waitingTasks->task, - (1ul << condition->waitingTasks->sigBit)); - - condition->waitingTasks = condition->waitingTasks->next; - } - } @finally { - Permit(); - } - - return 0; -} - -int -OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) -{ - ULONG signalMask = 0; - - return OFPlainConditionWaitOrExecSignal(condition, mutex, &signalMask); -} - -int -OFPlainConditionWaitOrExecSignal(OFPlainCondition *condition, - OFPlainMutex *mutex, ULONG *signalMask) -{ - struct OFPlainConditionWaitingTask waitingTask = { - .task = FindTask(NULL), - .sigBit = AllocSignal(-1) - }; - int error = 0; - ULONG mask; - - if (waitingTask.sigBit == -1) - return EAGAIN; - - Forbid(); - - if ((error = OFPlainMutexUnlock(mutex)) != 0) { - FreeSignal(waitingTask.sigBit); - return error; - } - - waitingTask.next = condition->waitingTasks; - condition->waitingTasks = &waitingTask; - - mask = Wait((1ul << waitingTask.sigBit) | *signalMask); - if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) - error = OFPlainMutexLock(mutex); - else - /* - * This should not happen - it means something interrupted the - * Wait(), so the best we can do is return EINTR. - */ - error = EINTR; - - FreeSignal(waitingTask.sigBit); - - Permit(); - - return error; -} - -int -OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, - OFTimeInterval timeout) -{ - ULONG signalMask = 0; - - return OFPlainConditionTimedWaitOrExecSignal(condition, mutex, timeout, - &signalMask); -} - -int -OFPlainConditionTimedWaitOrExecSignal(OFPlainCondition *condition, - OFPlainMutex *mutex, OFTimeInterval timeout, ULONG *signalMask) -{ - struct OFPlainConditionWaitingTask waitingTask = { - .task = FindTask(NULL), - .sigBit = AllocSignal(-1) - }; - struct MsgPort port = { - .mp_Node = { - .ln_Type = NT_MSGPORT - }, - .mp_Flags = PA_SIGNAL, - .mp_SigTask = waitingTask.task, - .mp_SigBit = AllocSignal(-1) - }; -#ifdef OF_AMIGAOS4 - struct TimeRequest request = { - .Request = { -#else - struct timerequest request = { - .tr_node = { -#endif - .io_Message = { - .mn_Node = { - .ln_Type = NT_MESSAGE - }, - .mn_ReplyPort = &port, - .mn_Length = sizeof(request) - }, - .io_Command = TR_ADDREQUEST - }, -#ifdef OF_AMIGAOS4 - .Time = { - .Seconds = (ULONG)timeout, - .Microseconds = - (timeout - request.Time.Seconds) * 1000000 -#else - .tr_time = { - .tv_sec = (ULONG)timeout, - .tv_micro = (timeout - request.tr_time.tv_sec) * 1000000 -#endif - } - }; - int error = 0; - ULONG mask; - - NewList(&port.mp_MsgList); - - if (waitingTask.sigBit == -1 || port.mp_SigBit == -1) { - error = EAGAIN; - goto fail; - } - - if (OpenDevice("timer.device", UNIT_MICROHZ, - (struct IORequest *)&request, 0) != 0) { - error = EAGAIN; - goto fail; - } - - Forbid(); - - if ((error = OFPlainMutexUnlock(mutex)) != 0) { - Permit(); - goto fail; - } - - waitingTask.next = condition->waitingTasks; - condition->waitingTasks = &waitingTask; - - SendIO((struct IORequest *)&request); - - mask = Wait((1ul << waitingTask.sigBit) | (1ul << port.mp_SigBit) | - *signalMask); - if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) - error = OFPlainMutexLock(mutex); - else if (mask & (1ul << port.mp_SigBit)) - error = ETIMEDOUT; - else - /* - * This should not happen - it means something interrupted the - * Wait(), so the best we can do is return EINTR. - */ - error = EINTR; - - condition->waitingTasks = waitingTask.next; - - if (!CheckIO((struct IORequest *)&request)) { - AbortIO((struct IORequest *)&request); - WaitIO((struct IORequest *)&request); - } - CloseDevice((struct IORequest *)&request); - - Permit(); - -fail: - if (waitingTask.sigBit != -1) - FreeSignal(waitingTask.sigBit); - if (port.mp_SigBit != -1) - FreeSignal(port.mp_SigBit); - - return error; -} - -int -OFPlainConditionFree(OFPlainCondition *condition) -{ - Forbid(); - @try { - if (condition->waitingTasks != NULL) - return EBUSY; - } @finally { - Permit(); - } - - return 0; -} DELETED src/platform/amiga/mutex.m Index: src/platform/amiga/mutex.m ================================================================== --- src/platform/amiga/mutex.m +++ src/platform/amiga/mutex.m @@ -1,91 +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 "mutex.h" - -#include - -int -OFPlainMutexNew(OFPlainMutex *mutex) -{ - InitSemaphore(mutex); - - return 0; -} - -int -OFPlainMutexLock(OFPlainMutex *mutex) -{ - ObtainSemaphore(mutex); - - return 0; -} - -int -OFPlainMutexTryLock(OFPlainMutex *mutex) -{ - if (!AttemptSemaphore(mutex)) - return EBUSY; - - return 0; -} - -int -OFPlainMutexUnlock(OFPlainMutex *mutex) -{ - ReleaseSemaphore(mutex); - - return 0; -} - -int -OFPlainMutexFree(OFPlainMutex *mutex) -{ - return 0; -} - -int -OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexNew(rmutex); -} - -int -OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexLock(rmutex); -} - -int -OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexTryLock(rmutex); -} - -int -OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexUnlock(rmutex); -} - -int -OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexFree(rmutex); -} DELETED src/platform/amiga/thread.m Index: src/platform/amiga/thread.m ================================================================== --- src/platform/amiga/thread.m +++ src/platform/amiga/thread.m @@ -1,215 +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 -#include - -#import "OFData.h" - -#import "thread.h" -#import "tlskey.h" - -#include -#include -#include - -#ifndef OF_MORPHOS -extern void OFTLSKeyThreadExited(void); -#endif -static OFTLSKey threadKey; - -OF_CONSTRUCTOR() -{ - OFEnsure(OFTLSKeyNew(&threadKey) == 0); -} - -static void -functionWrapper(void) -{ - bool detached = false; - OFPlainThread thread = - (OFPlainThread)((struct Process *)FindTask(NULL))->pr_ExitData; - OFEnsure(OFTLSKeySet(threadKey, thread) == 0); - - thread->function(thread->object); - - ObtainSemaphore(&thread->semaphore); - @try { - thread->done = true; - -#ifndef OF_MORPHOS - OFTLSKeyThreadExited(); -#endif - - if (thread->detached) - detached = true; - else if (thread->joinTask != NULL) - Signal(thread->joinTask, (1ul << thread->joinSigBit)); - } @finally { - ReleaseSemaphore(&thread->semaphore); - } - - if (detached) - free(thread); -} - -int -OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) -{ - attr->priority = 0; - attr->stackSize = 0; - - return 0; -} - -int -OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), - id object, const OFPlainThreadAttributes *attr) -{ - OFMutableData *tags = nil; - - if ((*thread = calloc(1, sizeof(**thread))) == NULL) - return ENOMEM; - - @try { - (*thread)->function = function; - (*thread)->object = object; - InitSemaphore(&(*thread)->semaphore); - - tags = [[OFMutableData alloc] - initWithItemSize: sizeof(struct TagItem) - capacity: 12]; -#define ADD_TAG(tag, data) \ - { \ - struct TagItem t = { \ - .ti_Tag = tag, \ - .ti_Data = data \ - }; \ - [tags addItem: &t]; \ - } - ADD_TAG(NP_Entry, (ULONG)functionWrapper) - ADD_TAG(NP_ExitData, (ULONG)*thread) -#ifdef OF_AMIGAOS4 - ADD_TAG(NP_Child, TRUE) -#endif -#ifdef OF_MORPHOS - ADD_TAG(NP_CodeType, CODETYPE_PPC); -#endif - if (name != NULL) - ADD_TAG(NP_Name, (ULONG)name); - - ADD_TAG(NP_Input, ((struct Process *)FindTask(NULL))->pr_CIS) - ADD_TAG(NP_Output, ((struct Process *)FindTask(NULL))->pr_COS) - ADD_TAG(NP_Error, ((struct Process *)FindTask(NULL))->pr_CES) - ADD_TAG(NP_CloseInput, FALSE) - ADD_TAG(NP_CloseOutput, FALSE) - ADD_TAG(NP_CloseError, FALSE) - - if (attr != NULL && attr->priority != 0) { - if (attr->priority < 1 || attr->priority > 1) - return EINVAL; - - /* - * -1 should be -128 (lowest possible priority) while - * +1 should be +127 (highest possible priority). - */ - ADD_TAG(NP_Priority, (attr->priority > 0 - ? attr->priority * 127 : attr->priority * 128)) - } - - if (attr != NULL && attr->stackSize != 0) - ADD_TAG(NP_StackSize, attr->stackSize) - else - ADD_TAG(NP_StackSize, - ((struct Process *)FindTask(NULL))->pr_StackSize) - - ADD_TAG(TAG_DONE, 0) -#undef ADD_TAG - - (*thread)->task = (struct Task *)CreateNewProc(tags.items); - if ((*thread)->task == NULL) { - free(*thread); - return EAGAIN; - } - } @catch (id e) { - free(*thread); - @throw e; - } @finally { - [tags release]; - } - - return 0; -} - -OFPlainThread -OFCurrentPlainThread(void) -{ - return OFTLSKeyGet(threadKey); -} - -int -OFPlainThreadJoin(OFPlainThread thread) -{ - ObtainSemaphore(&thread->semaphore); - - if (thread->done) { - ReleaseSemaphore(&thread->semaphore); - - free(thread); - return 0; - } - - @try { - if (thread->detached || thread->joinTask != NULL) - return EINVAL; - - if ((thread->joinSigBit = AllocSignal(-1)) == -1) - return EAGAIN; - - thread->joinTask = FindTask(NULL); - } @finally { - ReleaseSemaphore(&thread->semaphore); - } - - Wait(1ul << thread->joinSigBit); - FreeSignal(thread->joinSigBit); - - assert(thread->done); - free(thread); - - return 0; -} - -int -OFPlainThreadDetach(OFPlainThread thread) -{ - ObtainSemaphore(&thread->semaphore); - - if (thread->done) - free(thread); - else - thread->detached = true; - - ReleaseSemaphore(&thread->semaphore); - - return 0; -} - -void -OFSetThreadName(const char *name) -{ -} DELETED src/platform/amiga/tlskey.m Index: src/platform/amiga/tlskey.m ================================================================== --- src/platform/amiga/tlskey.m +++ src/platform/amiga/tlskey.m @@ -1,167 +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" - -#import "tlskey.h" - -#include -#include - -/* - * As we use this file in both the runtime and ObjFW, and since AmigaOS always - * has the runtime, use the hashtable from the runtime. - */ -#import "runtime/private.h" - -static OFTLSKey firstKey = NULL, lastKey = NULL; -static struct SignalSemaphore semaphore; -static bool semaphoreInitialized = false; - -static uint32_t -hashFunc(const void *ptr) -{ - return (uint32_t)(uintptr_t)ptr; -} - -static bool -equalFunc(const void *ptr1, const void *ptr2) -{ - return (ptr1 == ptr2); -} - -OF_CONSTRUCTOR() -{ - if (!semaphoreInitialized) { - InitSemaphore(&semaphore); - semaphoreInitialized = true; - } -} - -int -OFTLSKeyNew(OFTLSKey *key) -{ - if (!semaphoreInitialized) { - /* - * We might be called from another constructor, while ours has - * not run yet. This is safe, as the constructor is definitely - * run before a thread is spawned. - */ - InitSemaphore(&semaphore); - semaphoreInitialized = true; - } - - if ((*key = malloc(sizeof(**key))) == NULL) - return ENOMEM; - - (*key)->table = NULL; - - ObtainSemaphore(&semaphore); - @try { - (*key)->next = NULL; - (*key)->previous = lastKey; - - if (lastKey != NULL) - lastKey->next = *key; - - lastKey = *key; - - if (firstKey == NULL) - firstKey = *key; - } @finally { - ReleaseSemaphore(&semaphore); - } - - /* We create the hash table lazily. */ - return 0; -} - -int -OFTLSKeyFree(OFTLSKey key) -{ - ObtainSemaphore(&semaphore); - @try { - if (key->previous != NULL) - key->previous->next = key->next; - if (key->next != NULL) - key->next->previous = key->previous; - - if (firstKey == key) - firstKey = key->next; - if (lastKey == key) - lastKey = key->previous; - - objc_hashtable_free(key->table); - free(key); - } @finally { - ReleaseSemaphore(&semaphore); - } - - return 0; -} - -void * -OFTLSKeyGet(OFTLSKey key) -{ - void *ret; - - ObtainSemaphore(&semaphore); - @try { - if (key->table == NULL) - return NULL; - - ret = objc_hashtable_get(key->table, FindTask(NULL)); - } @finally { - ReleaseSemaphore(&semaphore); - } - - return ret; -} - -int -OFTLSKeySet(OFTLSKey key, void *ptr) -{ - ObtainSemaphore(&semaphore); - @try { - struct Task *task = FindTask(NULL); - - if (key->table == NULL) - key->table = objc_hashtable_new(hashFunc, equalFunc, 2); - - if (ptr == NULL) - objc_hashtable_delete(key->table, task); - else - objc_hashtable_set(key->table, task, ptr); - } @finally { - ReleaseSemaphore(&semaphore); - } - - return 0; -} - -void -OFTLSKeyThreadExited(void) -{ - ObtainSemaphore(&semaphore); - @try { - struct Task *task = FindTask(NULL); - - for (OFTLSKey iter = firstKey; iter != NULL; iter = iter->next) - if (iter->table != NULL) - objc_hashtable_delete(iter->table, task); - } @finally { - ReleaseSemaphore(&semaphore); - } -} ADDED src/platform/morphos/OFTLSKey.m Index: src/platform/morphos/OFTLSKey.m ================================================================== --- src/platform/morphos/OFTLSKey.m +++ src/platform/morphos/OFTLSKey.m @@ -0,0 +1,35 @@ +/* + * 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" + +#import "OFTLSKey.h" + +int +OFTLSKeyNew(OFTLSKeyT *key) +{ + *key = TLSAllocA(NULL); + + if (*key == TLS_INVALID_INDEX) + return EAGAIN; + + return 0; +} + +int +OFTLSKeyFree(OFTLSKeyT key) +{ + return (TLSFree(key) ? 0 : EINVAL); +} DELETED src/platform/morphos/tlskey.m Index: src/platform/morphos/tlskey.m ================================================================== --- src/platform/morphos/tlskey.m +++ src/platform/morphos/tlskey.m @@ -1,35 +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" - -#import "tlskey.h" - -int -OFTLSKeyNew(OFTLSKeyT *key) -{ - *key = TLSAllocA(NULL); - - if (*key == TLS_INVALID_INDEX) - return EAGAIN; - - return 0; -} - -int -OFTLSKeyFree(OFTLSKeyT key) -{ - return (TLSFree(key) ? 0 : EINVAL); -} ADDED src/platform/posix/OFPlainCondition.m Index: src/platform/posix/OFPlainCondition.m ================================================================== --- src/platform/posix/OFPlainCondition.m +++ src/platform/posix/OFPlainCondition.m @@ -0,0 +1,60 @@ +/* + * 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" + +#import "OFPlainCondition.h" + +int +OFPlainConditionNew(OFPlainCondition *condition) +{ + return pthread_cond_init(condition, NULL); +} + +int +OFPlainConditionSignal(OFPlainCondition *condition) +{ + return pthread_cond_signal(condition); +} + +int +OFPlainConditionBroadcast(OFPlainCondition *condition) +{ + return pthread_cond_broadcast(condition); +} + +int +OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) +{ + return pthread_cond_wait(condition, mutex); +} + +int +OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, + OFTimeInterval timeout) +{ + struct timespec ts; + + ts.tv_sec = (time_t)timeout; + ts.tv_nsec = (long)((timeout - ts.tv_sec) * 1000000000); + + return pthread_cond_timedwait(condition, mutex, &ts); +} + +int +OFPlainConditionFree(OFPlainCondition *condition) +{ + return pthread_cond_destroy(condition); +} ADDED src/platform/posix/OFPlainMutex.m Index: src/platform/posix/OFPlainMutex.m ================================================================== --- src/platform/posix/OFPlainMutex.m +++ src/platform/posix/OFPlainMutex.m @@ -0,0 +1,197 @@ +/* + * 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" + +#import "OFPlainMutex.h" + +int +OFPlainMutexNew(OFPlainMutex *mutex) +{ + return pthread_mutex_init(mutex, NULL); +} + +int +OFPlainMutexLock(OFPlainMutex *mutex) +{ + return pthread_mutex_lock(mutex); +} + +int +OFPlainMutexTryLock(OFPlainMutex *mutex) +{ + return pthread_mutex_trylock(mutex); +} + +int +OFPlainMutexUnlock(OFPlainMutex *mutex) +{ + return pthread_mutex_unlock(mutex); +} + +int +OFPlainMutexFree(OFPlainMutex *mutex) +{ + return pthread_mutex_destroy(mutex); +} + +#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + int error; + pthread_mutexattr_t attr; + + if ((error = pthread_mutexattr_init(&attr)) != 0) + return error; + + if ((error = pthread_mutexattr_settype(&attr, + PTHREAD_MUTEX_RECURSIVE)) != 0) + return error; + + if ((error = pthread_mutex_init(rmutex, &attr)) != 0) + return error; + + if ((error = pthread_mutexattr_destroy(&attr)) != 0) + return error; + + return 0; +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexLock(rmutex); +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexTryLock(rmutex); +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexUnlock(rmutex); +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexFree(rmutex); +} +#else +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + int error; + + if ((error = OFPlainMutexNew(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeyNew(&rmutex->count)) != 0) + return error; + + return 0; +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); + int error; + + if (count > 0) { + if ((error = OFTLSKeySet(rmutex->count, + (void *)(count + 1))) != 0) + return error; + + return 0; + } + + if ((error = OFPlainMutexLock(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeySet(rmutex->count, (void *)1)) != 0) { + OFPlainMutexUnlock(&rmutex->mutex); + return error; + } + + return 0; +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); + int error; + + if (count > 0) { + if ((error = OFTLSKeySet(rmutex->count, + (void *)(count + 1))) != 0) + return error; + + return 0; + } + + if ((error = OFPlainMutexTryLock(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeySet(rmutex->count, (void *)1)) != 0) { + OFPlainMutexUnlock(&rmutex->mutex); + return error; + } + + return 0; +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); + int error; + + if (count > 1) { + if ((error = OFTLSKeySet(rmutex->count, + (void *)(count - 1))) != 0) + return error; + + return 0; + } + + if ((error = OFTLSKeySet(rmutex->count, (void *)0)) != 0) + return error; + + if ((error = OFPlainMutexUnlock(&rmutex->mutex)) != 0) + return error; + + return 0; +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + int error; + + if ((error = OFPlainMutexFree(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeyFree(rmutex->count)) != 0) + return error; + + return 0; +} +#endif ADDED src/platform/posix/OFPlainThread.m Index: src/platform/posix/OFPlainThread.m ================================================================== --- src/platform/posix/OFPlainThread.m +++ src/platform/posix/OFPlainThread.m @@ -0,0 +1,220 @@ +/* + * 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 + +#ifdef HAVE_PTHREAD_NP_H +# include +#endif + +#ifdef OF_HAIKU +# include +#endif + +#import "OFPlainThread.h" + +#import "macros.h" + +static int minPrio = 0, maxPrio = 0, normalPrio = 0; + +struct ThreadContext { + void (*function)(id object); + id object; + const char *name; +}; + +/* + * This is done here to make sure this is done as early as possible in the main + * thread. + */ +OF_CONSTRUCTOR() +{ + pthread_attr_t attr; + + if (pthread_attr_init(&attr) == 0) { +#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY + int policy; +#endif + struct sched_param param; + +#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY + if (pthread_attr_getschedpolicy(&attr, &policy) == 0) { + minPrio = sched_get_priority_min(policy); + maxPrio = sched_get_priority_max(policy); + + if (minPrio == -1 || maxPrio == -1) + minPrio = maxPrio = 0; + } +#endif + + if (pthread_attr_getschedparam(&attr, ¶m) != 0) + normalPrio = param.sched_priority; + else + minPrio = maxPrio = 0; + + pthread_attr_destroy(&attr); + } +} + +static void * +functionWrapper(void *data) +{ + struct ThreadContext *ctx = data; + + if (ctx->name != NULL) + OFSetThreadName(ctx->name); + + pthread_cleanup_push(free, data); + + ctx->function(ctx->object); + + pthread_cleanup_pop(1); + return NULL; +} + +int +OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) +{ + int error; + pthread_attr_t POSIXAttr; + + attr->priority = 0; + attr->stackSize = 0; + + if ((error = pthread_attr_init(&POSIXAttr)) != 0) { + if (error == ENOSYS) + return 0; + + return error; + } + + error = pthread_attr_getstacksize(&POSIXAttr, &attr->stackSize); + + pthread_attr_destroy(&POSIXAttr); + + return error; +} + +int +OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), + id object, const OFPlainThreadAttributes *attr) +{ + int error = 0; + pthread_attr_t POSIXAttr; + bool POSIXAttrAvailable = true; + + if ((error = pthread_attr_init(&POSIXAttr)) != 0) { + if (error == ENOSYS) + POSIXAttrAvailable = false; + else + return error; + } + + @try { + struct ThreadContext *ctx; + + if (attr != NULL && POSIXAttrAvailable) { +#ifndef OF_HPUX + struct sched_param param; +#endif + + if (attr->priority < -1 || attr->priority > 1) + return EINVAL; + +#ifndef OF_HPUX +# ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED + if ((error = pthread_attr_setinheritsched(&POSIXAttr, + PTHREAD_EXPLICIT_SCHED)) != 0) + return error; +# endif + + if ((error = pthread_attr_getschedparam(&POSIXAttr, + ¶m)) != 0) + return error; + + if (attr->priority < 0) { + param.sched_priority = minPrio + + (1.0f + attr->priority) * + (normalPrio - minPrio); + } else + param.sched_priority = normalPrio + + attr->priority * (maxPrio - normalPrio); + + if ((error = pthread_attr_setschedparam(&POSIXAttr, + ¶m)) != 0) + return error; +#endif + + if (attr->stackSize > 0) { + if ((error = pthread_attr_setstacksize( + &POSIXAttr, attr->stackSize)) != 0) + return error; + } + } + + if ((ctx = malloc(sizeof(*ctx))) == NULL) + return ENOMEM; + + ctx->function = function; + ctx->object = object; + ctx->name = name; + + error = pthread_create(thread, + (POSIXAttrAvailable ? &POSIXAttr : NULL), functionWrapper, + ctx); + } @finally { + if (POSIXAttrAvailable) + pthread_attr_destroy(&POSIXAttr); + } + + return error; +} + +int +OFPlainThreadJoin(OFPlainThread thread) +{ + void *ret; + + return pthread_join(thread, &ret); +} + +int +OFPlainThreadDetach(OFPlainThread thread) +{ + return pthread_detach(thread); +} + +void +OFSetThreadName(const char *name) +{ +#if defined(OF_HAIKU) + rename_thread(find_thread(NULL), name); +#elif defined(HAVE_PTHREAD_SET_NAME_NP) + pthread_set_name_np(pthread_self(), name); +#elif defined(HAVE_PTHREAD_SETNAME_NP) +# if defined(OF_MACOS) || defined(OF_IOS) + pthread_setname_np(name); +# elif defined(__GLIBC__) + char buffer[16]; + + strncpy(buffer, name, 15); + buffer[15] = 0; + + pthread_setname_np(pthread_self(), buffer); +# endif +#endif +} ADDED src/platform/posix/OFTLSKey.m Index: src/platform/posix/OFTLSKey.m ================================================================== --- src/platform/posix/OFTLSKey.m +++ src/platform/posix/OFTLSKey.m @@ -0,0 +1,30 @@ +/* + * 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" + +#import "OFTLSKey.h" + +int +OFTLSKeyNew(OFTLSKey *key) +{ + return pthread_key_create(key, NULL); +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + return pthread_key_delete(key); +} DELETED src/platform/posix/condition.m Index: src/platform/posix/condition.m ================================================================== --- src/platform/posix/condition.m +++ src/platform/posix/condition.m @@ -1,60 +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" - -#import "condition.h" - -int -OFPlainConditionNew(OFPlainCondition *condition) -{ - return pthread_cond_init(condition, NULL); -} - -int -OFPlainConditionSignal(OFPlainCondition *condition) -{ - return pthread_cond_signal(condition); -} - -int -OFPlainConditionBroadcast(OFPlainCondition *condition) -{ - return pthread_cond_broadcast(condition); -} - -int -OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) -{ - return pthread_cond_wait(condition, mutex); -} - -int -OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, - OFTimeInterval timeout) -{ - struct timespec ts; - - ts.tv_sec = (time_t)timeout; - ts.tv_nsec = (long)((timeout - ts.tv_sec) * 1000000000); - - return pthread_cond_timedwait(condition, mutex, &ts); -} - -int -OFPlainConditionFree(OFPlainCondition *condition) -{ - return pthread_cond_destroy(condition); -} DELETED src/platform/posix/mutex.m Index: src/platform/posix/mutex.m ================================================================== --- src/platform/posix/mutex.m +++ src/platform/posix/mutex.m @@ -1,197 +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" - -#import "mutex.h" - -int -OFPlainMutexNew(OFPlainMutex *mutex) -{ - return pthread_mutex_init(mutex, NULL); -} - -int -OFPlainMutexLock(OFPlainMutex *mutex) -{ - return pthread_mutex_lock(mutex); -} - -int -OFPlainMutexTryLock(OFPlainMutex *mutex) -{ - return pthread_mutex_trylock(mutex); -} - -int -OFPlainMutexUnlock(OFPlainMutex *mutex) -{ - return pthread_mutex_unlock(mutex); -} - -int -OFPlainMutexFree(OFPlainMutex *mutex) -{ - return pthread_mutex_destroy(mutex); -} - -#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES -int -OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) -{ - int error; - pthread_mutexattr_t attr; - - if ((error = pthread_mutexattr_init(&attr)) != 0) - return error; - - if ((error = pthread_mutexattr_settype(&attr, - PTHREAD_MUTEX_RECURSIVE)) != 0) - return error; - - if ((error = pthread_mutex_init(rmutex, &attr)) != 0) - return error; - - if ((error = pthread_mutexattr_destroy(&attr)) != 0) - return error; - - return 0; -} - -int -OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexLock(rmutex); -} - -int -OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexTryLock(rmutex); -} - -int -OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexUnlock(rmutex); -} - -int -OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexFree(rmutex); -} -#else -int -OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) -{ - int error; - - if ((error = OFPlainMutexNew(&rmutex->mutex)) != 0) - return error; - - if ((error = OFTLSKeyNew(&rmutex->count)) != 0) - return error; - - return 0; -} - -int -OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) -{ - uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); - int error; - - if (count > 0) { - if ((error = OFTLSKeySet(rmutex->count, - (void *)(count + 1))) != 0) - return error; - - return 0; - } - - if ((error = OFPlainMutexLock(&rmutex->mutex)) != 0) - return error; - - if ((error = OFTLSKeySet(rmutex->count, (void *)1)) != 0) { - OFPlainMutexUnlock(&rmutex->mutex); - return error; - } - - return 0; -} - -int -OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) -{ - uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); - int error; - - if (count > 0) { - if ((error = OFTLSKeySet(rmutex->count, - (void *)(count + 1))) != 0) - return error; - - return 0; - } - - if ((error = OFPlainMutexTryLock(&rmutex->mutex)) != 0) - return error; - - if ((error = OFTLSKeySet(rmutex->count, (void *)1)) != 0) { - OFPlainMutexUnlock(&rmutex->mutex); - return error; - } - - return 0; -} - -int -OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) -{ - uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); - int error; - - if (count > 1) { - if ((error = OFTLSKeySet(rmutex->count, - (void *)(count - 1))) != 0) - return error; - - return 0; - } - - if ((error = OFTLSKeySet(rmutex->count, (void *)0)) != 0) - return error; - - if ((error = OFPlainMutexUnlock(&rmutex->mutex)) != 0) - return error; - - return 0; -} - -int -OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) -{ - int error; - - if ((error = OFPlainMutexFree(&rmutex->mutex)) != 0) - return error; - - if ((error = OFTLSKeyFree(rmutex->count)) != 0) - return error; - - return 0; -} -#endif DELETED src/platform/posix/thread.m Index: src/platform/posix/thread.m ================================================================== --- src/platform/posix/thread.m +++ src/platform/posix/thread.m @@ -1,219 +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 - -#ifdef HAVE_PTHREAD_NP_H -# include -#endif - -#ifdef OF_HAIKU -# include -#endif - -#import "thread.h" -#import "macros.h" - -static int minPrio = 0, maxPrio = 0, normalPrio = 0; - -struct thread_ctx { - void (*function)(id object); - id object; - const char *name; -}; - -/* - * This is done here to make sure this is done as early as possible in the main - * thread. - */ -OF_CONSTRUCTOR() -{ - pthread_attr_t attr; - - if (pthread_attr_init(&attr) == 0) { -#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY - int policy; -#endif - struct sched_param param; - -#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY - if (pthread_attr_getschedpolicy(&attr, &policy) == 0) { - minPrio = sched_get_priority_min(policy); - maxPrio = sched_get_priority_max(policy); - - if (minPrio == -1 || maxPrio == -1) - minPrio = maxPrio = 0; - } -#endif - - if (pthread_attr_getschedparam(&attr, ¶m) != 0) - normalPrio = param.sched_priority; - else - minPrio = maxPrio = 0; - - pthread_attr_destroy(&attr); - } -} - -static void * -functionWrapper(void *data) -{ - struct thread_ctx *ctx = data; - - if (ctx->name != NULL) - OFSetThreadName(ctx->name); - - pthread_cleanup_push(free, data); - - ctx->function(ctx->object); - - pthread_cleanup_pop(1); - return NULL; -} - -int -OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) -{ - int error; - pthread_attr_t POSIXAttr; - - attr->priority = 0; - attr->stackSize = 0; - - if ((error = pthread_attr_init(&POSIXAttr)) != 0) { - if (error == ENOSYS) - return 0; - - return error; - } - - error = pthread_attr_getstacksize(&POSIXAttr, &attr->stackSize); - - pthread_attr_destroy(&POSIXAttr); - - return error; -} - -int -OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), - id object, const OFPlainThreadAttributes *attr) -{ - int error = 0; - pthread_attr_t POSIXAttr; - bool POSIXAttrAvailable = true; - - if ((error = pthread_attr_init(&POSIXAttr)) != 0) { - if (error == ENOSYS) - POSIXAttrAvailable = false; - else - return error; - } - - @try { - struct thread_ctx *ctx; - - if (attr != NULL && POSIXAttrAvailable) { -#ifndef OF_HPUX - struct sched_param param; -#endif - - if (attr->priority < -1 || attr->priority > 1) - return EINVAL; - -#ifndef OF_HPUX -# ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED - if ((error = pthread_attr_setinheritsched(&POSIXAttr, - PTHREAD_EXPLICIT_SCHED)) != 0) - return error; -# endif - - if ((error = pthread_attr_getschedparam(&POSIXAttr, - ¶m)) != 0) - return error; - - if (attr->priority < 0) { - param.sched_priority = minPrio + - (1.0f + attr->priority) * - (normalPrio - minPrio); - } else - param.sched_priority = normalPrio + - attr->priority * (maxPrio - normalPrio); - - if ((error = pthread_attr_setschedparam(&POSIXAttr, - ¶m)) != 0) - return error; -#endif - - if (attr->stackSize > 0) { - if ((error = pthread_attr_setstacksize( - &POSIXAttr, attr->stackSize)) != 0) - return error; - } - } - - if ((ctx = malloc(sizeof(*ctx))) == NULL) - return ENOMEM; - - ctx->function = function; - ctx->object = object; - ctx->name = name; - - error = pthread_create(thread, - (POSIXAttrAvailable ? &POSIXAttr : NULL), functionWrapper, - ctx); - } @finally { - if (POSIXAttrAvailable) - pthread_attr_destroy(&POSIXAttr); - } - - return error; -} - -int -OFPlainThreadJoin(OFPlainThread thread) -{ - void *ret; - - return pthread_join(thread, &ret); -} - -int -OFPlainThreadDetach(OFPlainThread thread) -{ - return pthread_detach(thread); -} - -void -OFSetThreadName(const char *name) -{ -#if defined(OF_HAIKU) - rename_thread(find_thread(NULL), name); -#elif defined(HAVE_PTHREAD_SET_NAME_NP) - pthread_set_name_np(pthread_self(), name); -#elif defined(HAVE_PTHREAD_SETNAME_NP) -# if defined(OF_MACOS) || defined(OF_IOS) - pthread_setname_np(name); -# elif defined(__GLIBC__) - char buffer[16]; - - strncpy(buffer, name, 15); - buffer[15] = 0; - - pthread_setname_np(pthread_self(), buffer); -# endif -#endif -} DELETED src/platform/posix/tlskey.m Index: src/platform/posix/tlskey.m ================================================================== --- src/platform/posix/tlskey.m +++ src/platform/posix/tlskey.m @@ -1,30 +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" - -#import "tlskey.h" - -int -OFTLSKeyNew(OFTLSKey *key) -{ - return pthread_key_create(key, NULL); -} - -int -OFTLSKeyFree(OFTLSKey key) -{ - return pthread_key_delete(key); -} ADDED src/platform/windows/OFPlainCondition.m Index: src/platform/windows/OFPlainCondition.m ================================================================== --- src/platform/windows/OFPlainCondition.m +++ src/platform/windows/OFPlainCondition.m @@ -0,0 +1,135 @@ +/* + * 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 "OFPlainCondition.h" + +#include + +int +OFPlainConditionNew(OFPlainCondition *condition) +{ + condition->count = 0; + + if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) + return EAGAIN; + + return 0; +} + +int +OFPlainConditionSignal(OFPlainCondition *condition) +{ + if (!SetEvent(condition->event)) { + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + } + + return 0; +} + +int +OFPlainConditionBroadcast(OFPlainCondition *condition) +{ + int count = condition->count; + + for (int i = 0; i < count; i++) { + if (!SetEvent(condition->event)) { + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + } + } + + return 0; +} + +int +OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) +{ + int error; + DWORD status; + + if ((error = OFPlainMutexUnlock(mutex)) != 0) + return error; + + OFAtomicIntIncrease(&condition->count); + status = WaitForSingleObject(condition->event, INFINITE); + OFAtomicIntDecrease(&condition->count); + + switch (status) { + case WAIT_OBJECT_0: + return OFPlainMutexLock(mutex); + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + default: + OFEnsure(0); + } +} + +int +OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, + OFTimeInterval timeout) +{ + int error; + DWORD status; + + if ((error = OFPlainMutexUnlock(mutex)) != 0) + return error; + + OFAtomicIntIncrease(&condition->count); + status = WaitForSingleObject(condition->event, timeout * 1000); + OFAtomicIntDecrease(&condition->count); + + switch (status) { + case WAIT_OBJECT_0: + return OFPlainMutexLock(mutex); + case WAIT_TIMEOUT: + return ETIMEDOUT; + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + default: + OFEnsure(0); + } +} + +int +OFPlainConditionFree(OFPlainCondition *condition) +{ + if (condition->count != 0) + return EBUSY; + + return (CloseHandle(condition->event) ? 0 : EINVAL); +} ADDED src/platform/windows/OFPlainMutex.m Index: src/platform/windows/OFPlainMutex.m ================================================================== --- src/platform/windows/OFPlainMutex.m +++ src/platform/windows/OFPlainMutex.m @@ -0,0 +1,93 @@ +/* + * 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 "OFPlainMutex.h" + +#include + +int +OFPlainMutexNew(OFPlainMutex *mutex) +{ + InitializeCriticalSection(mutex); + + return 0; +} + +int +OFPlainMutexLock(OFPlainMutex *mutex) +{ + EnterCriticalSection(mutex); + + return 0; +} + +int +OFPlainMutexTryLock(OFPlainMutex *mutex) +{ + if (!TryEnterCriticalSection(mutex)) + return EBUSY; + + return 0; +} + +int +OFPlainMutexUnlock(OFPlainMutex *mutex) +{ + LeaveCriticalSection(mutex); + + return 0; +} + +int +OFPlainMutexFree(OFPlainMutex *mutex) +{ + DeleteCriticalSection(mutex); + + return 0; +} + +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexNew(rmutex); +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexLock(rmutex); +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexTryLock(rmutex); +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexUnlock(rmutex); +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexFree(rmutex); +} ADDED src/platform/windows/OFPlainThread.m Index: src/platform/windows/OFPlainThread.m ================================================================== --- src/platform/windows/OFPlainThread.m +++ src/platform/windows/OFPlainThread.m @@ -0,0 +1,133 @@ +/* + * 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 "OFPlainThread.h" + +#import "macros.h" + +#include + +struct ThreadContext { + void (*function)(id); + id object; +}; + +static WINAPI void +functionWrapper(struct ThreadContext *context) +{ + context->function(context->object); + + free(context); +} + +int +OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) +{ + attr->priority = 0; + attr->stackSize = 0; + + return 0; +} + +int +OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), + id object, const OFPlainThreadAttributes *attr) +{ + DWORD priority = THREAD_PRIORITY_NORMAL; + struct ThreadContext *context; + DWORD threadID; + + if (attr != NULL && attr->priority != 0) { + if (attr->priority < -1 || attr->priority > 1) + return EINVAL; + + if (attr->priority < 0) + priority = THREAD_PRIORITY_LOWEST + + (1.0 + attr->priority) * + (THREAD_PRIORITY_NORMAL - THREAD_PRIORITY_LOWEST); + else + priority = THREAD_PRIORITY_NORMAL + + attr->priority * + (THREAD_PRIORITY_HIGHEST - THREAD_PRIORITY_NORMAL); + } + + if ((context = malloc(sizeof(*context))) == NULL) + return ENOMEM; + + context->function = function; + context->object = object; + + *thread = CreateThread(NULL, (attr != NULL ? attr->stackSize : 0), + (LPTHREAD_START_ROUTINE)functionWrapper, context, 0, &threadID); + + if (thread == NULL) { + int error; + + switch (GetLastError()) { + case ERROR_NOT_ENOUGH_MEMORY: + error = ENOMEM; + break; + case ERROR_ACCESS_DENIED: + error = EACCES; + break; + default: + OFEnsure(0); + } + + free(context); + return error; + } + + if (attr != NULL && attr->priority != 0) + OFEnsure(!SetThreadPriority(*thread, priority)); + + return 0; +} + +int +OFPlainThreadJoin(OFPlainThread thread) +{ + switch (WaitForSingleObject(thread, INFINITE)) { + case WAIT_OBJECT_0: + CloseHandle(thread); + return 0; + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + default: + OFEnsure(0); + } +} + +int +OFPlainThreadDetach(OFPlainThread thread) +{ + CloseHandle(thread); + + return 0; +} + +void +OFSetThreadName(const char *name) +{ +} ADDED src/platform/windows/OFTLSKey.m Index: src/platform/windows/OFTLSKey.m ================================================================== --- src/platform/windows/OFTLSKey.m +++ src/platform/windows/OFTLSKey.m @@ -0,0 +1,35 @@ +/* + * 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" + +#import "OFTLSKey.h" + +int +OFTLSKeyNew(OFTLSKey *key) +{ + *key = TlsAlloc(); + + if (*key == TLS_OUT_OF_INDEXES) + return EAGAIN; + + return 0; +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + return (TlsFree(key) ? 0 : EINVAL); +} DELETED src/platform/windows/condition.m Index: src/platform/windows/condition.m ================================================================== --- src/platform/windows/condition.m +++ src/platform/windows/condition.m @@ -1,135 +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 "condition.h" - -#include - -int -OFPlainConditionNew(OFPlainCondition *condition) -{ - condition->count = 0; - - if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) - return EAGAIN; - - return 0; -} - -int -OFPlainConditionSignal(OFPlainCondition *condition) -{ - if (!SetEvent(condition->event)) { - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - return EINVAL; - default: - OFEnsure(0); - } - } - - return 0; -} - -int -OFPlainConditionBroadcast(OFPlainCondition *condition) -{ - int count = condition->count; - - for (int i = 0; i < count; i++) { - if (!SetEvent(condition->event)) { - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - return EINVAL; - default: - OFEnsure(0); - } - } - } - - return 0; -} - -int -OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) -{ - int error; - DWORD status; - - if ((error = OFPlainMutexUnlock(mutex)) != 0) - return error; - - OFAtomicIntIncrease(&condition->count); - status = WaitForSingleObject(condition->event, INFINITE); - OFAtomicIntDecrease(&condition->count); - - switch (status) { - case WAIT_OBJECT_0: - return OFPlainMutexLock(mutex); - case WAIT_FAILED: - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - return EINVAL; - default: - OFEnsure(0); - } - default: - OFEnsure(0); - } -} - -int -OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, - OFTimeInterval timeout) -{ - int error; - DWORD status; - - if ((error = OFPlainMutexUnlock(mutex)) != 0) - return error; - - OFAtomicIntIncrease(&condition->count); - status = WaitForSingleObject(condition->event, timeout * 1000); - OFAtomicIntDecrease(&condition->count); - - switch (status) { - case WAIT_OBJECT_0: - return OFPlainMutexLock(mutex); - case WAIT_TIMEOUT: - return ETIMEDOUT; - case WAIT_FAILED: - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - return EINVAL; - default: - OFEnsure(0); - } - default: - OFEnsure(0); - } -} - -int -OFPlainConditionFree(OFPlainCondition *condition) -{ - if (condition->count != 0) - return EBUSY; - - return (CloseHandle(condition->event) ? 0 : EINVAL); -} DELETED src/platform/windows/mutex.m Index: src/platform/windows/mutex.m ================================================================== --- src/platform/windows/mutex.m +++ src/platform/windows/mutex.m @@ -1,93 +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 "mutex.h" - -#include - -int -OFPlainMutexNew(OFPlainMutex *mutex) -{ - InitializeCriticalSection(mutex); - - return 0; -} - -int -OFPlainMutexLock(OFPlainMutex *mutex) -{ - EnterCriticalSection(mutex); - - return 0; -} - -int -OFPlainMutexTryLock(OFPlainMutex *mutex) -{ - if (!TryEnterCriticalSection(mutex)) - return EBUSY; - - return 0; -} - -int -OFPlainMutexUnlock(OFPlainMutex *mutex) -{ - LeaveCriticalSection(mutex); - - return 0; -} - -int -OFPlainMutexFree(OFPlainMutex *mutex) -{ - DeleteCriticalSection(mutex); - - return 0; -} - -int -OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexNew(rmutex); -} - -int -OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexLock(rmutex); -} - -int -OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexTryLock(rmutex); -} - -int -OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexUnlock(rmutex); -} - -int -OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexFree(rmutex); -} DELETED src/platform/windows/thread.m Index: src/platform/windows/thread.m ================================================================== --- src/platform/windows/thread.m +++ src/platform/windows/thread.m @@ -1,132 +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 "thread.h" -#import "macros.h" - -#include - -struct thread_context { - void (*function)(id); - id object; -}; - -static WINAPI void -functionWrapper(struct thread_context *context) -{ - context->function(context->object); - - free(context); -} - -int -OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) -{ - attr->priority = 0; - attr->stackSize = 0; - - return 0; -} - -int -OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), - id object, const OFPlainThreadAttributes *attr) -{ - DWORD priority = THREAD_PRIORITY_NORMAL; - struct thread_context *context; - DWORD threadID; - - if (attr != NULL && attr->priority != 0) { - if (attr->priority < -1 || attr->priority > 1) - return EINVAL; - - if (attr->priority < 0) - priority = THREAD_PRIORITY_LOWEST + - (1.0 + attr->priority) * - (THREAD_PRIORITY_NORMAL - THREAD_PRIORITY_LOWEST); - else - priority = THREAD_PRIORITY_NORMAL + - attr->priority * - (THREAD_PRIORITY_HIGHEST - THREAD_PRIORITY_NORMAL); - } - - if ((context = malloc(sizeof(*context))) == NULL) - return ENOMEM; - - context->function = function; - context->object = object; - - *thread = CreateThread(NULL, (attr != NULL ? attr->stackSize : 0), - (LPTHREAD_START_ROUTINE)functionWrapper, context, 0, &threadID); - - if (thread == NULL) { - int error; - - switch (GetLastError()) { - case ERROR_NOT_ENOUGH_MEMORY: - error = ENOMEM; - break; - case ERROR_ACCESS_DENIED: - error = EACCES; - break; - default: - OFEnsure(0); - } - - free(context); - return error; - } - - if (attr != NULL && attr->priority != 0) - OFEnsure(!SetThreadPriority(*thread, priority)); - - return 0; -} - -int -OFPlainThreadJoin(OFPlainThread thread) -{ - switch (WaitForSingleObject(thread, INFINITE)) { - case WAIT_OBJECT_0: - CloseHandle(thread); - return 0; - case WAIT_FAILED: - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - return EINVAL; - default: - OFEnsure(0); - } - default: - OFEnsure(0); - } -} - -int -OFPlainThreadDetach(OFPlainThread thread) -{ - CloseHandle(thread); - - return 0; -} - -void -OFSetThreadName(const char *name) -{ -} DELETED src/platform/windows/tlskey.m Index: src/platform/windows/tlskey.m ================================================================== --- src/platform/windows/tlskey.m +++ src/platform/windows/tlskey.m @@ -1,35 +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" - -#import "tlskey.h" - -int -OFTLSKeyNew(OFTLSKey *key) -{ - *key = TlsAlloc(); - - if (*key == TLS_OUT_OF_INDEXES) - return EAGAIN; - - return 0; -} - -int -OFTLSKeyFree(OFTLSKey key) -{ - return (TlsFree(key) ? 0 : EINVAL); -} Index: src/runtime/Makefile ================================================================== --- src/runtime/Makefile +++ src/runtime/Makefile @@ -30,14 +30,14 @@ sparsearray.m \ static-instances.m \ synchronized.m \ tagged-pointer.m \ ${USE_SRCS_THREADS} -SRCS_THREADS = mutex.m \ - once.m \ - threading.m \ - tlskey.m +SRCS_THREADS = OFOnce.m \ + OFPlainMutex.m \ + OFTLSKey.m \ + threading.m INCLUDES = ObjFWRT.h includesubdir = ObjFWRT OBJS_EXTRA = lookup-asm/lookup-asm.a LIB_OBJS_EXTRA = lookup-asm/lookup-asm.lib.a ADDED src/runtime/OFOnce.m Index: src/runtime/OFOnce.m ================================================================== --- src/runtime/OFOnce.m +++ src/runtime/OFOnce.m @@ -0,0 +1,21 @@ +/* + * 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" + +#import "ObjFWRT.h" +#import "private.h" + +#include "../OFOnce.m" ADDED src/runtime/OFPlainMutex.m Index: src/runtime/OFPlainMutex.m ================================================================== --- src/runtime/OFPlainMutex.m +++ src/runtime/OFPlainMutex.m @@ -0,0 +1,21 @@ +/* + * 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" + +#import "ObjFWRT.h" +#import "private.h" + +#include "../OFPlainMutex.m" ADDED src/runtime/OFTLSKey.m Index: src/runtime/OFTLSKey.m ================================================================== --- src/runtime/OFTLSKey.m +++ src/runtime/OFTLSKey.m @@ -0,0 +1,21 @@ +/* + * 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" + +#import "ObjFWRT.h" +#import "private.h" + +#include "../OFTLSKey.m" Index: src/runtime/arc.m ================================================================== --- src/runtime/arc.m +++ src/runtime/arc.m @@ -17,11 +17,11 @@ #import "ObjFWRT.h" #import "private.h" #ifdef OF_HAVE_THREADS -# import "mutex.h" +# import "OFPlainMutex.h" #endif struct weakref { id **locations; size_t count; Index: src/runtime/autorelease.m ================================================================== --- src/runtime/autorelease.m +++ src/runtime/autorelease.m @@ -25,11 +25,11 @@ # import #endif #import "macros.h" #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) -# import "tlskey.h" +# import "OFTLSKey.h" #endif #ifndef OF_OBJFW_RUNTIME @interface DummyObject - (void)release; Index: src/runtime/exception.m ================================================================== --- src/runtime/exception.m +++ src/runtime/exception.m @@ -24,11 +24,11 @@ #import "ObjFWRT.h" #import "private.h" #import "macros.h" #ifdef OF_HAVE_THREADS -# include "mutex.h" +# include "OFPlainMutex.h" #endif #ifdef HAVE_SEH_EXCEPTIONS # include #endif DELETED src/runtime/mutex.m Index: src/runtime/mutex.m ================================================================== --- src/runtime/mutex.m +++ src/runtime/mutex.m @@ -1,21 +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" - -#import "ObjFWRT.h" -#import "private.h" - -#include "../mutex.m" DELETED src/runtime/once.m Index: src/runtime/once.m ================================================================== --- src/runtime/once.m +++ src/runtime/once.m @@ -1,21 +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" - -#import "ObjFWRT.h" -#import "private.h" - -#include "../once.m" Index: src/runtime/property.m ================================================================== --- src/runtime/property.m +++ src/runtime/property.m @@ -19,11 +19,11 @@ #import "ObjFWRT.h" #import "private.h" #ifdef OF_HAVE_THREADS -# import "mutex.h" +# import "OFPlainMutex.h" # define NUM_SPINLOCKS 8 /* needs to be a power of 2 */ # define SPINLOCK_HASH(p) ((unsigned)((uintptr_t)p >> 4) & (NUM_SPINLOCKS - 1)) static OFSpinlock spinlocks[NUM_SPINLOCKS]; #endif Index: src/runtime/synchronized.m ================================================================== --- src/runtime/synchronized.m +++ src/runtime/synchronized.m @@ -20,11 +20,11 @@ #import "ObjFWRT.h" #import "private.h" #ifdef OF_HAVE_THREADS -# import "mutex.h" +# import "OFPlainMutex.h" static struct lock { id object; int count; OFPlainRecursiveMutex rmutex; Index: src/runtime/threading.m ================================================================== --- src/runtime/threading.m +++ src/runtime/threading.m @@ -18,12 +18,13 @@ #include #include #import "ObjFWRT.h" #import "private.h" -#import "mutex.h" -#import "once.h" + +#import "OFOnce.h" +#import "OFPlainMutex.h" static OFPlainRecursiveMutex globalMutex; static void init(void) DELETED src/runtime/tlskey.m Index: src/runtime/tlskey.m ================================================================== --- src/runtime/tlskey.m +++ src/runtime/tlskey.m @@ -1,21 +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" - -#import "ObjFWRT.h" -#import "private.h" - -#include "../tlskey.m" DELETED src/scrypt.h Index: src/scrypt.h ================================================================== --- src/scrypt.h +++ src/scrypt.h @@ -1,80 +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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#import "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -/** @file */ - -@class OFHMAC; - -/** - * @brief The parameters for @ref OFScrypt. - */ -typedef struct OFScryptParameters { - /** @brief The block size to use. */ - size_t blockSize; - /** @brief The CPU/memory cost factor to use. */ - size_t costFactor; - /** @brief The parallelization to use. */ - size_t parallelization; - /** @brief The salt to derive a key with. */ - const unsigned char *salt; - /** @brief The length of the salt. */ - size_t saltLength; - /** @brief The password to derive a key from. */ - const char *password; - /** @brief The length of the password. */ - size_t passwordLength; - /** @brief The buffer to write the key to. */ - unsigned char *key; - /** - * @brief The desired length for the derived key. - * - * @ref key needs to have enough storage. - */ - size_t keyLength; - /** @brief Whether data may be stored in swappable memory. */ - bool allowsSwappableMemory; -} OFScryptParameters; - -#ifdef __cplusplus -extern "C" { -#endif -extern void OFSalsa20_8Core(uint32_t buffer[_Nonnull 16]); -extern void OFScryptBlockMix(uint32_t *output, const uint32_t *input, - size_t blockSize); -extern void OFScryptROMix(uint32_t *buffer, size_t blockSize, - size_t costFactor, uint32_t *tmp); - -/** - * @brief Derives a key from a password and a salt using scrypt. - * - * @param param The parameters to use - */ -extern void OFScrypt(OFScryptParameters param); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/scrypt.m Index: src/scrypt.m ================================================================== --- src/scrypt.m +++ src/scrypt.m @@ -1,219 +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" - -#import "OFHMAC.h" -#import "OFSHA256Hash.h" -#import "OFSecureData.h" - -#import "OFInvalidArgumentException.h" -#import "OFOutOfMemoryException.h" -#import "OFOutOfRangeException.h" - -#import "scrypt.h" -#import "pbkdf2.h" - -void -OFSalsa20_8Core(uint32_t buffer[16]) -{ - uint32_t tmp[16]; - - for (uint_fast8_t i = 0; i < 16; i++) - tmp[i] = OFToLittleEndian32(buffer[i]); - - for (uint_fast8_t i = 0; i < 8; i += 2) { - tmp[ 4] ^= OFRotateLeft(tmp[ 0] + tmp[12], 7); - tmp[ 8] ^= OFRotateLeft(tmp[ 4] + tmp[ 0], 9); - tmp[12] ^= OFRotateLeft(tmp[ 8] + tmp[ 4], 13); - tmp[ 0] ^= OFRotateLeft(tmp[12] + tmp[ 8], 18); - tmp[ 9] ^= OFRotateLeft(tmp[ 5] + tmp[ 1], 7); - tmp[13] ^= OFRotateLeft(tmp[ 9] + tmp[ 5], 9); - tmp[ 1] ^= OFRotateLeft(tmp[13] + tmp[ 9], 13); - tmp[ 5] ^= OFRotateLeft(tmp[ 1] + tmp[13], 18); - tmp[14] ^= OFRotateLeft(tmp[10] + tmp[ 6], 7); - tmp[ 2] ^= OFRotateLeft(tmp[14] + tmp[10], 9); - tmp[ 6] ^= OFRotateLeft(tmp[ 2] + tmp[14], 13); - tmp[10] ^= OFRotateLeft(tmp[ 6] + tmp[ 2], 18); - tmp[ 3] ^= OFRotateLeft(tmp[15] + tmp[11], 7); - tmp[ 7] ^= OFRotateLeft(tmp[ 3] + tmp[15], 9); - tmp[11] ^= OFRotateLeft(tmp[ 7] + tmp[ 3], 13); - tmp[15] ^= OFRotateLeft(tmp[11] + tmp[ 7], 18); - tmp[ 1] ^= OFRotateLeft(tmp[ 0] + tmp[ 3], 7); - tmp[ 2] ^= OFRotateLeft(tmp[ 1] + tmp[ 0], 9); - tmp[ 3] ^= OFRotateLeft(tmp[ 2] + tmp[ 1], 13); - tmp[ 0] ^= OFRotateLeft(tmp[ 3] + tmp[ 2], 18); - tmp[ 6] ^= OFRotateLeft(tmp[ 5] + tmp[ 4], 7); - tmp[ 7] ^= OFRotateLeft(tmp[ 6] + tmp[ 5], 9); - tmp[ 4] ^= OFRotateLeft(tmp[ 7] + tmp[ 6], 13); - tmp[ 5] ^= OFRotateLeft(tmp[ 4] + tmp[ 7], 18); - tmp[11] ^= OFRotateLeft(tmp[10] + tmp[ 9], 7); - tmp[ 8] ^= OFRotateLeft(tmp[11] + tmp[10], 9); - tmp[ 9] ^= OFRotateLeft(tmp[ 8] + tmp[11], 13); - tmp[10] ^= OFRotateLeft(tmp[ 9] + tmp[ 8], 18); - tmp[12] ^= OFRotateLeft(tmp[15] + tmp[14], 7); - tmp[13] ^= OFRotateLeft(tmp[12] + tmp[15], 9); - tmp[14] ^= OFRotateLeft(tmp[13] + tmp[12], 13); - tmp[15] ^= OFRotateLeft(tmp[14] + tmp[13], 18); - } - - for (uint_fast8_t i = 0; i < 16; i++) - buffer[i] = OFToLittleEndian32(OFFromLittleEndian32(buffer[i]) + - tmp[i]); - - OFZeroMemory(tmp, sizeof(tmp)); -} - -void -OFScryptBlockMix(uint32_t *output, const uint32_t *input, size_t blockSize) -{ - uint32_t tmp[16]; - - /* Check defined here and executed in OFScrypt() */ -#define OVERFLOW_CHECK_1 \ - if (param.blockSize > SIZE_MAX / 2 || \ - 2 * param.blockSize - 1 > SIZE_MAX / 16) \ - @throw [OFOutOfRangeException exception]; - - memcpy(tmp, input + (2 * blockSize - 1) * 16, 64); - - for (size_t i = 0; i < 2 * blockSize; i++) { - for (size_t j = 0; j < 16; j++) - tmp[j] ^= input[i * 16 + j]; - - OFSalsa20_8Core(tmp); - - /* - * Even indices are stored in the first half and odd ones in - * the second. - */ - memcpy(output + ((i / 2) + (i & 1) * blockSize) * 16, tmp, 64); - } - - OFZeroMemory(tmp, sizeof(tmp)); -} - -void -OFScryptROMix(uint32_t *buffer, size_t blockSize, size_t costFactor, - uint32_t *tmp) -{ - /* Check defined here and executed in OFScrypt() */ -#define OVERFLOW_CHECK_2 \ - if (param.blockSize > SIZE_MAX / 128 / param.costFactor) \ - @throw [OFOutOfRangeException exception]; - - uint32_t *tmp2 = tmp + 32 * blockSize; - - memcpy(tmp, buffer, 128 * blockSize); - - for (size_t i = 0; i < costFactor; i++) { - memcpy(tmp2 + i * 32 * blockSize, tmp, 128 * blockSize); - OFScryptBlockMix(tmp, tmp2 + i * 32 * blockSize, blockSize); - } - - for (size_t i = 0; i < costFactor; i++) { - uint32_t j = OFFromLittleEndian32( - tmp[(2 * blockSize - 1) * 16]) & (costFactor - 1); - - for (size_t k = 0; k < 32 * blockSize; k++) - tmp[k] ^= tmp2[j * 32 * blockSize + k]; - - OFScryptBlockMix(buffer, tmp, blockSize); - - if (i < costFactor - 1) - memcpy(tmp, buffer, 128 * blockSize); - } -} - -void -OFScrypt(OFScryptParameters param) -{ - OFSecureData *tmp = nil, *buffer = nil; - OFHMAC *HMAC = nil; - - if (param.blockSize == 0 || param.costFactor <= 1 || - (param.costFactor & (param.costFactor - 1)) != 0 || - param.parallelization == 0) - @throw [OFInvalidArgumentException exception]; - - /* - * These are defined by the functions above. They are defined there so - * that the check is next to the code and easy to verify, but actually - * checked here for performance. - */ - OVERFLOW_CHECK_1 - OVERFLOW_CHECK_2 - - @try { - uint32_t *tmpItems, *bufferItems; - - if (param.costFactor > SIZE_MAX - 1 || - (param.costFactor + 1) > SIZE_MAX / 128) - @throw [OFOutOfRangeException exception]; - - tmp = [[OFSecureData alloc] - initWithCount: (param.costFactor + 1) * 128 - itemSize: param.blockSize - allowsSwappableMemory: param.allowsSwappableMemory]; - tmpItems = tmp.mutableItems; - - if (param.parallelization > SIZE_MAX / 128) - @throw [OFOutOfRangeException exception]; - - buffer = [[OFSecureData alloc] - initWithCount: param.parallelization * 128 - itemSize: param.blockSize - allowsSwappableMemory: param.allowsSwappableMemory]; - bufferItems = buffer.mutableItems; - - HMAC = [[OFHMAC alloc] - initWithHashClass: [OFSHA256Hash class] - allowsSwappableMemory: param.allowsSwappableMemory]; - - OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 1, - .salt = param.salt, - .saltLength = param.saltLength, - .password = param.password, - .passwordLength = param.passwordLength, - .key = (unsigned char *)bufferItems, - .keyLength = param.parallelization * 128 * - param.blockSize, - .allowsSwappableMemory = param.allowsSwappableMemory - }); - - for (size_t i = 0; i < param.parallelization; i++) - OFScryptROMix(bufferItems + i * 32 * param.blockSize, - param.blockSize, param.costFactor, tmpItems); - - OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 1, - .salt = (unsigned char *)bufferItems, - .saltLength = param.parallelization * 128 * - param.blockSize, - .password = param.password, - .passwordLength = param.passwordLength, - .key = param.key, - .keyLength = param.keyLength, - .allowsSwappableMemory = param.allowsSwappableMemory - }); - } @finally { - [tmp release]; - [buffer release]; - [HMAC release]; - } -} DELETED src/socket.h Index: src/socket.h ================================================================== --- src/socket.h +++ src/socket.h @@ -1,297 +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 "objfw-defs.h" - -#ifndef OF_HAVE_SOCKETS -# error No sockets available! -#endif - -#include - -#import "OFString.h" - -#ifdef OF_HAVE_SYS_SOCKET_H -# include -#endif -#ifdef OF_HAVE_NETINET_IN_H -# include -#endif -#ifdef OF_HAVE_NETINET_TCP_H -# include -#endif -#ifdef OF_HAVE_NETIPX_IPX_H -# include -#endif - -#include "platform.h" - -#ifdef OF_WINDOWS -# include -# include -# ifdef OF_HAVE_IPX -# include -# endif -#endif - -/** @file */ - -#ifdef OF_WII -# include -#endif - -#ifdef OF_PSP -# include -#endif - -#import "macros.h" -#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) -# import "tlskey.h" -#endif - -OF_ASSUME_NONNULL_BEGIN - -#ifndef OF_WINDOWS -typedef int OFSocketHandle; -#else -typedef SOCKET OFSocketHandle; -#endif - -#ifdef OF_WII -typedef u8 sa_family_t; -#endif - -#ifdef OF_MORPHOS -typedef long socklen_t; -typedef u_char sa_family_t; -typedef u_short in_port_t; -#endif - -/** - * @brief A socket address family. - */ -typedef enum { - /** An unknown address family. */ - OFSocketAddressFamilyUnknown, - /** IPv4 */ - OFSocketAddressFamilyIPv4, - /** IPv6 */ - OFSocketAddressFamilyIPv6, - /** IPX */ - OFSocketAddressFamilyIPX, - /** Any address family */ - OFSocketAddressFamilyAny = 255 -} OFSocketAddressFamily; - -#ifndef OF_HAVE_IPV6 -struct sockaddr_in6 { - sa_family_t sin6_family; - in_port_t sin6_port; - uint32_t sin6_flowinfo; - struct in6_addr { - uint8_t s6_addr[16]; - } sin6_addr; - uint32_t sin6_scope_id; -}; -#endif - -#ifndef OF_HAVE_IPX -# define IPX_NODE_LEN 6 -struct sockaddr_ipx { - sa_family_t sipx_family; - uint32_t sipx_network; - unsigned char sipx_node[IPX_NODE_LEN]; - uint16_t sipx_port; - uint8_t sipx_type; -}; -#endif -#ifdef OF_WINDOWS -# define IPX_NODE_LEN 6 -# define sipx_family sa_family -# define sipx_network sa_netnum -# define sipx_node sa_nodenum -# define sipx_port sa_socket -#endif - -/** - * @struct OFSocketAddress socket.h ObjFW/socket.h - * - * @brief A struct which represents a host / port pair for a socket. - */ -struct OF_BOXABLE OFSocketAddress { - /* - * Even though struct sockaddr contains the family, we need to use our - * own family, as we need to support storing an IPv6 address on systems - * that don't support IPv6. These may not have AF_INET6 defined and we - * can't just define it, as the value is system-dependent and might - * clash with an existing value. - */ - OFSocketAddressFamily family; - union { - struct sockaddr sockaddr; - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr_ipx ipx; - } sockaddr; - socklen_t length; -}; -typedef struct OFSocketAddress OFSocketAddress; - -#ifdef __cplusplus -extern "C" { -#endif -/** - * @brief Parses the specified IP (either v4 or v6) and port into an - * @ref OFSocketAddress. - * - * @param IP The IP to parse - * @param port The port to use - * @return The parsed IP and port as an OFSocketAddress - */ -extern OFSocketAddress OFSocketAddressParseIP(OFString *IP, uint16_t port); - -/** - * @brief Parses the specified IPv4 and port into an @ref OFSocketAddress. - * - * @param IP The IPv4 to parse - * @param port The port to use - * @return The parsed IPv4 and port as an OFSocketAddress - */ -extern OFSocketAddress OFSocketAddressParseIPv4(OFString *IP, uint16_t port); - -/** - * @brief Parses the specified IPv6 and port into an @ref OFSocketAddress. - * - * @param IP The IPv6 to parse - * @param port The port to use - * @return The parsed IPv6 and port as an OFSocketAddress - */ -extern OFSocketAddress OFSocketAddressParseIPv6(OFString *IP, uint16_t port); - -/** - * @brief Creates an IPX address for the specified network, node and port. - * - * @param node The node in the IPX network - * @param network The IPX network - * @param port The IPX port (sometimes called socket number) on the node - */ -extern OFSocketAddress OFSocketAddressMakeIPX( - const unsigned char node[_Nonnull IPX_NODE_LEN], uint32_t network, - uint16_t port); - -/** - * @brief Compares two OFSocketAddress for equality. - * - * @param address1 The address to compare with the second address - * @param address2 The second address - * @return Whether the two addresses are equal - */ -extern bool OFSocketAddressEqual(const OFSocketAddress *_Nonnull address1, - const OFSocketAddress *_Nonnull address2); - -/** - * @brief Returns the hash for the specified @ref OFSocketAddress. - * - * @param address The address to hash - * @return The hash for the specified OFSocketAddress - */ -extern unsigned long OFSocketAddressHash( - const OFSocketAddress *_Nonnull address); - -/** - * @brief Converts the specified @ref OFSocketAddress to a string. - * - * @param address The address to convert to a string - * @return The address as an IP string - */ -extern OFString *_Nonnull OFSocketAddressString( - const OFSocketAddress *_Nonnull address); - -/** - * @brief Sets the port of the specified @ref OFSocketAddress, independent of - * the address family used. - * - * @param address The address on which to set the port - * @param port The port to set on the address - */ -extern void OFSocketAddressSetPort(OFSocketAddress *_Nonnull address, - uint16_t port); - -/** - * @brief Returns the port of the specified @ref OFSocketAddress, independent of - * the address family used. - * - * @param address The address on which to get the port - * @return The port of the address - */ -extern uint16_t OFSocketAddressPort(const OFSocketAddress *_Nonnull address); - -/** - * @brief Sets the IPX network of the specified @ref OFSocketAddress. - * - * @param address The address on which to set the IPX network - * @param network The IPX network to set on the address - */ -extern void OFSocketAddressSetIPXNetwork(OFSocketAddress *_Nonnull address, - uint32_t network); - -/** - * @brief Returns the IPX network of the specified @ref OFSocketAddress. - * - * @param address The address on which to get the IPX network - * @return The IPX network of the address - */ -extern uint32_t OFSocketAddressIPXNetwork( - const OFSocketAddress *_Nonnull address); - -/** - * @brief Sets the IPX node of the specified @ref OFSocketAddress. - * - * @param address The address on which to set the IPX node - * @param node The IPX node to set on the address - */ -extern void OFSocketAddressSetIPXNode(OFSocketAddress *_Nonnull address, - const unsigned char node[_Nonnull IPX_NODE_LEN]); - -/** - * @brief Gets the IPX node of the specified @ref OFSocketAddress. - * - * @param address The address on which to get the IPX node - * @param node A byte array to store the IPX node of the address - */ -extern void OFSocketAddressIPXNode(const OFSocketAddress *_Nonnull address, - unsigned char node[_Nonnull IPX_NODE_LEN]); - -extern bool of_socket_init(void); -#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) -extern void of_socket_deinit(void); -#endif -extern int of_socket_errno(void); -#if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) -extern int of_getsockname(OFSocketHandle sock, struct sockaddr *restrict addr, - socklen_t *restrict addrLen); -#endif - -#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) -extern OFTLSKey of_socket_base_key; -# ifdef OF_AMIGAOS4 -extern OFTLSKey of_socket_interface_key; -# endif -#endif -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/socket.m Index: src/socket.m ================================================================== --- src/socket.m +++ src/socket.m @@ -1,851 +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" - -#ifndef _XOPEN_SOURCE_EXTENDED -# define _XOPEN_SOURCE_EXTENDED -#endif -#define _HPUX_ALT_XOPEN_SOCKET_API - -#ifdef OF_NINTENDO_3DS -# include /* For memalign() */ -#endif - -#include - -#import "OFArray.h" -#import "OFCharacterSet.h" -#import "OFLocale.h" -#ifdef OF_HAVE_THREADS -# import "OFMutex.h" -#endif -#import "OFString.h" - -#import "OFException.h" /* For some E* -> WSAE* defines */ -#import "OFInitializationFailedException.h" -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" -#import "OFLockFailedException.h" -#import "OFUnlockFailedException.h" - -#import "socket.h" -#import "socket_helpers.h" -#ifdef OF_HAVE_THREADS -# import "tlskey.h" -#endif -#import "once.h" - -#ifdef OF_AMIGAOS -# include -#endif - -#ifdef OF_NINTENDO_3DS -# include <3ds/types.h> -# include <3ds/services/soc.h> -#endif - -#if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) -static OFMutex *mutex; - -static void -releaseMutex(void) -{ - [mutex release]; -} -#endif -#if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) || !defined(OF_HAVE_THREADS) -static bool initSuccessful = false; -#endif - -#ifdef OF_AMIGAOS -# if defined(OF_HAVE_THREADS) && !defined(OF_MORPHOS) -OFTLSKey of_socket_base_key; -# ifdef OF_AMIGAOS4 -OFTLSKey of_socket_interface_key; -# endif -# else -struct Library *SocketBase; -# ifdef OF_AMIGAOS4 -struct SocketIFace *ISocket = NULL; -# endif -# endif -#endif - -#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) -OF_CONSTRUCTOR() -{ - if (OFTLSKeyNew(&of_socket_base_key) != 0) - @throw [OFInitializationFailedException exception]; - -# ifdef OF_AMIGAOS4 - if (OFTLSKeyNew(&of_socket_interface_key) != 0) - @throw [OFInitializationFailedException exception]; -# endif -} -#endif - -#if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) || !defined(OF_HAVE_THREADS) -static void -init(void) -{ -# if defined(OF_WINDOWS) - WSADATA wsa; - - if (WSAStartup(MAKEWORD(2, 0), &wsa)) - return; -# elif defined(OF_AMIGAOS) - if ((SocketBase = OpenLibrary("bsdsocket.library", 4)) == NULL) - return; - -# ifdef OF_AMIGAOS4 - if ((ISocket = (struct SocketIFace *) - GetInterface(SocketBase, "main", 1, NULL)) == NULL) { - CloseLibrary(SocketBase); - return; - } -# endif -# elif defined(OF_WII) - if (net_init() < 0) - return; -# elif defined(OF_NINTENDO_3DS) - void *ctx; - - if ((ctx = memalign(0x1000, 0x100000)) == NULL) - return; - - if (socInit(ctx, 0x100000) != 0) - return; - - atexit((void (*)(void))socExit); -# endif - -# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) - mutex = [[OFMutex alloc] init]; - atexit(releaseMutex); - -# ifdef OF_WII - if (OFSpinlockNew(&spinlock) != 0) - return; -# endif -# endif - - initSuccessful = true; -} - -OF_DESTRUCTOR() -{ -# ifdef OF_AMIGAOS -# ifdef OF_AMIGAOS4 - if (ISocket != NULL) - DropInterface((struct Interface *)ISocket); -# endif - - if (SocketBase != NULL) - CloseLibrary(SocketBase); -# endif -} -#endif - -bool -of_socket_init(void) -{ -#if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) || !defined(OF_HAVE_THREADS) - static OFOnceControl onceControl = OFOnceControlInitValue; - OFOnce(&onceControl, init); - - return initSuccessful; -#else - struct Library *socketBase; -# ifdef OF_AMIGAOS4 - struct SocketIFace *socketInterface; -# endif - -# ifdef OF_AMIGAOS4 - if ((socketInterface = OFTLSKeyGet(of_socket_interface_key)) != NULL) -# else - if ((socketBase = OFTLSKeyGet(of_socket_base_key)) != NULL) -# endif - return true; - - if ((socketBase = OpenLibrary("bsdsocket.library", 4)) == NULL) - return false; - -# ifdef OF_AMIGAOS4 - if ((socketInterface = (struct SocketIFace *) - GetInterface(socketBase, "main", 1, NULL)) == NULL) { - CloseLibrary(socketBase); - return false; - } -# endif - - if (OFTLSKeySet(of_socket_base_key, socketBase) != 0) { - CloseLibrary(socketBase); -# ifdef OF_AMIGAOS4 - DropInterface((struct Interface *)socketInterface); -# endif - return false; - } - -# ifdef OF_AMIGAOS4 - if (OFTLSKeySet(of_socket_interface_key, socketInterface) != 0) { - CloseLibrary(socketBase); - DropInterface((struct Interface *)socketInterface); - return false; - } -# endif - - return true; -#endif -} - -#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) -void -of_socket_deinit(void) -{ - struct Library *socketBase = OFTLSKeyGet(of_socket_base_key); -# ifdef OF_AMIGAOS4 - struct SocketIFace *socketInterface = - OFTLSKeyGet(of_socket_interface_key); - - if (socketInterface != NULL) - DropInterface((struct Interface *)socketInterface); -# endif - if (socketBase != NULL) - CloseLibrary(socketBase); -} -#endif - -int -of_socket_errno() -{ -#if defined(OF_WINDOWS) - switch (WSAGetLastError()) { - case WSAEACCES: - return EACCES; - case WSAEADDRINUSE: - return EADDRINUSE; - case WSAEADDRNOTAVAIL: - return EADDRNOTAVAIL; - case WSAEAFNOSUPPORT: - return EAFNOSUPPORT; - case WSAEALREADY: - return EALREADY; - case WSAEBADF: - return EBADF; - case WSAECONNABORTED: - return ECONNABORTED; - case WSAECONNREFUSED: - return ECONNREFUSED; - case WSAECONNRESET: - return ECONNRESET; - case WSAEDESTADDRREQ: - return EDESTADDRREQ; - case WSAEDISCON: - return EPIPE; - case WSAEDQUOT: - return EDQUOT; - case WSAEFAULT: - return EFAULT; - case WSAEHOSTDOWN: - return EHOSTDOWN; - case WSAEHOSTUNREACH: - return EHOSTUNREACH; - case WSAEINPROGRESS: - return EINPROGRESS; - case WSAEINTR: - return EINTR; - case WSAEINVAL: - return EINVAL; - case WSAEISCONN: - return EISCONN; - case WSAELOOP: - return ELOOP; - case WSAEMSGSIZE: - return EMSGSIZE; - case WSAENAMETOOLONG: - return ENAMETOOLONG; - case WSAENETDOWN: - return ENETDOWN; - case WSAENETRESET: - return ENETRESET; - case WSAENETUNREACH: - return ENETUNREACH; - case WSAENOBUFS: - return ENOBUFS; - case WSAENOPROTOOPT: - return ENOPROTOOPT; - case WSAENOTCONN: - return ENOTCONN; - case WSAENOTEMPTY: - return ENOTEMPTY; - case WSAENOTSOCK: - return ENOTSOCK; - case WSAEOPNOTSUPP: - return EOPNOTSUPP; - case WSAEPFNOSUPPORT: - return EPFNOSUPPORT; - case WSAEPROCLIM: - return EPROCLIM; - case WSAEPROTONOSUPPORT: - return EPROTONOSUPPORT; - case WSAEPROTOTYPE: - return EPROTOTYPE; - case WSAEREMOTE: - return EREMOTE; - case WSAESHUTDOWN: - return ESHUTDOWN; - case WSAESOCKTNOSUPPORT: - return ESOCKTNOSUPPORT; - case WSAESTALE: - return ESTALE; - case WSAETIMEDOUT: - return ETIMEDOUT; - case WSAETOOMANYREFS: - return ETOOMANYREFS; - case WSAEUSERS: - return EUSERS; - case WSAEWOULDBLOCK: - return EWOULDBLOCK; - } - - return 0; -#elif defined(OF_AMIGAOS) - return Errno(); -#else - return errno; -#endif -} - -#ifndef OF_WII -int -of_getsockname(OFSocketHandle sock, struct sockaddr *restrict addr, - socklen_t *restrict addrLen) -{ - int ret; - -# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) - [mutex lock]; -# endif - ret = getsockname(sock, addr, addrLen); -# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) - [mutex unlock]; -# endif - - return ret; -} -#endif - -OFSocketAddress -OFSocketAddressParseIPv4(OFString *IPv4, uint16_t port) -{ - void *pool = objc_autoreleasePoolPush(); - OFCharacterSet *whitespaceCharacterSet = - [OFCharacterSet whitespaceCharacterSet]; - OFSocketAddress ret; - struct sockaddr_in *addrIn = &ret.sockaddr.in; - OFArray OF_GENERIC(OFString *) *components; - uint32_t addr; - - memset(&ret, '\0', sizeof(ret)); - ret.family = OFSocketAddressFamilyIPv4; -#if defined(OF_WII) || defined(OF_NINTENDO_3DS) - ret.length = 8; -#else - ret.length = sizeof(ret.sockaddr.in); -#endif - - addrIn->sin_family = AF_INET; - addrIn->sin_port = OFToBigEndian16(port); -#ifdef OF_WII - addrIn->sin_len = ret.length; -#endif - - components = [IPv4 componentsSeparatedByString: @"."]; - - if (components.count != 4) - @throw [OFInvalidFormatException exception]; - - addr = 0; - - for (OFString *component in components) { - unsigned long long number; - - if (component.length == 0) - @throw [OFInvalidFormatException exception]; - - if ([component indexOfCharacterFromSet: - whitespaceCharacterSet] != OFNotFound) - @throw [OFInvalidFormatException exception]; - - number = component.unsignedLongLongValue; - - if (number > UINT8_MAX) - @throw [OFInvalidFormatException exception]; - - addr = (addr << 8) | ((uint32_t)number & 0xFF); - } - - addrIn->sin_addr.s_addr = OFToBigEndian32(addr); - - objc_autoreleasePoolPop(pool); - - return ret; -} - -static uint16_t -parseIPv6Component(OFString *component) -{ - unsigned long long number; - - if ([component indexOfCharacterFromSet: - [OFCharacterSet whitespaceCharacterSet]] != OFNotFound) - @throw [OFInvalidFormatException exception]; - - number = [component unsignedLongLongValueWithBase: 16]; - - if (number > UINT16_MAX) - @throw [OFInvalidFormatException exception]; - - return (uint16_t)number; -} - -OFSocketAddress -OFSocketAddressParseIPv6(OFString *IPv6, uint16_t port) -{ - void *pool = objc_autoreleasePoolPush(); - OFSocketAddress ret; - struct sockaddr_in6 *addrIn6 = &ret.sockaddr.in6; - size_t doubleColon; - - memset(&ret, '\0', sizeof(ret)); - ret.family = OFSocketAddressFamilyIPv6; - ret.length = sizeof(ret.sockaddr.in6); - -#ifdef AF_INET6 - addrIn6->sin6_family = AF_INET6; -#else - addrIn6->sin6_family = AF_UNSPEC; -#endif - addrIn6->sin6_port = OFToBigEndian16(port); - - doubleColon = [IPv6 rangeOfString: @"::"].location; - - if (doubleColon != OFNotFound) { - OFString *left = [IPv6 substringToIndex: doubleColon]; - OFString *right = [IPv6 substringFromIndex: doubleColon + 2]; - OFArray OF_GENERIC(OFString *) *leftComponents; - OFArray OF_GENERIC(OFString *) *rightComponents; - size_t i; - - if ([right hasPrefix: @":"] || [right containsString: @"::"]) - @throw [OFInvalidFormatException exception]; - - leftComponents = [left componentsSeparatedByString: @":"]; - rightComponents = [right componentsSeparatedByString: @":"]; - - if (leftComponents.count + rightComponents.count > 7) - @throw [OFInvalidFormatException exception]; - - i = 0; - for (OFString *component in leftComponents) { - uint16_t number = parseIPv6Component(component); - - addrIn6->sin6_addr.s6_addr[i++] = number >> 8; - addrIn6->sin6_addr.s6_addr[i++] = number; - } - - i = 16; - for (OFString *component in rightComponents.reversedArray) { - uint16_t number = parseIPv6Component(component); - - addrIn6->sin6_addr.s6_addr[--i] = number; - addrIn6->sin6_addr.s6_addr[--i] = number >> 8; - } - } else { - OFArray OF_GENERIC(OFString *) *components = - [IPv6 componentsSeparatedByString: @":"]; - size_t i; - - if (components.count != 8) - @throw [OFInvalidFormatException exception]; - - i = 0; - for (OFString *component in components) { - uint16_t number; - - if (component.length == 0) - @throw [OFInvalidFormatException exception]; - - number = parseIPv6Component(component); - - addrIn6->sin6_addr.s6_addr[i++] = number >> 8; - addrIn6->sin6_addr.s6_addr[i++] = number; - } - } - - objc_autoreleasePoolPop(pool); - - return ret; -} - -OFSocketAddress -OFSocketAddressParseIP(OFString *IP, uint16_t port) -{ - OFSocketAddress ret; - - @try { - ret = OFSocketAddressParseIPv6(IP, port); - } @catch (OFInvalidFormatException *e) { - ret = OFSocketAddressParseIPv4(IP, port); - } - - return ret; -} - -OFSocketAddress -OFSocketAddressMakeIPX(const unsigned char node[IPX_NODE_LEN], uint32_t network, - uint16_t port) -{ - OFSocketAddress ret; - - memset(&ret, '\0', sizeof(ret)); - ret.family = OFSocketAddressFamilyIPX; - ret.length = sizeof(ret.sockaddr.ipx); - -#ifdef AF_IPX - ret.sockaddr.ipx.sipx_family = AF_IPX; -#else - ret.sockaddr.ipx.sipx_family = AF_UNSPEC; -#endif - memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); - network = OFToBigEndian32(network); - memcpy(&ret.sockaddr.ipx.sipx_network, &network, - sizeof(ret.sockaddr.ipx.sipx_network)); - ret.sockaddr.ipx.sipx_port = OFToBigEndian16(port); - - return ret; -} - -bool -OFSocketAddressEqual(const OFSocketAddress *address1, - const OFSocketAddress *address2) -{ - const struct sockaddr_in *addrIn1, *addrIn2; - const struct sockaddr_in6 *addrIn6_1, *addrIn6_2; - const struct sockaddr_ipx *addrIPX1, *addrIPX2; - - if (address1->family != address2->family) - return false; - - switch (address1->family) { - case OFSocketAddressFamilyIPv4: -#if defined(OF_WII) || defined(OF_NINTENDO_3DS) - if (address1->length < 8 || address2->length < 8) - @throw [OFInvalidArgumentException exception]; -#else - if (address1->length < (socklen_t)sizeof(struct sockaddr_in) || - address2->length < (socklen_t)sizeof(struct sockaddr_in)) - @throw [OFInvalidArgumentException exception]; -#endif - - addrIn1 = &address1->sockaddr.in; - addrIn2 = &address2->sockaddr.in; - - if (addrIn1->sin_port != addrIn2->sin_port) - return false; - if (addrIn1->sin_addr.s_addr != addrIn2->sin_addr.s_addr) - return false; - - break; - case OFSocketAddressFamilyIPv6: - if (address1->length < (socklen_t)sizeof(struct sockaddr_in6) || - address2->length < (socklen_t)sizeof(struct sockaddr_in6)) - @throw [OFInvalidArgumentException exception]; - - addrIn6_1 = &address1->sockaddr.in6; - addrIn6_2 = &address2->sockaddr.in6; - - if (addrIn6_1->sin6_port != addrIn6_2->sin6_port) - return false; - if (memcmp(addrIn6_1->sin6_addr.s6_addr, - addrIn6_2->sin6_addr.s6_addr, - sizeof(addrIn6_1->sin6_addr.s6_addr)) != 0) - return false; - - break; - case OFSocketAddressFamilyIPX: - if (address1->length < (socklen_t)sizeof(struct sockaddr_ipx) || - address2->length < (socklen_t)sizeof(struct sockaddr_ipx)) - @throw [OFInvalidArgumentException exception]; - - addrIPX1 = &address1->sockaddr.ipx; - addrIPX2 = &address2->sockaddr.ipx; - - if (addrIPX1->sipx_port != addrIPX2->sipx_port) - return false; - if (memcmp(&addrIPX1->sipx_network, &addrIPX2->sipx_network, - 4) != 0) - return false; - if (memcmp(addrIPX1->sipx_node, addrIPX2->sipx_node, - IPX_NODE_LEN) != 0) - return false; - - break; - default: - @throw [OFInvalidArgumentException exception]; - } - - return true; -} - -unsigned long -OFSocketAddressHash(const OFSocketAddress *address) -{ - unsigned long hash; - - OFHashInit(&hash); - OFHashAdd(&hash, address->family); - - switch (address->family) { - case OFSocketAddressFamilyIPv4: -#if defined(OF_WII) || defined(OF_NINTENDO_3DS) - if (address->length < 8) - @throw [OFInvalidArgumentException exception]; -#else - if (address->length < (socklen_t)sizeof(struct sockaddr_in)) - @throw [OFInvalidArgumentException exception]; -#endif - - OFHashAdd(&hash, address->sockaddr.in.sin_port >> 8); - OFHashAdd(&hash, address->sockaddr.in.sin_port); - OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 24); - OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 16); - OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 8); - OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr); - - break; - case OFSocketAddressFamilyIPv6: - if (address->length < (socklen_t)sizeof(struct sockaddr_in6)) - @throw [OFInvalidArgumentException exception]; - - OFHashAdd(&hash, address->sockaddr.in6.sin6_port >> 8); - OFHashAdd(&hash, address->sockaddr.in6.sin6_port); - - for (size_t i = 0; - i < sizeof(address->sockaddr.in6.sin6_addr.s6_addr); i++) - OFHashAdd(&hash, - address->sockaddr.in6.sin6_addr.s6_addr[i]); - - break; - case OFSocketAddressFamilyIPX:; - unsigned char network[ - sizeof(address->sockaddr.ipx.sipx_network)]; - - if (address->length < (socklen_t)sizeof(struct sockaddr_ipx)) - @throw [OFInvalidArgumentException exception]; - - OFHashAdd(&hash, address->sockaddr.ipx.sipx_port >> 8); - OFHashAdd(&hash, address->sockaddr.ipx.sipx_port); - - memcpy(network, &address->sockaddr.ipx.sipx_network, - sizeof(network)); - - for (size_t i = 0; i < sizeof(network); i++) - OFHashAdd(&hash, network[i]); - - for (size_t i = 0; i < IPX_NODE_LEN; i++) - OFHashAdd(&hash, address->sockaddr.ipx.sipx_node[i]); - - break; - default: - @throw [OFInvalidArgumentException exception]; - } - - OFHashFinalize(&hash); - - return hash; -} - -static OFString * -IPv4String(const OFSocketAddress *address) -{ - const struct sockaddr_in *addrIn = &address->sockaddr.in; - uint32_t addr = OFFromBigEndian32(addrIn->sin_addr.s_addr); - OFString *string; - - string = [OFString stringWithFormat: @"%u.%u.%u.%u", - (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, - (addr & 0x0000FF00) >> 8, addr & 0x000000FF]; - - return string; -} - -static OFString * -IPv6String(const OFSocketAddress *address) -{ - OFMutableString *string = [OFMutableString string]; - const struct sockaddr_in6 *addrIn6 = &address->sockaddr.in6; - int_fast8_t zerosStart = -1, maxZerosStart = -1; - uint_fast8_t zerosCount = 0, maxZerosCount = 0; - bool first = true; - - for (uint_fast8_t i = 0; i < 16; i += 2) { - if (addrIn6->sin6_addr.s6_addr[i] == 0 && - addrIn6->sin6_addr.s6_addr[i + 1] == 0) { - if (zerosStart >= 0) - zerosCount++; - else { - zerosStart = i; - zerosCount = 1; - } - } else { - if (zerosCount > maxZerosCount) { - maxZerosStart = zerosStart; - maxZerosCount = zerosCount; - } - - zerosStart = -1; - } - } - if (zerosCount > maxZerosCount) { - maxZerosStart = zerosStart; - maxZerosCount = zerosCount; - } - - if (maxZerosCount >= 2) { - for (int_fast8_t i = 0; i < maxZerosStart; i += 2) { - [string appendFormat: - (first ? @"%x" : @":%x"), - (addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i] << 8) | - addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i + 1]]; - first = false; - } - - [string appendString: @"::"]; - first = true; - - for (int_fast8_t i = maxZerosStart + (maxZerosCount * 2); - i < 16; i += 2) { - [string appendFormat: - (first ? @"%x" : @":%x"), - (addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i] << 8) | - addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i + 1]]; - first = false; - } - } else { - for (uint_fast8_t i = 0; i < 16; i += 2) { - [string appendFormat: - (first ? @"%x" : @":%x"), - (addrIn6->sin6_addr.s6_addr[i] << 8) | - addrIn6->sin6_addr.s6_addr[i + 1]]; - first = false; - } - } - - [string makeImmutable]; - - return string; -} - -OFString * -OFSocketAddressString(const OFSocketAddress *address) -{ - switch (address->family) { - case OFSocketAddressFamilyIPv4: - return IPv4String(address); - case OFSocketAddressFamilyIPv6: - return IPv6String(address); - default: - @throw [OFInvalidArgumentException exception]; - } -} - -void -OFSocketAddressSetPort(OFSocketAddress *address, uint16_t port) -{ - switch (address->family) { - case OFSocketAddressFamilyIPv4: - address->sockaddr.in.sin_port = OFToBigEndian16(port); - break; - case OFSocketAddressFamilyIPv6: - address->sockaddr.in6.sin6_port = OFToBigEndian16(port); - break; - case OFSocketAddressFamilyIPX: - address->sockaddr.ipx.sipx_port = OFToBigEndian16(port); - break; - default: - @throw [OFInvalidArgumentException exception]; - } -} - -uint16_t -OFSocketAddressPort(const OFSocketAddress *address) -{ - switch (address->family) { - case OFSocketAddressFamilyIPv4: - return OFFromBigEndian16(address->sockaddr.in.sin_port); - case OFSocketAddressFamilyIPv6: - return OFFromBigEndian16(address->sockaddr.in6.sin6_port); - case OFSocketAddressFamilyIPX: - return OFFromBigEndian16(address->sockaddr.ipx.sipx_port); - default: - @throw [OFInvalidArgumentException exception]; - } -} - -void -OFSocketAddressSetIPXNetwork(OFSocketAddress *address, uint32_t network) -{ - if (address->family != OFSocketAddressFamilyIPX) - @throw [OFInvalidArgumentException exception]; - - network = OFToBigEndian32(network); - memcpy(&address->sockaddr.ipx.sipx_network, &network, - sizeof(address->sockaddr.ipx.sipx_network)); -} - -uint32_t -OFSocketAddressIPXNetwork(const OFSocketAddress *address) -{ - uint32_t network; - - if (address->family != OFSocketAddressFamilyIPX) - @throw [OFInvalidArgumentException exception]; - - memcpy(&network, &address->sockaddr.ipx.sipx_network, sizeof(network)); - - return OFFromBigEndian32(network); -} - -void -OFSocketAddressSetIPXNode(OFSocketAddress *address, - const unsigned char node[IPX_NODE_LEN]) -{ - if (address->family != OFSocketAddressFamilyIPX) - @throw [OFInvalidArgumentException exception]; - - memcpy(address->sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); -} - -void -OFSocketAddressIPXNode(const OFSocketAddress *address, - unsigned char node[IPX_NODE_LEN]) -{ - if (address->family != OFSocketAddressFamilyIPX) - @throw [OFInvalidArgumentException exception]; - - memcpy(node, address->sockaddr.ipx.sipx_node, IPX_NODE_LEN); -} DELETED src/socket_helpers.h Index: src/socket_helpers.h ================================================================== --- src/socket_helpers.h +++ src/socket_helpers.h @@ -1,97 +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 "unistd_wrapper.h" - -#ifdef HAVE_ARPA_INET_H -# include -#endif -#ifdef HAVE_NETDB_H -# include -#endif - -#include "socket.h" - -#ifndef INVALID_SOCKET -# define INVALID_SOCKET -1 -#endif - -#ifndef INADDR_NONE -# define INADDR_NONE ((in_addr_t)-1) -#endif - -#ifndef SOMAXCONN -/* - * Use 16 as everything > 17 fails on Nintendo 3DS and 16 is a less arbitrary - * number than 17. - */ -# define SOMAXCONN 16 -#endif - -#ifndef SOCK_CLOEXEC -# define SOCK_CLOEXEC 0 -#endif - -#if defined(OF_AMIGAOS) -# ifdef OF_MORPHOS -# include -# else -# include -# endif -# include -# define closesocket(sock) CloseSocket(sock) -# define ioctlsocket(fd, req, arg) IoctlSocket(fd, req, arg) -# define hstrerror(err) "unknown (no hstrerror)" -# define SOCKET_ERROR -1 -# if defined(OF_HAVE_THREADS) && !defined(OF_MORPHOS) -# define SocketBase ((struct Library *)OFTLSKeyGet(of_socket_base_key)) -# ifdef OF_AMIGAOS4 -# define ISocket ((struct SocketIFace *)OFTLSKeyGet(of_socket_interface_key)) -# endif -# endif -# ifdef OF_MORPHOS -typedef uint32_t in_addr_t; -# endif -#elif !defined(OF_WINDOWS) && !defined(OF_WII) -# define closesocket(sock) close(sock) -#endif - -#ifdef OF_WII -# define accept(sock, addr, addrlen) net_accept(sock, addr, addrlen) -# define bind(sock, addr, addrlen) net_bind(sock, addr, addrlen) -# define closesocket(sock) net_close(sock) -# define connect(sock, addr, addrlen) \ - net_connect(sock, (struct sockaddr *)addr, addrlen) -# define fcntl(fd, cmd, flags) net_fcntl(fd, cmd, flags) -# define h_errno 0 -# define hstrerror(err) "unknown (no hstrerror)" -# define listen(sock, backlog) net_listen(sock, backlog) -# define poll(fds, nfds, timeout) net_poll(fds, nfds, timeout) -# define recv(sock, buf, len, flags) net_recv(sock, buf, len, flags) -# define recvfrom(sock, buf, len, flags, addr, addrlen) \ - net_recvfrom(sock, buf, len, flags, addr, addrlen) -# define select(nfds, readfds, writefds, errorfds, timeout) \ - net_select(nfds, readfds, writefds, errorfds, timeout) -# define send(sock, buf, len, flags) net_send(sock, buf, len, flags) -# define sendto(sock, buf, len, flags, addr, addrlen) \ - net_sendto(sock, buf, len, flags, (struct sockaddr *)(addr), addrlen) -# define setsockopt(sock, level, name, value, len) \ - net_setsockopt(sock, level, name, value, len) -# define socket(domain, type, proto) net_socket(domain, type, proto) -typedef u32 in_addr_t; -typedef u32 nfds_t; -#endif DELETED src/thread.h Index: src/thread.h ================================================================== --- src/thread.h +++ src/thread.h @@ -1,97 +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 "objfw-defs.h" - -#include "platform.h" - -#if !defined(OF_HAVE_THREADS) || \ - (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) -# error No threads available! -#endif - -#import "macros.h" - -#if defined(OF_HAVE_PTHREADS) -# include -typedef pthread_t OFPlainThread; -#elif defined(OF_WINDOWS) -# include -typedef HANDLE OFPlainThread; -#elif defined(OF_AMIGAOS) -# include -# include -typedef struct { - struct Task *task; - void (*function)(id); - id object; - struct SignalSemaphore semaphore; - struct Task *joinTask; - unsigned char joinSigBit; - bool detached, done; -} *OFPlainThread; -#endif - -typedef struct OFPlainThreadAttributes { - float priority; - size_t stackSize; -} OFPlainThreadAttributes; - -#if defined(OF_HAVE_PTHREADS) -static OF_INLINE OFPlainThread -OFCurrentPlainThread(void) -{ - return pthread_self(); -} - -static OF_INLINE bool -OFPlainThreadIsCurrent(OFPlainThread thread) -{ - return pthread_equal(thread, pthread_self()); -} -#elif defined(OF_WINDOWS) -static OF_INLINE OFPlainThread -OFCurrentPlainThread(void) -{ - return GetCurrentThread(); -} - -static OF_INLINE bool -OFPlainThreadIsCurrent(OFPlainThread thread) -{ - return (thread == GetCurrentThread()); -} -#elif defined(OF_AMIGAOS) -extern OFPlainThread OFCurrentPlainThread(void); - -static OF_INLINE bool -OFPlainThreadIsCurrent(OFPlainThread thread) -{ - return (thread->thread == FindTask(NULL)); -} -#endif - -#ifdef __cplusplus -extern "C" { -#endif -extern int OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr); -extern int OFPlainThreadNew(OFPlainThread *thread, const char *name, - void (*function)(id), id object, const OFPlainThreadAttributes *attr); -extern void OFSetThreadName(const char *name); -extern int OFPlainThreadJoin(OFPlainThread thread); -extern int OFPlainThreadDetach(OFPlainThread thread); -#ifdef __cplusplus -} -#endif DELETED src/thread.m Index: src/thread.m ================================================================== --- src/thread.m +++ src/thread.m @@ -1,26 +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 "platform.h" - -#if defined(OF_HAVE_PTHREADS) -# include "platform/posix/thread.m" -#elif defined(OF_WINDOWS) -# include "platform/windows/thread.m" -#elif defined(OF_AMIGAOS) -# include "platform/amiga/thread.m" -#endif DELETED src/tlskey.h Index: src/tlskey.h ================================================================== --- src/tlskey.h +++ src/tlskey.h @@ -1,102 +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 "objfw-defs.h" - -#include - -#include "platform.h" - -#if !defined(OF_HAVE_THREADS) || \ - (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) -# error No thread-local storage available! -#endif - -#import "macros.h" - -#if defined(OF_HAVE_PTHREADS) -# include -typedef pthread_key_t OFTLSKey; -#elif defined(OF_WINDOWS) -# include -typedef DWORD OFTLSKey; -#elif defined(OF_MORPHOS) -# include -typedef ULONG OFTLSKey; -#elif defined(OF_AMIGAOS) -typedef struct OFTLSKey { - struct objc_hashtable *table; - struct OFTLSKey *next, *previous; -} *OFTLSKey; -#endif - -#ifdef __cplusplus -extern "C" { -#endif -extern int OFTLSKeyNew(OFTLSKey *key); -extern int OFTLSKeyFree(OFTLSKey key); -#ifdef __cplusplus -} -#endif - -/* TLS keys are inlined for performance. */ - -#if defined(OF_HAVE_PTHREADS) -static OF_INLINE void * -OFTLSKeyGet(OFTLSKey key) -{ - return pthread_getspecific(key); -} - -static OF_INLINE int -OFTLSKeySet(OFTLSKey key, void *ptr) -{ - return pthread_setspecific(key, ptr); -} -#elif defined(OF_WINDOWS) -static OF_INLINE void * -OFTLSKeyGet(OFTLSKey key) -{ - return TlsGetValue(key); -} - -static OF_INLINE int -OFTLSKeySet(OFTLSKey key, void *ptr) -{ - return (TlsSetValue(key, ptr) ? 0 : EINVAL); -} -#elif defined(OF_MORPHOS) -static OF_INLINE void * -OFTLSKeyGet(OFTLSKey key) -{ - return (void *)TLSGetValue(key); -} - -static OF_INLINE int -OFTLSKeySet(OFTLSKey key, void *ptr) -{ - return (TLSSetValue(key, (APTR)ptr) ? 0 : EINVAL); -} -#elif defined(OF_AMIGAOS) -/* Those are too big too inline. */ -# ifdef __cplusplus -extern "C" { -# endif -extern void *OFTLSKeyGet(OFTLSKey key); -extern int OFTLSKeySet(OFTLSKey key, void *ptr); -# ifdef __cplusplus -} -# endif -#endif DELETED src/tlskey.m Index: src/tlskey.m ================================================================== --- src/tlskey.m +++ src/tlskey.m @@ -1,28 +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 "platform.h" - -#if defined(OF_HAVE_PTHREADS) -# include "platform/posix/tlskey.m" -#elif defined(OF_WINDOWS) -# include "platform/windows/tlskey.m" -#elif defined(OF_MORPHOS) -# include "platform/morphos/tlskey.m" -#elif defined(OF_AMIGAOS) -# include "platform/amiga/tlskey.m" -#endif Index: tests/OFDateTests.m ================================================================== --- tests/OFDateTests.m +++ tests/OFDateTests.m @@ -28,12 +28,12 @@ OFDate *d1, *d2; struct tm tm; int16_t tz; const char *dstr = "Wed, 09 Jun 2021 +0200x"; - TEST(@"of_strptime()", - of_strptime(dstr, "%a, %d %b %Y %z", &tm, &tz) == dstr + 22 && + TEST(@"OFStrPTime()", + OFStrPTime(dstr, "%a, %d %b %Y %z", &tm, &tz) == dstr + 22 && tm.tm_wday == 3 && tm.tm_mday == 9 && tm.tm_mon == 5 && tm.tm_year == 2021 - 1900 && tz == 2 * 60) TEST(@"+[dateWithTimeIntervalSince1970:]", (d1 = [OFDate dateWithTimeIntervalSince1970: 0]))