2010-02-04 6 views
35

Comment faire pour convertir NSData en base64. J'ai NSData et que vous voulez convertir en base64 comment puis-je faire cela?Conversion de NSData en base64

+0

Salut Mr-sk pouvez-vous s'il vous plaît dites-moi comment accepter la réponse? – mactalent

+0

Ceci est très proche de cette question: http://stackoverflow.com/questions/392464/any-base64-library-on-iphone-sdk –

+0

alors, pourquoi avons-nous besoin de convertir NSData en base 64 en général? – zumzum

Répondre

46

EDIT

Au OS X 10.9/iOS 7, il est intégré dans les cadres.

Voir -[NSData base64EncodedDataWithOptions:]


Avant iOS 7/OS X 10.9:

Matt Gallagher a écrit an article sur ce thème. En bas, il donne un lien vers son code embarqué pour iPhone.

Sur le mac vous pouvez utiliser la bibliothèque OpenSSL, sur l'iPhone il écrit son propre impl.

+2

Il semble y avoir un petit problème dans le code Matts: Dans la ligne 'void * NewBase64Decode' 128, 'j + = accumulateIndex - 1;' doit être entouré de 'if (accumulatedIndex> 0) {...} ' Sinon, si le flux codé contient des caractères invalides (par exemple '\ r \ n') à la fin, le dernier caractère du texte décodé peut être perdu. Cela a causé des problèmes étranges dans mon code en faisant le décodage basé sur la ligne des réponses IMAP ... – DEAD10CC

+0

@Joker Cela m'est arrivé. Merci pour la solution facile, votre génie! – AndersTornkvist

+0

Il s'avère qu'il y avait une fonction pour faire cela depuis iOS4, mais il n'a jamais été publié publiquement jusqu'à iOS 7. Si imageData est une instance de NSData, alors simplement ... [imageData base64Encoding]; https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/classes/NSData_Class/DeprecationAppendix/AppendixADeprecatedAPI.html –

4

