Search code examples
cocoansarraynsdatades

Cocoa Convert NSArray/NSString of octals to NSData?


I'm trying to covert this bit of C code to Cocoa and I'm struggling to figure out how.

  char *deskey = "123 456 789 101 112 131 415 161";
  unsigned char key[16];
  memset(key, 0, sizeof(key));
  sscanf(deskey, "%o %o %o %o %o %o %o %o",
    (int*)&key[0], (int*)&key[1], (int*)&key[2],
    (int*)&key[3], (int*)&key[4], (int*)&key[5],
    (int*)&key[6], (int*)&key[7]);

I've tried using NSMutableArray and NSData but having no luck. I was able to scan the string and pull out the numbers, but I'm not sure how to store into NSData after that.

  NSMutableArray *enckey = [[[NSMutableArray alloc] init] autorelease];
  NSScanner *scanner = [NSScanner scannerWithString:self.deskey];
  int pos = 0;

  while ([scanner isAtEnd] == NO) {
    if ([scanner scanInt:&pos]) {
      [enckey addObject:[NSString stringWithFormat:@"%o", pos]];
    }
    else {
      NSLog(@"Your DES key appears to be invalid.");
      return;
    }
  }

Basically trying to convert ascii DES key to string to use for Triple DES encryption. Any help is greatly appreciated, thank you!


Solution

  • @Keenan "I was hoping to avoid using sscanf and char* in place of the Cocoa classes". Well you can do that, but what are you hoping to produce? If you want a byte array as the result then you need to stick to unsigned char[], and that begs the question why you'd do the parsing on NSString in the first place.

    Here is an Objective-C translation of your C code. Note that octal is seen as ancient history by Cocoa so its parsing classes only deal with decimal and hexadecimal, so you need to write your own or use a standard C function (strtol below).

    This example produces both a unsigned char[] and an NSMutableArray - pick one.

    // There are no checks in the code, like in the original...
    // BTW 789 is not an octal number...
    NSString *descKey = @"123 456 789 101 112 131 415 161";         //    char *deskey = "123 456 789 101 112 131 415 161";
    // pick one...
    NSMutableArray *keyObjC = [NSMutableArray new];                 //    unsigned char key[16];
    unsigned char keyC[16];
    //    memset(key, 0, sizeof(key));
    
    // As @JeremyP has pointed out the sscanf is wrong as %o produces a 4-byte value and you only want a 1-byte one.
    // In C you would therefore need key to be an array of ints and then assign each element to a byte (unsigned char),
    // or parse a different way.
    
    unsigned ix = 0;    // for keyC choice only
    NSArray *numbers = [descKey componentsSeparatedByString:@" "];  //    sscanf(deskey, "%o %o %o %o %o %o %o %o",
    for (NSString *aNumber in numbers)                              //           (int*)&key[0], (int*)&key[1], (int*)&key[2],
    {                                                               //           (int*)&key[3], (int*)&key[4], (int*)&key[5],
                                                                    //           (int*)&key[6], (int*)&key[7]);
        unsigned char next = (unsigned char)strtol([aNumber UTF8String], NULL, 8);
        keyC[ix++] = next;                                          // for keyC choice
        [keyObjC addObject:[NSNumber numberWithUnsignedChar:next]]; // keyObjC choice
    }
    

    If you want to approach the one line of your Python just compress the iteration to:

    for (NSString *aNumber in [descKey componentsSeparatedByString:@" "]) { [keyObjC addObject:[NSNumber numberWithUnsignedChar:(unsigned char)strtol([aNumber UTF8String], NULL, 8)]]; }
    

    but it is still longer of course!