Artifact d222b0db89e5aa3ffeff38a051c5176f9e519da55eba0ccd717e1152c4221dd9:
- File
src/OFDataArray.m
— part of check-in
[3d16a30f41]
at
2013-06-22 12:12:36
on branch trunk
— Rework exceptions.
This mostly removes the argument for the class in which the exception
occurred. As backtraces were recently added for all platforms, the
passed class does not give any extra information on where the exception
occurred anymore.This also removes a few other arguments which were not too helpful. In
the past, the idea was to pass as many arguments as possible so that it
is easier to find the origin of the exception. However, as backtraces
are a much better way to find the origin, those are not useful anymore
and just make the exception more cumbersome to use. The rule is now to
only pass arguments that might help in recovering from the exception or
provide information that is otherwise not easily accessible. (user: js, size: 17510) [annotate] [blame] [check-ins using]
/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 * Jonathan Schleifer <js@webkeks.org> * * 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 <stdio.h> #include <string.h> #include <limits.h> #import "OFDataArray.h" #import "OFString.h" #import "OFFile.h" #import "OFURL.h" #ifdef OF_HAVE_SOCKETS # import "OFHTTPClient.h" # import "OFHTTPRequest.h" # import "OFHTTPRequestReply.h" #endif #import "OFDictionary.h" #import "OFXMLElement.h" #import "OFSystemInfo.h" #ifdef OF_HAVE_SOCKETS # import "OFHTTPRequestFailedException.h" #endif #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" #import "autorelease.h" #import "base64.h" #import "macros.h" /* References for static linking */ void _references_to_categories_of_OFDataArray(void) { _OFDataArray_MessagePackValue_reference = 1; _OFDataArray_Hashing_reference = 1; } @implementation OFDataArray + (instancetype)dataArray { return [[[self alloc] init] autorelease]; } + (instancetype)dataArrayWithItemSize: (size_t)itemSize { return [[[self alloc] initWithItemSize: itemSize] autorelease]; } + (instancetype)dataArrayWithCapacity: (size_t)capacity { return [[[self alloc] initWithCapacity: capacity] autorelease]; } + (instancetype)dataArrayWithItemSize: (size_t)itemSize capacity: (size_t)capacity { return [[[self alloc] initWithItemSize: itemSize capacity: capacity] autorelease]; } + (instancetype)dataArrayWithContentsOfFile: (OFString*)path { return [[[self alloc] initWithContentsOfFile: path] autorelease]; } + (instancetype)dataArrayWithContentsOfURL: (OFURL*)URL { return [[[self alloc] initWithContentsOfURL: URL] autorelease]; } + (instancetype)dataArrayWithStringRepresentation: (OFString*)string { return [[[self alloc] initWithStringRepresentation: string] autorelease]; } + (instancetype)dataArrayWithBase64EncodedString: (OFString*)string { return [[[self alloc] initWithBase64EncodedString: string] autorelease]; } - init { return [self initWithItemSize: 1 capacity: 0]; } - initWithItemSize: (size_t)itemSize { return [self initWithItemSize: itemSize capacity: 0]; } - initWithCapacity: (size_t)capacity { return [self initWithItemSize: 1 capacity: capacity]; } - initWithItemSize: (size_t)itemSize capacity: (size_t)capacity { self = [super init]; if (itemSize == 0) { [self release]; @throw [OFInvalidArgumentException exception]; } _items = [self allocMemoryWithSize: itemSize count: capacity]; _itemSize = itemSize; _capacity = capacity; return self; } - initWithContentsOfFile: (OFString*)path { @try { OFFile *file = [[OFFile alloc] initWithPath: path mode: @"rb"]; off_t size = [OFFile sizeOfFileAtPath: path]; if (size > SIZE_MAX) @throw [OFOutOfRangeException exception]; self = [self initWithItemSize: 1 capacity: (size_t)size]; @try { size_t pageSize = [OFSystemInfo pageSize]; char *buffer = [self allocMemoryWithSize: pageSize]; while (![file isAtEndOfStream]) { size_t length; length = [file readIntoBuffer: buffer length: pageSize]; [self addItems: buffer count: length]; } [self freeMemory: buffer]; } @finally { [file release]; } } @catch (id e) { [self release]; @throw e; } return self; } - initWithContentsOfURL: (OFURL*)URL { void *pool; #ifdef OF_HAVE_SOCKETS OFHTTPClient *client; OFHTTPRequest *request; OFHTTPRequestReply *reply; OFDictionary *headers; OFString *contentLength; #endif Class c; c = [self class]; [self release]; pool = objc_autoreleasePoolPush(); #ifdef OF_HAVE_SOCKETS if ([[URL scheme] isEqual: @"file"]) { self = [[c alloc] initWithContentsOfFile: [URL path]]; objc_autoreleasePoolPop(pool); return self; } client = [OFHTTPClient client]; request = [OFHTTPRequest requestWithURL: URL]; reply = [client performRequest: request]; if ([reply statusCode] != 200) @throw [OFHTTPRequestFailedException exceptionWithRequest: request reply: reply]; /* * TODO: This can be optimized by allocating a data array with the * capacity from the Content-Length header. */ self = [[reply readDataArrayTillEndOfStream] retain]; headers = [reply headers]; if ((contentLength = [headers objectForKey: @"Content-Length"]) != nil) if ([self count] != (size_t)[contentLength decimalValue]) @throw [OFTruncatedDataException exception]; #else @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; #endif objc_autoreleasePoolPop(pool); return self; } - initWithStringRepresentation: (OFString*)string { self = [super init]; @try { const char *cString; size_t i; _itemSize = 1; _count = [string cStringLengthWithEncoding: OF_STRING_ENCODING_ASCII]; if (_count % 2 != 0) @throw [OFInvalidFormatException exception]; _count /= 2; cString = [string cStringWithEncoding: OF_STRING_ENCODING_ASCII]; _items = [self allocMemoryWithSize: _count]; for (i = 0; i < _count; i++) { uint8_t c1 = cString[2 * i]; uint8_t c2 = cString[2 * i + 1]; uint8_t byte; if (c1 >= '0' && c1 <= '9') byte = (c1 - '0') << 4; else if (c1 >= 'a' && c1 <= 'f') byte = (c1 - 'a' + 10) << 4; else if (c1 >= 'A' && c1 <= 'F') byte = (c1 - 'A' + 10) << 4; else @throw [OFInvalidFormatException exception]; if (c2 >= '0' && c2 <= '9') byte |= c2 - '0'; else if (c2 >= 'a' && c2 <= 'f') byte |= c2 - 'a' + 10; else if (c2 >= 'A' && c2 <= 'F') byte |= c2 - 'A' + 10; else @throw [OFInvalidFormatException exception]; _items[i] = byte; } } @catch (id e) { [self release]; @throw e; } return self; } - initWithBase64EncodedString: (OFString*)string { self = [self initWithItemSize: 1 capacity: [string length] / 3]; @try { if (!of_base64_decode(self, [string cStringWithEncoding: OF_STRING_ENCODING_ASCII], [string cStringLengthWithEncoding: OF_STRING_ENCODING_ASCII])) @throw [OFInvalidFormatException exception]; } @catch (id e) { [self release]; @throw e; } return self; } - initWithSerialization: (OFXMLElement*)element { @try { void *pool = objc_autoreleasePoolPush(); OFString *stringValue; if (![[element name] isEqual: [self className]] || ![[element namespace] isEqual: OF_SERIALIZATION_NS]) @throw [OFInvalidArgumentException exception]; stringValue = [element stringValue]; self = [self initWithBase64EncodedString: stringValue]; objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; } return self; } - (size_t)count { return _count; } - (size_t)itemSize { return _itemSize; } - (void*)items { return _items; } - (void*)itemAtIndex: (size_t)index { if (index >= _count) @throw [OFOutOfRangeException exception]; return _items + index * _itemSize; } - (void*)firstItem { if (_items == NULL || _count == 0) return NULL; return _items; } - (void*)lastItem { if (_items == NULL || _count == 0) return NULL; return _items + (_count - 1) * _itemSize; } - (void)addItem: (const void*)item { if (SIZE_MAX - _count < 1) @throw [OFOutOfRangeException exception]; if (_count + 1 > _capacity) { _items = [self resizeMemory: _items size: _itemSize count: _count + 1]; _capacity = _count + 1; } memcpy(_items + _count * _itemSize, item, _itemSize); _count++; } - (void)insertItem: (const void*)item atIndex: (size_t)index { [self insertItems: item atIndex: index count: 1]; } - (void)addItems: (const void*)items count: (size_t)count { if (count > SIZE_MAX - count) @throw [OFOutOfRangeException exception]; if (_count + count > _capacity) { _items = [self resizeMemory: _items size: _itemSize count: _count + count]; _capacity = _count + count; } memcpy(_items + _count * _itemSize, items, count * _itemSize); _count += count; } - (void)insertItems: (const void*)items atIndex: (size_t)index count: (size_t)count { if (count > SIZE_MAX - _count || index > _count) @throw [OFOutOfRangeException exception]; if (_count + count > _capacity) { _items = [self resizeMemory: _items size: _itemSize count: _count + count]; _capacity = _count + count; } memmove(_items + (index + count) * _itemSize, _items + index * _itemSize, (_count - index) * _itemSize); memcpy(_items + index * _itemSize, items, count * _itemSize); _count += count; } - (void)removeItemAtIndex: (size_t)index { [self removeItemsInRange: of_range(index, 1)]; } - (void)removeItemsInRange: (of_range_t)range { if (range.length > SIZE_MAX - range.location || range.location + range.length > _count) @throw [OFOutOfRangeException exception]; memmove(_items + range.location * _itemSize, _items + (range.location + range.length) * _itemSize, (_count - range.location - range.length) * _itemSize); _count -= range.length; @try { _items = [self resizeMemory: _items size: _itemSize count: _count]; _capacity = _count; } @catch (OFOutOfMemoryException *e) { /* We don't really care, as we only made it smaller */ } } - (void)removeLastItem { if (_count == 0) return; _count--; @try { _items = [self resizeMemory: _items size: _itemSize count: _count]; _capacity = _count; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only made it smaller */ } } - (void)removeAllItems { [self freeMemory: _items]; _items = NULL; _count = 0; _capacity = 0; } - copy { OFDataArray *copy = [[[self class] alloc] initWithItemSize: _itemSize capacity: _count]; [copy addItems: _items count: _count]; return copy; } - (bool)isEqual: (id)object { OFDataArray *dataArray; if (![object isKindOfClass: [OFDataArray class]]) return false; dataArray = object; if ([dataArray count] != _count || [dataArray itemSize] != _itemSize) return false; if (memcmp([dataArray items], _items, _count * _itemSize)) return false; return true; } - (of_comparison_result_t)compare: (id <OFComparing>)object { OFDataArray *dataArray; int comparison; size_t count, minCount; if (![object isKindOfClass: [OFDataArray class]]) @throw [OFInvalidArgumentException exception]; dataArray = (OFDataArray*)object; if ([dataArray itemSize] != _itemSize) @throw [OFInvalidArgumentException exception]; count = [dataArray count]; minCount = (_count > count ? count : _count); if ((comparison = memcmp(_items, [dataArray items], minCount * _itemSize)) == 0) { if (_count > count) return OF_ORDERED_DESCENDING; if (_count < count) return OF_ORDERED_ASCENDING; return OF_ORDERED_SAME; } if (comparison > 0) return OF_ORDERED_DESCENDING; else return OF_ORDERED_ASCENDING; } - (uint32_t)hash { uint32_t hash; size_t i; OF_HASH_INIT(hash); for (i = 0; i < _count * _itemSize; i++) OF_HASH_ADD(hash, ((uint8_t*)_items)[i]); OF_HASH_FINALIZE(hash); return hash; } - (OFString*)description { OFMutableString *ret = [OFMutableString stringWithString: @"<"]; size_t i; for (i = 0; i < _count; i++) { size_t j; if (i > 0) [ret appendString: @" "]; for (j = 0; j < _itemSize; j++) [ret appendFormat: @"%02x", _items[i * _itemSize + j]]; } [ret appendString: @">"]; [ret makeImmutable]; return ret; } - (OFString*)stringRepresentation { OFMutableString *ret = [OFMutableString string]; size_t i, j; for (i = 0; i < _count; i++) for (j = 0; j < _itemSize; j++) [ret appendFormat: @"%02x", _items[i * _itemSize + j]]; [ret makeImmutable]; return ret; } - (OFString*)stringByBase64Encoding { return of_base64_encode(_items, _count * _itemSize); } - (void)writeToFile: (OFString*)path { OFFile *file = [[OFFile alloc] initWithPath: path mode: @"wb"]; @try { [file writeBuffer: _items length: _count * _itemSize]; } @finally { [file release]; } } - (OFXMLElement*)XMLElementBySerializing { void *pool; OFXMLElement *element; if (_itemSize != 1) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); element = [OFXMLElement elementWithName: [self className] namespace: OF_SERIALIZATION_NS stringValue: of_base64_encode(_items, _count * _itemSize)]; [element retain]; objc_autoreleasePoolPop(pool); return [element autorelease]; } - (OFDataArray*)messagePackRepresentation { OFDataArray *data; if (_itemSize != 1) @throw [OFInvalidArgumentException exception]; if (_count <= UINT8_MAX) { uint8_t type = 0xC4; uint8_t tmp = (uint8_t)_count; data = [OFDataArray dataArrayWithItemSize: 1 capacity: _count + 2]; [data addItem: &type]; [data addItem: &tmp]; } else if (_count <= UINT16_MAX) { uint8_t type = 0xC5; uint16_t tmp = OF_BSWAP16_IF_LE((uint16_t)_count); data = [OFDataArray dataArrayWithItemSize: 1 capacity: _count + 3]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else if (_count <= UINT32_MAX) { uint8_t type = 0xC6; uint32_t tmp = OF_BSWAP32_IF_LE((uint32_t)_count); data = [OFDataArray dataArrayWithItemSize: 1 capacity: _count + 5]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; [data addItems: _items count: _count]; return data; } @end @implementation OFBigDataArray - initWithItemSize: (size_t)itemSize capacity: (size_t)capacity { size_t lastPageByte = [OFSystemInfo pageSize] - 1; capacity = (capacity * itemSize + lastPageByte) & ~lastPageByte; return [super initWithItemSize: itemSize capacity: capacity]; } - (void)addItem: (const void*)item { size_t size, lastPageByte; if (SIZE_MAX - _count < 1 || _count + 1 > SIZE_MAX / _itemSize) @throw [OFOutOfRangeException exception]; lastPageByte = [OFSystemInfo pageSize] - 1; size = ((_count + 1) * _itemSize + lastPageByte) & ~lastPageByte; if (size > _capacity) { _items = [self resizeMemory: _items size: size]; _capacity = size; } memcpy(_items + _count * _itemSize, item, _itemSize); _count++; _size = size; } - (void)addItems: (const void*)items count: (size_t)count { size_t size, lastPageByte; if (count > SIZE_MAX - _count || _count + count > SIZE_MAX / _itemSize) @throw [OFOutOfRangeException exception]; lastPageByte = [OFSystemInfo pageSize] - 1; size = ((_count + count) * _itemSize + lastPageByte) & ~lastPageByte; if (size > _capacity) { _items = [self resizeMemory: _items size: size]; _capacity = size; } memcpy(_items + _count * _itemSize, items, count * _itemSize); _count += count; _size = size; } - (void)insertItems: (const void*)items atIndex: (size_t)index count: (size_t)count { size_t size, lastPageByte; if (count > SIZE_MAX - _count || index > _count || _count + count > SIZE_MAX / _itemSize) @throw [OFOutOfRangeException exception]; lastPageByte = [OFSystemInfo pageSize] - 1; size = ((_count + count) * _itemSize + lastPageByte) & ~lastPageByte; if (size > _capacity) { _items = [self resizeMemory: _items size: size]; _capacity = size; } memmove(_items + (index + count) * _itemSize, _items + index * _itemSize, (_count - index) * _itemSize); memcpy(_items + index * _itemSize, items, count * _itemSize); _count += count; _size = size; } - (void)removeItemsInRange: (of_range_t)range { size_t pageSize, size; if (range.length > SIZE_MAX - range.location || range.location + range.length > _count) @throw [OFOutOfRangeException exception]; memmove(_items + range.location * _itemSize, _items + (range.location + range.length) * _itemSize, (_count - range.location - range.length) * _itemSize); _count -= range.length; pageSize = [OFSystemInfo pageSize]; size = (_count * _itemSize + pageSize - 1) & ~(pageSize - 1); if (_size != size && size >= pageSize) { @try { _items = [self resizeMemory: _items size: size]; _capacity = size; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only made it smaller */ } _size = size; } } - (void)removeLastItem { size_t pageSize, size; if (_count == 0) return; _count--; pageSize = [OFSystemInfo pageSize]; size = (_count * _itemSize + pageSize - 1) & ~(pageSize - 1); if (_size != size && size >= pageSize) { @try { _items = [self resizeMemory: _items size: size]; _capacity = size; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only made it smaller */ } _size = size; } } - (void)removeAllItems { size_t pageSize = [OFSystemInfo pageSize]; @try { _items = [self resizeMemory: _items size: pageSize]; _capacity = pageSize; _size = pageSize; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only made it smaller */ } _count = 0; } @end