@@ -903,18 +903,18 @@ encoding: (of_string_encoding_t)encoding { @try { if ([data itemSize] != 1) @throw [OFInvalidArgumentException exception]; - - self = [self initWithCString: [data items] - encoding: encoding - length: [data count]]; } @catch (id e) { [self release]; @throw e; } + + self = [self initWithCString: [data items] + encoding: encoding + length: [data count]]; return self; } - (instancetype)initWithString: (OFString *)string @@ -1020,11 +1020,11 @@ char *tmp; uintmax_t fileSize; @try { void *pool = objc_autoreleasePoolPush(); - OFFile *file; + OFFile *file = nil; @try { fileSize = [[[OFFileManager defaultManager] attributesOfItemAtPath: path] fileSize]; } @catch (OFRetrieveItemAttributesFailedException *e) { @@ -1039,30 +1039,53 @@ # if UINTMAX_MAX > SIZE_MAX if (fileSize > SIZE_MAX) @throw [OFOutOfRangeException exception]; #endif - file = [[OFFile alloc] initWithPath: path - mode: @"r"]; + /* + * We need one extra byte for the terminating zero if we want + * to use -[initWithUTF8StringNoCopy:length:freeWhenDone:]. + */ + if (SIZE_MAX - (size_t)fileSize < 1) + @throw [OFOutOfRangeException exception]; + + if ((tmp = malloc((size_t)fileSize + 1)) == NULL) + @throw [OFOutOfMemoryException + exceptionWithRequestedSize: (size_t)fileSize]; @try { - tmp = [self allocMemoryWithSize: (size_t)fileSize]; + file = [[OFFile alloc] initWithPath: path + mode: @"r"]; [file readIntoBuffer: tmp exactLength: (size_t)fileSize]; + } @catch (id e) { + free(tmp); + @throw e; } @finally { [file release]; } + + tmp[(size_t)fileSize] = '\0'; } @catch (id e) { [self release]; @throw e; } - self = [self initWithCString: tmp - encoding: encoding - length: (size_t)fileSize]; - [self freeMemory: tmp]; + if (encoding == OF_STRING_ENCODING_UTF_8) + self = [self initWithUTF8StringNoCopy: tmp + length: (size_t)fileSize + freeWhenDone: true]; + else { + @try { + self = [self initWithCString: tmp + encoding: encoding + length: (size_t)fileSize]; + } @finally { + free(tmp); + } + } return self; } #endif @@ -1073,32 +1096,35 @@ } - (instancetype)initWithContentsOfURL: (OFURL *)URL encoding: (of_string_encoding_t)encoding { + void *pool = objc_autoreleasePoolPush(); + OFData *data; + @try { - void *pool = objc_autoreleasePoolPush(); - OFData *data = [OFData dataWithContentsOfURL: URL]; - - self = [self initWithCString: [data items] - encoding: encoding - length: [data count]]; - - objc_autoreleasePoolPop(pool); + data = [OFData dataWithContentsOfURL: URL]; } @catch (id e) { [self release]; @throw e; } + + self = [self initWithCString: [data items] + encoding: encoding + length: [data count]]; + + objc_autoreleasePoolPop(pool); return self; } - (instancetype)initWithSerialization: (OFXMLElement *)element { + void *pool = objc_autoreleasePoolPush(); + OFString *stringValue; + @try { - void *pool = objc_autoreleasePoolPush(); - if (![[element namespace] isEqual: OF_SERIALIZATION_NS]) @throw [OFInvalidArgumentException exception]; if ([self isKindOfClass: [OFMutableString class]]) { if (![[element name] isEqual: @"OFMutableString"]) @@ -1106,17 +1132,19 @@ } else { if (![[element name] isEqual: @"OFString"]) @throw [OFInvalidArgumentException exception]; } - self = [self initWithString: [element stringValue]]; - - objc_autoreleasePoolPop(pool); + stringValue = [element stringValue]; } @catch (id e) { [self release]; @throw e; } + + self = [self initWithString: stringValue]; + + objc_autoreleasePoolPop(pool); return self; } - (size_t)of_getCString: (char *)cString