Ce n'est pas facile. Comme il n'y a pas de support intégré pour cela dans c ou obj-c. Voici ce que Im faire (ce qui est d'avoir essentiellement la CL faire pour moi):

- (NSString *)_base64Encoding:(NSString *) str 
{ 
    NSTask *task = [[[NSTask alloc] init] autorelease]; 
    NSPipe *inPipe = [NSPipe pipe], *outPipe = [NSPipe pipe]; 
    NSFileHandle *inHandle = [inPipe fileHandleForWriting], *outHandle = [outPipe fileHandleForReading]; 
    NSData *outData = nil; 

    [task setLaunchPath:@"/usr/bin/openssl"]; 
    [task setArguments:[NSArray arrayWithObjects:@"base64", @"-e", nil]]; 
    [task setStandardInput:inPipe]; 
    [task setStandardOutput:outPipe]; 
    [task setStandardError:outPipe]; 

    [task launch]; 

    [inHandle writeData:[str dataUsingEncoding: NSASCIIStringEncoding]]; 
    [inHandle closeFile]; 

    [task waitUntilExit]; 

    outData = [outHandle readDataToEndOfFile]; 
    if (outData) 
    { 
     NSString *base64 = [[[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding] autorelease]; 
     if (base64) 
      return base64; 
    } 

    return nil; 
} 

Et vous l'utiliser comme ceci:

NSString *b64str = [strToConvert _base64Encoding:strToConvert]; 

Et ce n'est pas mon code - je l'ai trouvé ici : http://www.cocoadev.com/index.pl?BaseSixtyFour et ça marche très bien. Vous pouvez toujours transformer ceci en une méthode +().

Oh, et pour obtenir votre NSData à un NSString pour cette méthode:

NSString *str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; 
+1

Sur le mac, il n'est pas nécessaire de générer un processus - vous pouvez directement utiliser libcrypto. Sur l'iPhone, est-ce que/usr/bin/openssl est présent? – Ken

+0

bonne réponse ... +1 –

6

Super facile drop dans le code de la bibliothèque Google here.

Il suffit d'utiliser +rfc4648Base64StringEncoding pour obtenir une instance, puis utilisez les fonctions encode/decode.

C'est une belle chose. (Ne pas oublier de saisir le fichier d'en-tête et l'en-tête GTMDefines.h de la racine, cependant.)

27
//from: http://cocoadev.com/BaseSixtyFour 
+ (NSString*)base64forData:(NSData*)theData { 

    const uint8_t* input = (const uint8_t*)[theData bytes]; 
    NSInteger length = [theData length]; 

    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/="; 

    NSMutableData* data = [NSMutableData dataWithLength:((length + 2)/3) * 4]; 
    uint8_t* output = (uint8_t*)data.mutableBytes; 

    NSInteger i; 
    for (i=0; i < length; i += 3) { 
    NSInteger value = 0; 
     NSInteger j; 
    for (j = i; j < (i + 3); j++) { 
     value <<= 8; 

     if (j < length) { 
     value |= (0xFF & input[j]); 
     } 
    } 

    NSInteger theIndex = (i/3) * 4; 
    output[theIndex + 0] =     table[(value >> 18) & 0x3F]; 
    output[theIndex + 1] =     table[(value >> 12) & 0x3F]; 
    output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '='; 
    output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '='; 
    } 

    return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease]; 
} 
+0

Une version rapide si vous avez? –

0

Je modifié le code ci-dessus pour répondre à mes besoins, la construction d'un HTTP POST. J'ai pu sauter l'étape NSString, et inclure les sauts de ligne dans le code BASE64, dont au moins un serveur web trouvé plus acceptable:

#define LINE_SIZE 76 

//originally from: http://www.cocoadev.com/index.pl?BaseSixtyFour 
// via joshrl on stockoverflow 

- (void) appendBase64Of: (NSData *)inData to:(NSMutableData *)outData { 
    const uint8_t* input = (const uint8_t*)[inData bytes]; 
    NSInteger length = [inData length]; 

    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/="; 

    uint8_t buf[LINE_SIZE + 4 + 2]; 
    size_t n = 0; 

    NSInteger i; 
    for (i=0; i < length; i += 3) { 
     NSInteger value = 0; 
     NSInteger j; 
     for (j = i; j < (i + 3); j++) { 
      value <<= 8; 

      if (j < length) { 
       value |= (0xFF & input[j]); 
      } 
     } 

     buf[n + 0] =     table[(value >> 18) & 0x3F]; 
     buf[n + 1] =     table[(value >> 12) & 0x3F]; 
     buf[n + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '='; 
     buf[n + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '='; 
     n += 4; 
     if (n + 2 >= LINE_SIZE) { 
      buf[n++] = '\r'; 
      buf[n++] = '\n'; 
      [outData appendBytes:buf length:n]; 
      n = 0; 
     } 
    } 
    if (n > 0) { 
     buf[n++] = '\r'; 
     buf[n++] = '\n'; 
     [outData appendBytes:buf length:n]; 
    } 
    return; 
} 
20

Comme une mise à jour, le SDK iOS 7 a une catégorie sur NSData (NSDataBase64Encoding) avec des méthodes

-[NSData base64EncodedStringWithOptions:] 
-[NSData initWithBase64EncodedString:options:] 
-[NSData initWithBase64EncodedData:options:] 
-[NSData base64EncodedDataWithOptions:] 

devrait éviter d'avoir à rouler votre propre méthode de catégorie

+0

Wow, c'est génial d'entendre! Chaque fois qu'il s'agit de base64, je me demande pourquoi il n'est pas présent dans les librairies standard de tant de langues ... – DEAD10CC

+1

Ceux-ci sont disponibles sur iOS 4, iOS 7 SDK vient de les rendre publics – Crake

+0

Désolé, il y a des équivalents fonctionnels méthodes disponibles retour à iOS 4 (initWithBase64Encoding et base64Encoding) – Crake

2

iOS a toujours inclus un support intégré pour le codage et le décodage base64. Si vous regardez resolv.h, vous devriez voir les deux fonctions b64_ntop et b64_pton. La bibliothèque Square SocketRocket fournit un exemple raisonnable de la façon d'utiliser ces fonctions à partir de l'objectif-c.

Ces fonctions sont assez bien testées et fiables - contrairement à la plupart des implémentations que vous pouvez trouver dans les publications Internet aléatoires. Ne pas oublier de lier contre libresolv.dylib.

Si vous lien contre le SDK iOS 7, vous pouvez utiliser les méthodes plus récentes initWithBase64Encoding: et base64EncodedDataWithOptions:. Ceux-ci existent dans les versions précédentes, mais étaient privés. Donc, si vous faites un lien avec le 6 SDK, vous pouvez rencontrer un comportement indéfini. Ce serait un exemple de la façon de l'utiliser uniquement lors de la liaison contre le 7 SDK:

#ifndef __IPHONE_7_0 
    // oh no! you are using something unsupported! 
    // Call and implementation that uses b64_pton here 
#else 
    data = [[NSData alloc] initWithBase64Encoding:string]; 
#endif