Working With Mutable Binary Data

This article contains code examples of common tasks that apply specifically to mutable data objects, NSMutableData objects. Basically, you can change the bytes in a mutable binary data object by getting the byte array to modify directly, appending bytes to them, or replacing a range of bytes.

Modifying Bytes

The two NSMutableData primitive methods—mutableBytes and setLength:—provide the basis for all other methods in the class. The mutableBytes method returns a pointer for writing into the bytes contained in the mutable data object. The setLength: method allows you to truncate or extend the length of a mutable data object. The increaseLengthBy: method also allows you to change the length of a mutable data object.

In Listing 1, mutableBytes is used to return a pointer to the bytes in data2. The bytes in data2 are then overwritten with the contents of data1.

Listing 1  Modifying bytes

NSMutableData *data1, *data2;
NSString *myString = @"string for data1";
NSString *yourString = @"string for data2";
const char *utfMyString = [myString UTF8String];
const char *utfYourString = [yourString UTF8String];
unsigned char *firstBuffer, secondBuffer[20];
/* initialize data1, data2, and secondBuffer... */
data1 = [NSMutableData dataWithBytes:utfMyString length:strlen(utfMyString)+1];
data2 = [NSMutableData dataWithBytes:utfYourString length:strlen(utfYourString)+1];
[data2 getBytes:secondBuffer length:20];
NSLog(@"data2 before: \"%s\"\n", (char *)secondBuffer);
firstBuffer = [data2 mutableBytes];
[data1 getBytes:firstBuffer length:[data2 length]];
NSLog(@"data1: \"%s\"\n", (char *)firstBuffer);
[data2 getBytes:secondBuffer length:20];
NSLog(@"data2 after: \"%s\"\n", (char *)secondBuffer);

This is the output from Listing 1:

Oct  3 15:59:51 [1113] data2 before: "string for data2"
Oct  3 15:59:51 [1113] data1: "string for data1"
Oct  3 15:59:51 [1113] data2 after: "string for data1"

Appending Bytes

The appendBytes:length: and appendData: methods let you append bytes or the contents of another data object to a mutable data object. For example, Listing 2 copies the bytes in data2 into aBuffer, and then appends aBuffer to data1:

Listing 2  Appending bytes

NSMutableData *data1, *data2;
NSString *firstString  = @"ABCD";
NSString *secondString = @"EFGH";
const char *utfFirstString = [firstString UTF8String];
const char *utfSecondString = [secondString UTF8String];
unsigned char *aBuffer;
unsigned len;
data1 = [NSMutableData dataWithBytes:utfFirstString length:strlen(utfFirstString)];
data2 = [NSMutableData dataWithBytes:utfSecondString length:strlen(utfSecondString)];
len = [data2 length];
aBuffer = malloc(len);
[data2 getBytes:aBuffer length:[data2 length]];
[data1 appendBytes:aBuffer length:len];

The final value of data1 is the series of ASCII characters "ABCDEFGH".

Replacing Bytes

You can replace a range of bytes in a mutable data object with zeros using the resetBytesInRange: method, or with different bytes using the replaceBytesInRange:withBytes: method. In Listing 3, a range of bytes in data1 is replaced by the bytes in data2, and the content of data1 changes from “Liz and John” to “Liz and Larry”:

Listing 3  Replacing bytes

NSMutableData *data1, *data2;
NSString *myString = @"Liz and John";
NSString *yourString = @"Larry";
const char *utfMyString = [myString UTF8String];
const char *utfYourString = [yourString UTF8String];
unsigned len;
unsigned char *aBuffer;
NSRange range = {8, strlen(utfYourString)};
data1 = [NSMutableData dataWithBytes:utfMyString length:strlen(utfMyString)];
data2 = [NSMutableData dataWithBytes:utfYourString length:strlen(utfYourString)];
len = [data2 length];
aBuffer = malloc(len);
[data2 getBytes:aBuffer length:len];
[data1 replaceBytesInRange:range withBytes:aBuffer];