This is NSData.m in view mode; [Download] [Up]
/*
NSData.m
Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
All rights reserved.
Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
This file is part of libFoundation.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
We disclaim all warranties with regard to this software, including all
implied warranties of merchantability and fitness, in no event shall
we be liable for any special, indirect or consequential damages or any
damages whatsoever resulting from loss of use, data or profits, whether in
an action of contract, negligence or other tortious action, arising out of
or in connection with the use or performance of this software.
*/
#include <Foundation/common.h>
#include <Foundation/NSData.h>
#include <Foundation/NSString.h>
#include <Foundation/NSPosixFileDescriptor.h>
#include <Foundation/NSCoder.h>
#include <Foundation/NSException.h>
#include <Foundation/NSAutoreleasePool.h>
#include <Foundation/exceptions/GeneralExceptions.h>
#include <extensions/objc-runtime.h>
#include "byte_order.h"
#include "NSConcreteData.h"
@implementation NSData
+ (id)allocWithZone:(NSZone*)zone
{
return NSAllocateObject(((self == [NSData class]) ?
[NSConcreteData class] : self), 0, zone);
}
+ (id)data
{
return [[[self allocWithZone:NSDefaultMallocZone()]
initWithBytes:NULL length:0]
autorelease];
}
+ (id)dataWithBytes:(const void*)bytes
length:(unsigned int)length
{
return [[[self allocWithZone:NSDefaultMallocZone()]
initWithBytes:bytes length:length]
autorelease];
}
+ (id)dataWithBytesNoCopy:(void*)bytes
length:(unsigned int)length
{
return [[[self allocWithZone:NSDefaultMallocZone()]
initWithBytesNoCopy:bytes
length:length] autorelease];
}
+ (id)dataWithContentsOfFile:(NSString*)path
{
return [[[self allocWithZone:NSDefaultMallocZone()]
initWithContentsOfFile:path]
autorelease];
}
+ (id)dataWithContentsOfMappedFile:(NSString*)path
{
NSPosixFileDescriptor* descriptor;
NSRange range = {0, 0};
descriptor = [[[NSPosixFileDescriptor alloc]
initWithPath:path] autorelease];
range.length = [descriptor fileLength];
return [descriptor mapFileRange:range];
}
+ (id)dataWithData:(NSData*)aData
{
return [[[self alloc] initWithData:aData] autorelease];
}
- (id)initWithBytes:(const void*)bytes
length:(unsigned int)length
{
[self subclassResponsibility:_cmd];
return nil;
}
- (id)initWithBytesNoCopy:(void*)bytes
length:(unsigned int)length
{
[self subclassResponsibility:_cmd];
return nil;
}
- (id)initWithContentsOfFile:(NSString*)path
{
NSRange range = {0, 0};
char* content = NULL;
NSPosixFileDescriptor* descriptor = [[NSPosixFileDescriptor alloc]
initWithPath:path];
/* Take the address of range to force the compiler to do not allocate it
in registers */
(&range)->length = 0;
TRY {
range.length = [descriptor fileLength];
content = descriptor ? NSZoneMalloc([self zone], range.length) : NULL;
[descriptor readBytes:content range:range];
} END_TRY
OTHERWISE {
Free(content);
content = NULL;
descriptor = [descriptor self];
} END_CATCH
[descriptor release];
if (!content) {
[self autorelease];
return nil;
}
return [self initWithBytesNoCopy:content length:range.length];
}
- (id)initWithContentsOfMappedFile:(NSString*)path
{
NSPosixFileDescriptor* descriptor;
NSRange range = {0, 0};
descriptor = [[[NSPosixFileDescriptor alloc]
initWithPath:path] autorelease];
range.length = [descriptor fileLength];
[self release];
return [descriptor mapFileRange:range];
}
- (id)initWithData:(NSData*)data
{
return [self initWithBytes:[data bytes] length:[data length]];
}
- copy
{
return [self copyWithZone:NSDefaultMallocZone()];
}
- (id)copyWithZone:(NSZone*)zone
{
return [[NSData allocWithZone:zone] initWithData:self];
}
- mutableCopy
{
return [self mutableCopyWithZone:NSDefaultMallocZone()];
}
- (id)mutableCopyWithZone:(NSZone*)zone
{
return [[NSMutableData allocWithZone:zone] initWithData:self];
}
- (const void*)bytes
{
[self subclassResponsibility:_cmd];
return NULL;
}
- (NSString*)description
{
int i;
unsigned int length = [self length];
const char* bytes = [self bytes];
unsigned int final_length = 4 + 2 * length + 1 + length / 4;
char* description = Malloc(final_length);
char* temp = description + 1;
description[0] = 0;
Strcat(description, "<");
for(i = 0; i < length; i++, temp += 2) {
if (i % 4 == 0)
*temp++ = ' ';
sprintf (temp, "%02X", (unsigned char)((char*)bytes)[i]);
}
strcat(temp, " >");
*(temp += 2) = 0;
return [NSString stringWithCStringNoCopy:description freeWhenDone:YES];
}
- (void)getBytes:(void*)buffer
{
memcpy(buffer, [self bytes], [self length]);
}
- (void)getBytes:(void*)buffer
length:(unsigned int)_length
{
if(_length > [self length])
THROW([RangeException new]);
else memcpy(buffer, [self bytes], _length);
}
- (void)getBytes:(void*)buffer
range:(NSRange)aRange
{
unsigned int length = [self length];
if(aRange.location > length
|| aRange.length > length
|| aRange.location + aRange.length > length)
THROW([RangeException new]);
else memcpy(buffer, [self bytes] + aRange.location, aRange.length);
}
- (NSData*)subdataWithRange:(NSRange)aRange
{
return [[[NSConcreteDataRange allocWithZone:NSDefaultMallocZone()]
initWithData:self range:aRange] autorelease];
}
- (BOOL)isEqualToData:(NSData*)other
{
if([self length] == [other length])
return memcmp([self bytes], [other bytes], [self length]) == 0;
else return NO;
}
- (BOOL)isEqual:(id)anObject
{
if([anObject isKindOfClass:[NSData class]])
return [self isEqualToData:anObject];
else return NO;
}
- (unsigned int)length
{
[self subclassResponsibility:_cmd];
return 0;
}
- (BOOL)writeToFile:(NSString*)path
atomically:(BOOL)useAuxiliaryFile
{
return writeToFile(path, self, useAuxiliaryFile);
}
- (unsigned int)deserializeAlignedBytesLengthAtCursor:(unsigned int*)cursor
{
return *cursor;
}
- (void)deserializeBytes:(void*)buffer
length:(unsigned int)bytes
atCursor:(unsigned int*)cursor
{
NSRange range = { *cursor, bytes };
[self getBytes:buffer range:range];
*cursor += bytes;
}
- (void)deserializeDataAt:(void*)data
ofObjCType:(const char*)type
atCursor:(unsigned int*)cursor
context:(id <NSObjCTypeSerializationCallBack>)callback
{
if(!type || !data)
return;
switch(*type) {
case _C_ID: {
[callback deserializeObjectAt:data ofObjCType:type
fromData:self atCursor:cursor];
break;
}
case _C_CHARPTR: {
volatile int len = [self deserializeIntAtCursor:cursor];
id adr = nil;
/* This statement, by taking the address of `type', forces the
compiler to not allocate `type' into a register */
*(void**)data = &type;
if(len == -1) {
*(const char**)data = NULL;
return;
}
else {
*(char**)data = Malloc(len + 1);
/* Autorelease *data in case of exceptions */
adr = [NSAutoreleasedPointer autoreleasePointer:*(char**)data];
}
[self deserializeBytes:*(char**)data length:len atCursor:cursor];
/* Save the *data from destruction */
[adr retain];
break;
}
case _C_ARY_B: {
int i, count, offset, itemSize;
const char* itemType;
count = Atoi(type + 1);
itemType = type;
while(isdigit(*++itemType));
itemSize = objc_sizeof_type(itemType);
for(i = offset = 0; i < count; i++, offset += itemSize)
[self deserializeDataAt:(char*)data + offset
ofObjCType:itemType
atCursor:cursor
context:callback];
break;
}
case _C_STRUCT_B: {
int offset = 0;
int align, rem;
while(*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
while(1) {
[self deserializeDataAt:((char*)data) + offset
ofObjCType:type
atCursor:cursor
context:callback];
offset += objc_sizeof_type(type);
type = objc_skip_typespec(type);
if(*type != _C_STRUCT_E) {
align = objc_alignof_type(type);
if((rem = offset % align))
offset += align - rem;
}
else break;
}
break;
}
case _C_PTR: {
id addr;
*(char**)data = Malloc(objc_sizeof_type(++type));
/* Autorelease *data in case of exceptions */
addr = [NSAutoreleasedPointer autoreleasePointer:*(char**)data];
[self deserializeDataAt:*(char**)data
ofObjCType:type
atCursor:cursor
context:callback];
/* Save the *data from destruction */
[addr retain];
break;
}
case _C_CHR:
case _C_UCHR: {
[self deserializeBytes:data
length:sizeof(unsigned char)
atCursor:cursor];
break;
}
case _C_SHT:
case _C_USHT: {
unsigned short ns;
[self deserializeBytes:&ns
length:sizeof(unsigned short)
atCursor:cursor];
*(unsigned short*)data = network_short_to_host (ns);
break;
}
case _C_INT:
case _C_UINT: {
unsigned int ni;
[self deserializeBytes:&ni
length:sizeof(unsigned int)
atCursor:cursor];
*(unsigned int*)data = network_int_to_host (ni);
break;
}
case _C_LNG:
case _C_ULNG: {
unsigned int nl;
[self deserializeBytes:&nl
length:sizeof(unsigned long)
atCursor:cursor];
*(unsigned long*)data = network_long_to_host (nl);
break;
}
case _C_FLT: {
network_float nf;
[self deserializeBytes:&nf
length:sizeof(float)
atCursor:cursor];
*(float*)data = network_float_to_host (nf);
break;
}
case _C_DBL: {
network_double nd;
[self deserializeBytes:&nd
length:sizeof(double)
atCursor:cursor];
*(double*)data = network_double_to_host (nd);
break;
}
default:
THROW([[UnknownTypeException alloc] initForType:type]);
}
}
- (int)deserializeIntAtCursor:(unsigned int*)cursor
{
unsigned int ni, result;
[self deserializeBytes:&ni length:sizeof(unsigned int) atCursor:cursor];
result = network_int_to_host (ni);
return result;
}
- (int)deserializeIntAtIndex:(unsigned int)index
{
unsigned int ni, result;
[self deserializeBytes:&ni length:sizeof(unsigned int) atCursor:&index];
result = network_int_to_host (ni);
return result;
}
- (void)deserializeInts:(int*)intBuffer
count:(unsigned int)numInts
atCursor:(unsigned int*)cursor
{
int i;
[self deserializeBytes:&intBuffer
length:numInts * sizeof(unsigned int)
atCursor:cursor];
for (i = 0; i < numInts; i++)
intBuffer[i] = network_int_to_host (intBuffer[i]);
}
- (void)deserializeInts:(int*)intBuffer
count:(unsigned int)numInts
atIndex:(unsigned int)index
{
int i;
[self deserializeBytes:&intBuffer
length:numInts * sizeof(int)
atCursor:&index];
for (i = 0; i < numInts; i++)
intBuffer[i] = network_int_to_host (intBuffer[i]);
}
- (Class)classForCoder
{
return [NSData class];
}
- (void)encodeWithCoder:(NSCoder*)aCoder
{
const char* bytes = [self bytes];
unsigned int length = [self length];
[aCoder encodeValueOfObjCType:@encode(unsigned int) at:&length];
[aCoder encodeArrayOfObjCType:@encode(char) count:length at:&bytes];
}
- (id)initWithCoder:(NSCoder*)aDecoder
{
char* bytes;
unsigned int length;
[aDecoder decodeValueOfObjCType:@encode(unsigned int) at:&length];
bytes = Malloc (length);
[aDecoder decodeArrayOfObjCType:@encode(char) count:length at:bytes];
[self initWithBytesNoCopy:bytes length:length];
return self;
}
@end /* NSData */
@implementation NSMutableData
+ (id)allocWithZone:(NSZone*)zone
{
return NSAllocateObject(((self == [NSMutableData class]) ?
[NSConcreteMutableData class] : self), 0, zone);
}
+ (id)dataWithCapacity:(unsigned int)numBytes
{
return [[[self allocWithZone:NSDefaultMallocZone()]
initWithCapacity:numBytes]
autorelease];
}
+ (id)dataWithLength:(unsigned int)length
{
return [[[self allocWithZone:NSDefaultMallocZone()]
initWithLength:length]
autorelease];
}
- (id)initWithCapacity:(unsigned int)capacity
{
[self subclassResponsibility:_cmd];
return nil;
}
- (id)initWithLength:(unsigned int)length
{
[self subclassResponsibility:_cmd];
return nil;
}
- (NSData*)subdataWithRange:(NSRange)aRange
{
char* buffer = Malloc(aRange.length);
[self getBytes:buffer range:aRange];
return [[NSData alloc] initWithBytesNoCopy:buffer
length:aRange.length];
}
- (void)increaseLengthBy:(unsigned int)extraLength
{
[self subclassResponsibility:_cmd];
}
- (void*)mutableBytes
{
[self subclassResponsibility:_cmd];
return NULL;
}
- (void)setLength:(unsigned int)length
{
[self subclassResponsibility:_cmd];
}
- (void)appendBytes:(const void*)_bytes
length:(unsigned int)_length
{
[self subclassResponsibility:_cmd];
}
- (void)appendData:(NSData*)other
{
[self appendBytes:[other bytes] length:[other length]];
}
- (void)replaceBytesInRange:(NSRange)aRange
withBytes:(const void*)bytes
{
unsigned int length = [self length];
if(aRange.location > length
|| aRange.length > length
|| aRange.location + aRange.length > length)
THROW([RangeException new]);
else {
char* mBytes = [self mutableBytes];
memcpy(mBytes + aRange.location, bytes, aRange.length);
}
}
- (void)setData:(NSData*)aData
{
[self setLength:[aData length]];
[self replaceBytesInRange:NSMakeRange(0, [self length])
withBytes:[aData bytes]];
}
- (void)resetBytesInRange:(NSRange)aRange
{
unsigned int length = [self length];
if(aRange.location > length
|| aRange.length > length
|| aRange.location + aRange.length > length)
THROW([RangeException new]);
else {
char* mBytes = [self mutableBytes];
memset(mBytes + aRange.location, 0, aRange.length);
}
}
- (void)serializeAlignedBytesLength:(unsigned int)length
{
}
- (void)serializeDataAt:(const void*)data
ofObjCType:(const char*)type
context:(id <NSObjCTypeSerializationCallBack>)callback
{
if(!data || !type)
return;
switch(*type) {
case _C_ID: {
[callback serializeObjectAt:(id*)data
ofObjCType:type
intoData:self];
break;
}
case _C_CHARPTR: {
int len;
if(!*(void**)data) {
[self serializeInt:-1];
return;
}
len = Strlen(*(void**)data);
[self serializeInt:len];
[self appendBytes:*(void**)data length:len];
break;
}
case _C_ARY_B: {
int i, offset, itemSize, count = Atoi(type + 1);
const char* itemType = type;
while(isdigit(*++itemType));
itemSize = objc_sizeof_type(itemType);
for(i = offset = 0; i < count; i++, offset += itemSize)
[self serializeDataAt:(char*)data + offset
ofObjCType:itemType
context:callback];
break;
}
case _C_STRUCT_B: {
int offset = 0;
int align, rem;
while(*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
while(1) {
[self serializeDataAt:((char*)data) + offset
ofObjCType:type
context:callback];
offset += objc_sizeof_type(type);
type = objc_skip_typespec(type);
if(*type != _C_STRUCT_E) {
align = objc_alignof_type(type);
if((rem = offset % align))
offset += align - rem;
}
else break;
}
break;
}
case _C_PTR:
[self serializeDataAt:*(char**)data
ofObjCType:++type context:callback];
break;
case _C_CHR:
case _C_UCHR:
[self appendBytes:data length:sizeof(unsigned char)];
break;
case _C_SHT:
case _C_USHT: {
unsigned short ns = host_short_to_network (*(unsigned short*)data);
[self appendBytes:&ns length:sizeof(unsigned short)];
break;
}
case _C_INT:
case _C_UINT: {
unsigned int ni = host_int_to_network (*(unsigned int*)data);
[self appendBytes:&ni length:sizeof(unsigned int)];
break;
}
case _C_LNG:
case _C_ULNG: {
unsigned long nl = host_long_to_network (*(unsigned long*)data);
[self appendBytes:&nl length:sizeof(unsigned long)];
break;
}
case _C_FLT: {
network_float nf = host_float_to_network (*(float*)data);
[self appendBytes:&nf length:sizeof(float)];
break;
}
case _C_DBL: {
network_double nd = host_double_to_network (*(double*)data);
[self appendBytes:&nd length:sizeof(double)];
break;
}
default:
THROW([[UnknownTypeException alloc] initForType:type]);
}
}
- (void)serializeInt:(int)value
{
unsigned int ni = host_int_to_network (value);
[self appendBytes:&ni length:sizeof(unsigned int)];
}
- (void)serializeInt:(int)value atIndex:(unsigned int)index
{
unsigned int ni = host_int_to_network (value);
NSRange range = { index, sizeof(int) };
[self replaceBytesInRange:range withBytes:&ni];
}
- (void)serializeInts:(int*)intBuffer count:(unsigned int)numInts
{
int i;
SEL selector = @selector (serializeInt:);
IMP imp = [self methodForSelector:selector];
for (i = 0; i < numInts; i++)
(*imp)(self, selector, intBuffer[i]);
}
- (void)serializeInts:(int*)intBuffer
count:(unsigned int)numInts
atIndex:(unsigned int)index
{
int i;
SEL selector = @selector (serializeInt:atIndex:);
IMP imp = [self methodForSelector:selector];
for (i = 0; i < numInts; i++)
(*imp)(self, selector, intBuffer[i], index++);
}
- (Class)classForCoder
{
return [NSMutableData class];
}
@end /* NSMutableData */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.