Compy
Compy

Reputation: 1177

Left bit rotation of a string Objective C

I've been given the following C++ function to do a left bit rotation of a string, I need to implement it in Objective C(Obviously I've added the logging bit at the bottom):

void left_rotate ( uint16_t *in,
              uint16_t *out,
              int16_t   len,
              int16_t   shift )
{
    int16_t i, j;

    j = (len / 2) - 1;
    for (i = 0; i < (len / 2); i++) {
        out[i] = (uint16_t) (in[i] << shift);
        if (i < j) {
            out[i] |= in[i + 1] >> ((int16_t) len - shift);
        } else {
            out[i] |= in[0] >> ((int16_t) len - shift);
        }
    }
    NSLog(@"In: %hd", (short)in);
    NSLog(@"Out: %hd", (short)out);

    unsigned char * char1 = out;

    NSLog(@"Char: %s", char1);

    NSData * data1 = [[NSData alloc] initWithBytes:char1 length:sizeof(char1)];

    NSLog(@"Data: %@", data1);

}

However I'm not entirely sure how it's supposed to work. I've tried to call it as follows:

NSString * originStringData = @"acf7183f7673200BBA7719775b20393c4487fa008e13542f4013eb9b2eb7490e";

NSString * RotateNumber = @"0003";

NSData *data = originStringData;
NSUInteger len = [data length];
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);

for(int i=0; i<sizeof(byteData); i++)
{
    u_int16_t data2 = byteData[i];
    int16_t shift1 = (short)[RotateNumber intValue];

    u_int16_t out1;

    left_rotate(&data2, &out1, sizeof(byteData),shift1);
}

However it returns:

<60055600><b8077b00><c1001c00><f9011f00>

Where as the string I actually want is:

67b8c1fbb399005dd3b8cbbad901c9e2243fd004709aa17a009f5cd975ba4875

What I need to do is perform a left bit rotation on the origin string by the Rotate Number. I'm willing to give anything a go right now so any help would be appreciated, I'm a bit stuck!

Cheers!

Adam

Upvotes: 1

Views: 331

Answers (2)

wuqiang
wuqiang

Reputation: 644

It seems left_rotate doesn't work as you desire. You can write you own rotate function like this(it works as what you want):

#import <Foundation/Foundation.h>

char char_to_hex(char ch)
{
    char* table = "0123456789abcdef";
    char* str = strchr(table, tolower(ch));
    if(str == NULL)
        return -1;
    return str - table;
}

NSString* left_rotate(NSString* source, NSUInteger shift)
{
    if(shift >= [source length] * 4)
    {
        shift %= ([source length] * 4);
    }
    NSInteger index = shift / 4;
    NSString* tmp = [source substringFromIndex:index];
    NSString* left = [source substringToIndex:index+1];
    tmp = [tmp stringByAppendingString:left];

    shift %= 4;

    //get the internal pointer;
    const char* data = [tmp cStringUsingEncoding:NSASCIIStringEncoding];

    NSString* result = [[NSString alloc] init];
    for(NSInteger i = 0; i < strlen(data) - 1; i++)
    {
        char ch1 = char_to_hex(data[i]);
        char ch2 = char_to_hex(data[i+1]);
        if(ch1 < 0 || ch2 < 0)
            return nil;
        char ch = ((ch1 << shift) | (ch2 >> (4 - shift))) & 0xF;
        result = [result stringByAppendingFormat:@"%x", ch];
    }

    return result;
}

int main(int argc, const char * argv[]) {
    NSString* source = @"acf7183f7673200BBA7719775b20393c4487fa008e13542f4013eb9b2eb7490e";
    NSString* result = left_rotate(source, 3);
    NSLog(@"result:%@", result);
    return 0;
}

Upvotes: 1

Pieter
Pieter

Reputation: 17715

I believe you pass the wrong types to your function, you want to convert your NSString* to an array of int16 before you pass it, what you're doing however, is simply copying the bytes representing the string.

Simply put, if you copy the byes representing "1", you won't get the equivalent of 1, you have to add some conversion.

Something along these lines (no error handling, assuming a lot of things from your input, adapt!)

for (NSUInteger i = 0; i < originStringData.length; ++i {
    unichar oneChar = [originStringData characterAtIndex:i];
    if (isnumber(oneChar)) {
        byteData[i] = oneChar - '0';
    } else {
        byteData[i] = oneChar - 'a' + 10;
    }
}

On top of that you want to allocate some space for your out too, you're passing a pointer to a single int16, allocate another array of the same size and pass that.

Upvotes: 0

Related Questions