1

I have a binary file that I would like to regex search/replace hex bytes within it. I know there are command line methods for achieving this with Perl, however, if there's a way to do this with Objective-C/Cocoa I haven't been able to find it. The Perl method from the command line in OSX which works fine, although I would like to incorporate such in a Cocoa application - thanks

Binary file: TEST

45 76 65 6E 20 69 66 20 79 6F 75 20 66 61 6C 6C 20 6F 6E 20 79 6F 75 72 20 66 61 63 65 2C 20 79 6F 75 27 72 65 20 73 74 69 6C 6C 20 6D 6F 76 69 6E 67 20 66 6F 72 77 61 72 64 2E 20 

Bytes to replace: 66 61 63 Replace with: 61 72 73

Perl example:

# grep -Z -r -l face TEST | xargs -0 perl -pi -e "s/\x66\x61\x63/\x61\x72\x73/g"

1 Answer 1

3

Something along the lines of this should work:

// Change TEST to the absolute path of the file to read the data from
NSString *fileName = @"TEST";
NSMutableData *data = [NSMutableData dataWithContentsOfFile:fileName];
if (data == nil || [data length] == 0) {
    return;
}

Your original question:

char bytes[]     = {0x66, 0x61, 0x63};
char new_bytes[] = {0x61, 0x72, 0x73};

NSRange range = [data rangeOfData:[NSData dataWithBytes:bytes length:3] options:0 range:NSMakeRange(0, [data length])];
if (range.location == NSNotFound) {
    return;
}

[data replaceBytesInRange:range withBytes:new_bytes];
[data writeToFile:fileName atomically:YES];

Edited for wildcard (I just used -1 for the wildcard and it can be in any spot):

char bytes[]     = {0x66, -0x1, 0x63};
char new_bytes[] = {0x61, 0x72, 0x73};

NSUInteger dataLength = [data length];
if (dataLength < 3) {
    return;
}

char *data_bytes = (char *)[data bytes];

int dataLengthMinus3 = dataLength - 3;

for (NSUInteger i = 0; i < dataLengthMinus3; i++) {
    if (bytes[0] == -0x1 || data_bytes[i] == bytes[0]) {
        if (bytes[1] == -0x1 || data_bytes[i+1] == bytes[1]) {
            if (bytes[2] == -0x1 || data_bytes[i+2] == bytes[2]) {
                for (int z = 0; z < 3; z++) {
                    if (new_bytes[z] != -0x1){
                        [data replaceBytesInRange:NSMakeRange(i+z, 1) withBytes:new_bytes[z]];
                    }
                }
                i += 2;
                continue; // Make this break if you only want to replace the first occurrence.
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

14 Comments

@Inafziger, thanks for the example. I compiled your code (no errors), run it (no errors), although the file remains unchanged. Everything seems like it should work, so I'm a little perplexed. If you have any thoughts let me know.
Did you step through it in the debugger to see if it returns early?
After running the debugger it appears it's looking for this: bytes char [3] [0] char 'B' [1] char '=' [2] char '?' and newbytes is: new_bytes char [3] [0] char '=' [1] char 'H' [2] char 'I' — so it looks like an encoding issue?
Okay, I know why. NSData wants to see values in decimal so convert the bytes in the two status from hex to decimal.
Thank you so very much Inafziger, I seriously appreciate it! ;-)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.