İOS'ta base64 kodlamasını nasıl yaparım?


230

base64Kodlama ve kod çözme yapmak istiyorum , ancak iPhone'dan herhangi bir destek bulamadım SDK. base64Kütüphane ile veya kütüphane olmadan nasıl kodlama ve kod çözme yapabilirim ?


1
Bu yazının altında güzel bir kod örneği var. Çok kendine yeten ... BaseSixtyFour
Greg Bernhardt

@GregBernhardt bağlantısı öldü.
Coeur

Yanıtlar:


116

Bu, Objective C kategorileri için iyi bir kullanım durumudur .

Base64 kodlaması için:

#import <Foundation/NSString.h>

@interface NSString (NSStringAdditions)

+ (NSString *) base64StringFromData:(NSData *)data length:(int)length;

@end

-------------------------------------------

#import "NSStringAdditions.h"

static char base64EncodingTable[64] = {
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
  'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};

@implementation NSString (NSStringAdditions)

+ (NSString *) base64StringFromData: (NSData *)data length: (int)length {
  unsigned long ixtext, lentext;
  long ctremaining;
  unsigned char input[3], output[4];
  short i, charsonline = 0, ctcopy;
  const unsigned char *raw;
  NSMutableString *result;

  lentext = [data length]; 
  if (lentext < 1)
    return @"";
  result = [NSMutableString stringWithCapacity: lentext];
  raw = [data bytes];
  ixtext = 0; 

  while (true) {
    ctremaining = lentext - ixtext;
    if (ctremaining <= 0) 
       break;        
    for (i = 0; i < 3; i++) { 
       unsigned long ix = ixtext + i;
       if (ix < lentext)
          input[i] = raw[ix];
       else
  input[i] = 0;
  }
  output[0] = (input[0] & 0xFC) >> 2;
  output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);
  output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);
  output[3] = input[2] & 0x3F;
  ctcopy = 4;
  switch (ctremaining) {
    case 1: 
      ctcopy = 2; 
      break;
    case 2: 
      ctcopy = 3; 
      break;
  }

  for (i = 0; i < ctcopy; i++)
     [result appendString: [NSString stringWithFormat: @"%c", base64EncodingTable[output[i]]]];

  for (i = ctcopy; i < 4; i++)
     [result appendString: @"="];

  ixtext += 3;
  charsonline += 4;

  if ((length > 0) && (charsonline >= length))
    charsonline = 0;
  }     
  return result;
}

@end

Base64 kod çözme için:

#import <Foundation/Foundation.h>

@class NSString;

@interface NSData (NSDataAdditions)

+ (NSData *) base64DataFromString:(NSString *)string;

@end

-------------------------------------------

#import "NSDataAdditions.h"

@implementation NSData (NSDataAdditions)

+ (NSData *)base64DataFromString: (NSString *)string
{
    unsigned long ixtext, lentext;
    unsigned char ch, inbuf[4], outbuf[3];
    short i, ixinbuf;
    Boolean flignore, flendtext = false;
    const unsigned char *tempcstring;
    NSMutableData *theData;

    if (string == nil)
    {
        return [NSData data];
    }

    ixtext = 0;

    tempcstring = (const unsigned char *)[string UTF8String];

    lentext = [string length];

    theData = [NSMutableData dataWithCapacity: lentext];

    ixinbuf = 0;

    while (true)
    {
        if (ixtext >= lentext)
        {
            break;
        }

        ch = tempcstring [ixtext++];

        flignore = false;

        if ((ch >= 'A') && (ch <= 'Z'))
        {
            ch = ch - 'A';
        }
        else if ((ch >= 'a') && (ch <= 'z'))
        {
            ch = ch - 'a' + 26;
        }
        else if ((ch >= '0') && (ch <= '9'))
        {
            ch = ch - '0' + 52;
        }
        else if (ch == '+')
        {
            ch = 62;
        }
        else if (ch == '=')
        {
            flendtext = true;
        }
        else if (ch == '/')
        {
            ch = 63;
        }
        else
        {
            flignore = true; 
        }

        if (!flignore)
        {
            short ctcharsinbuf = 3;
            Boolean flbreak = false;

            if (flendtext)
            {
                if (ixinbuf == 0)
                {
                    break;
                }

                if ((ixinbuf == 1) || (ixinbuf == 2))
                {
                    ctcharsinbuf = 1;
                }
                else
                {
                    ctcharsinbuf = 2;
                }

                ixinbuf = 3;

                flbreak = true;
            }

            inbuf [ixinbuf++] = ch;

            if (ixinbuf == 4)
            {
                ixinbuf = 0;

                outbuf[0] = (inbuf[0] << 2) | ((inbuf[1] & 0x30) >> 4);
                outbuf[1] = ((inbuf[1] & 0x0F) << 4) | ((inbuf[2] & 0x3C) >> 2);
                outbuf[2] = ((inbuf[2] & 0x03) << 6) | (inbuf[3] & 0x3F);

                for (i = 0; i < ctcharsinbuf; i++)
                {
                    [theData appendBytes: &outbuf[i] length: 1];
                }
            }

            if (flbreak)
            {
                break;
            }
        }
    }

    return theData;
}

    @end

5
Obj-C, C gibi bir şeyse, bunu yapabilmeniz gerekir: statik karakter tabanı baseEnEndingTable [64] = "ABCDE [vb] 789 + /";
Artelius

3
Neden sadece 4 karakter elde ettiğimi buldum ... while () döngüsünün dönüşünden önce bir} olması gerekiyor. Düzenlerdim ama yapabildiğim gibi görünmüyorum.
Larry Hipp

3
Bu bir analizör hatası değil. Kodun, bu dizinin sınırlarının ötesinde olan inbuf [3] 'e erişmeye çalıştığına dikkat edin. Bu kod kokuyor.
Mike Weller

1
Uzunluk değeri neyi temsil eder?
MegaManX

3
İOS7'den itibaren Apple, yerel temel 64 kodlama yöntemini ortaya çıkardı. Geriye dönük uyumluluğu korurken nasıl kullanılacağı hakkında aşağıdaki Rob yanıtına bakın.
Kod Komutanı

100

PHP Core kitaplığından yerel Objective-C koduna taşınan (ve değiştirilen / geliştirilen) gerçekten, gerçekten hızlı bir uygulama , QSUtilities Kitaplığından QSStrings Sınıfında mevcuttur . Hızlı bir kıyaslama yaptım: 5.3MB'lık bir görüntü (JPEG) dosyasının kodlanması <50ms ve kod çözülmesi yaklaşık 140ms.

Tüm kütüphanenin kodu (Base64 Yöntemleri dahil) GitHub'da bulunur .

Veya alternatif olarak, kodun yalnızca Base64 yöntemlerinin kendilerine olmasını istiyorsanız, buraya gönderdim:

İlk olarak, eşleme tablolarına ihtiyacınız var:

static const char _base64EncodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const short _base64DecodingTable[256] = {
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -1, -1, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2,
    -2,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2,
    -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
};

Kodlamak için:

+ (NSString *)encodeBase64WithString:(NSString *)strData {
    return [QSStrings encodeBase64WithData:[strData dataUsingEncoding:NSUTF8StringEncoding]];
}

+ (NSString *)encodeBase64WithData:(NSData *)objData {
    const unsigned char * objRawData = [objData bytes];
    char * objPointer;
    char * strResult;

    // Get the Raw Data length and ensure we actually have data
    int intLength = [objData length];
    if (intLength == 0) return nil;

    // Setup the String-based Result placeholder and pointer within that placeholder
    strResult = (char *)calloc((((intLength + 2) / 3) * 4) + 1, sizeof(char));
    objPointer = strResult;

    // Iterate through everything
    while (intLength > 2) { // keep going until we have less than 24 bits
        *objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
        *objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
        *objPointer++ = _base64EncodingTable[((objRawData[1] & 0x0f) << 2) + (objRawData[2] >> 6)];
        *objPointer++ = _base64EncodingTable[objRawData[2] & 0x3f];

        // we just handled 3 octets (24 bits) of data
        objRawData += 3;
        intLength -= 3; 
    }

    // now deal with the tail end of things
    if (intLength != 0) {
        *objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
        if (intLength > 1) {
            *objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
            *objPointer++ = _base64EncodingTable[(objRawData[1] & 0x0f) << 2];
            *objPointer++ = '=';
        } else {
            *objPointer++ = _base64EncodingTable[(objRawData[0] & 0x03) << 4];
            *objPointer++ = '=';
            *objPointer++ = '=';
        }
    }

    // Terminate the string-based result
    *objPointer = '\0';

    // Create result NSString object
    NSString *base64String = [NSString stringWithCString:strResult encoding:NSASCIIStringEncoding];

    // Free memory
    free(strResult);

    return base64String;
}

Kod Çözmek için:

+ (NSData *)decodeBase64WithString:(NSString *)strBase64 {
    const char *objPointer = [strBase64 cStringUsingEncoding:NSASCIIStringEncoding];
    size_t intLength = strlen(objPointer);
    int intCurrent;
    int i = 0, j = 0, k;

    unsigned char *objResult = calloc(intLength, sizeof(unsigned char));

    // Run through the whole string, converting as we go
    while ( ((intCurrent = *objPointer++) != '\0') && (intLength-- > 0) ) {
        if (intCurrent == '=') {
            if (*objPointer != '=' && ((i % 4) == 1)) {// || (intLength > 0)) {
                // the padding character is invalid at this point -- so this entire string is invalid
                free(objResult);
                return nil;
            }
            continue;
        }

        intCurrent = _base64DecodingTable[intCurrent];
        if (intCurrent == -1) {
            // we're at a whitespace -- simply skip over
            continue;
        } else if (intCurrent == -2) {
            // we're at an invalid character
            free(objResult);
            return nil;
        }

        switch (i % 4) {
            case 0:
                objResult[j] = intCurrent << 2;
                break;

            case 1:
                objResult[j++] |= intCurrent >> 4;
                objResult[j] = (intCurrent & 0x0f) << 4;
                break;

            case 2:
                objResult[j++] |= intCurrent >>2;
                objResult[j] = (intCurrent & 0x03) << 6;
                break;

            case 3:
                objResult[j++] |= intCurrent;
                break;
        }
        i++;
    }

    // mop things up if we ended on a boundary
    k = j;
    if (intCurrent == '=') {
        switch (i % 4) {
            case 1:
                // Invalid state
                free(objResult);
                return nil;

            case 2:
                k++;
                // flow through
            case 3:
                objResult[k] = 0;
        }
    }

    // Cleanup and setup the return NSData
    NSData * objData = [[[NSData alloc] initWithBytes:objResult length:j] autorelease];
    free(objResult);
    return objData;
}

2
Son olarak doğru ve verimli bir uygulama. Teşekkürler. Buradaki diğer kodlardan bazıları beni korkutuyor.
Mike Weller

4
strResultKodlayıcıda olduğu gibi tahsis edilen bellek sızdırılmış gibi görünüyor; sadece free()(sonunda dönmeden önce ama sonra NSString stringWithCString) bir ihtiyacı var
JosephH

2
Senin içinde encodeBase64WithData:metoda çağrısında ilk parametre gelmez calloc()ihtiyacı null Terminatör (hesaba için 1 arttırılır edilecek '\0') Eğer sonuna eklenecek?
erikprice


2
Bir süredir kullanıyorum ve bazı bellek bozulması ile ilgili hatalar almaya başlayana kadar harika görünüyordu ve bekçi malloc kullanarak ben bu satıra daralttım: * objPointer = '\ 0'; bu yüzden bunu kendi uygulamalarınızda kullanıyorsanız dikkatli olun.
Mattia

72

Tarihsel olarak, sizi ikili verilerden temel 64 dizeye (ve geri) dönüştürmek için birçok üçüncü taraf temel 64 kütüphanesinden birine (diğer yanıtlarda tartışıldığı gibi) yönlendirirdik, ancak iOS 7 artık yerel temel 64 kodlamasına (ve iOS'un önceki sürümlerini desteklemeniz gerekiyorsa, önceki özel iOS 4 yöntemlerini gösterir).

Böylece taban 64 temsile dönüştürmek NSDataiçin NSStringkullanabilirsiniz base64EncodedStringWithOptions. 7.0'dan önceki iOS sürümlerini de desteklemeniz gerekiyorsa şunları yapabilirsiniz:

NSString *string;

if ([data respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
    string = [data base64EncodedStringWithOptions:kNilOptions];  // iOS 7+
} else {
    string = [data base64Encoding];                              // pre iOS7
}

Ve taban 64 NSStringgeri dönüştürmek için NSDatakullanabilirsiniz initWithBase64EncodedString. Benzer şekilde, 7.0'dan önceki iOS sürümlerini desteklemeniz gerekiyorsa şunları yapabilirsiniz:

NSData *data;

if ([NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)]) {
    data = [[NSData alloc] initWithBase64EncodedString:string options:kNilOptions];  // iOS 7+
} else {
    data = [[NSData alloc] initWithBase64Encoding:string];                           // pre iOS7
}

Açıkçası, 7.0'dan önceki iOS sürümleriyle geriye dönük uyumluluğa ihtiyacınız yoksa, daha da kolay, sadece base64EncodedStringWithOptionsveya initWithBase64EncodedStringsırasıyla kullanın ve daha önceki iOS sürümleri için çalışma zamanı kontrolü ile uğraşmayın. Aslında, minimum hedefiniz iOS 7 veya daha yüksek olduğunda yukarıdaki kodu kullanırsanız, kullanımdan kaldırılan yöntemler hakkında derleyici uyarısı alırsınız. Bu nedenle, iOS 7 ve daha yeni sürümlerde, temel 64 dizeye şu şekilde dönüştürebilirsiniz:

NSString *string = [data base64EncodedStringWithOptions:kNilOptions];

ve tekrar:

NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:kNilOptions]; 

Rob için teţekkürler. Yazdıklarınızı kısaca açıklar mısınız, " ... ve daha önce özel iOS 4 yöntemlerini ortaya koyar "?
phi

8
Bu cevabın tüm bu özel uygulamaların altına gömülmesi bir utanç. Bu, orijinal sorunun sorulmasından çok daha uzun bir süre sonra daha uygun bir çözümün gelebileceği SO'nun zayıflığıdır, bu çözümün daha önce kabul edilenle rekabet etmek zorunda kalmasıdır.
jakev

Bu yüzden daha yakın zamanda doğru cevapları değerlendirmek her zaman yararlıdır :)
Steve Wilford

neden böyle cehennem cevapları üstte değildir :(, ben T__T yukarıdaki tüm cevapları işleme çok zaman geçirdim
Alsh derleyici

33

iOS, base64 kodlama ve kod çözme için yerleşik destek içerir. Eğer bakarsanız resolv.hsize iki işlevi görmelisiniz b64_ntopve b64_pton. Square SocketRocket kütüphanesi, bu işlevlerin objektif-c'den nasıl kullanılacağına dair makul bir örnek sağlar.

Bu işlevler oldukça iyi test edilmiş ve güvenilirdir - rastgele internet yayınlarında bulabileceğiniz birçok uygulamanın aksine. Bağlantı kurmayı unutmayın libresolv.dylib.


3
müthiş; rastgele internet sitesinden çok daha iyi! Herhangi birinin bu az belgelenmiş işlevleri kullanmaktan endişe etmesi durumunda, bunların kaynağını Apple'ın sitesinde görebilirsiniz .
Jesse Rusak

1
Bu adam biraz daha arka plan veriyor: blog.montgomerie.net/ios-hidden-base64-routines
Mike

21

Bu base64 kodlama ve iphone bir numaralı google hit gibi göründüğünden, yukarıdaki kod snippet ile deneyimimi paylaşmak gibi hissettim.

Çalışıyor, ancak son derece yavaş. Rastgele bir görüntüdeki (0.4 mb) bir kıyaslama, yerel iphone'da 37 saniye sürdü. Ana nedeni muhtemelen tüm OOP büyüsüdür - tek kodlama yapıldıktan sonra otomatik olarak yayınlanan tek karakterli NSStrings vb.

Burada (ab) yayınlanan başka bir öneri de aşırı doldurma gibi görünen openssl kütüphanesini kullanıyor.

Aşağıdaki kod 70 ms sürüyor - bu 500 kat hızlanıyor. Bu sadece base64 kodlaması yapar (kod çözme, karşılaştığım anda takip eder)

+ (NSString *) base64StringFromData: (NSData *)data length: (int)length {
int lentext = [data length]; 
if (lentext < 1) return @"";

char *outbuf = malloc(lentext*4/3+4); // add 4 to be sure

if ( !outbuf ) return nil;

const unsigned char *raw = [data bytes];

int inp = 0;
int outp = 0;
int do_now = lentext - (lentext%3);

for ( outp = 0, inp = 0; inp < do_now; inp += 3 )
{
    outbuf[outp++] = base64EncodingTable[(raw[inp] & 0xFC) >> 2];
    outbuf[outp++] = base64EncodingTable[((raw[inp] & 0x03) << 4) | ((raw[inp+1] & 0xF0) >> 4)];
    outbuf[outp++] = base64EncodingTable[((raw[inp+1] & 0x0F) << 2) | ((raw[inp+2] & 0xC0) >> 6)];
    outbuf[outp++] = base64EncodingTable[raw[inp+2] & 0x3F];
}

if ( do_now < lentext )
{
    char tmpbuf[2] = {0,0};
    int left = lentext%3;
    for ( int i=0; i < left; i++ )
    {
        tmpbuf[i] = raw[do_now+i];
    }
    raw = tmpbuf;
    outbuf[outp++] = base64EncodingTable[(raw[inp] & 0xFC) >> 2];
    outbuf[outp++] = base64EncodingTable[((raw[inp] & 0x03) << 4) | ((raw[inp+1] & 0xF0) >> 4)];
    if ( left == 2 ) outbuf[outp++] = base64EncodingTable[((raw[inp+1] & 0x0F) << 2) | ((raw[inp+2] & 0xC0) >> 6)];
}

NSString *ret = [[[NSString alloc] initWithBytes:outbuf length:outp encoding:NSASCIIStringEncoding] autorelease];
free(outbuf);

return ret;
}

İhtiyaç duymadığım için satır kesmeyi bıraktım, ancak eklemek çok kolay.

Optimize etmek isteyenler için: amaç, ana döngüde olanları en aza indirmektir. Bu nedenle, son 3 bayt ile ilgili tüm mantık döngü dışında işlem görür.

Ayrıca, arabelleklere / arabelleklerinden ek kopyalama yapmadan yerinde veriler üzerinde çalışmayı deneyin. Ve herhangi bir aritmetiği en düşük seviyeye indirin.

Tablodaki bir girişi aramak için bir araya getirilen bitlerin, kaydırılmadan birlikte yönlendirilecekleri zaman üst üste binmeyeceğini gözlemleyin. Bu nedenle büyük bir gelişme, 4 ayrı 256 bayt arama tablosu kullanmak ve vardiyaları ortadan kaldırmak olabilir, örneğin:

outbuf[outp++] = base64EncodingTable1[(raw[inp] & 0xFC)];
outbuf[outp++] = base64EncodingTable2[(raw[inp] & 0x03) | (raw[inp+1] & 0xF0)];
outbuf[outp++] = base64EncodingTable3[(raw[inp+1] & 0x0F) | (raw[inp+2] & 0xC0)];
outbuf[outp++] = base64EncodingTable4[raw[inp+2] & 0x3F];

Tabii ki bunu çok daha ileriye götürebilirsiniz, ama buradaki kapsamın ötesinde.


Hmm. Bunu çalıştıramadım. Beklediğim değerden farklı bir base64 kodlaması gözlemliyorum. Bunu RFC 4648'deki örneklerle test ettiniz mi? tools.ietf.org/html/rfc4648
Alex Reynolds

3
Base64EncodingTable1, base64EncodingTable2, base64EncodingTable3 ve base64EncodingTable4'ün hangi kaynaklara başvurduğunu görmek için uğraşıyor musunuz?
Jamie Chapman

Çok yararlı, ancak giriş arabelleğinin ötesinde okuyabilir. (Left == 2) olduğunda, ham [inp + 2], tmpbuf'un sonunun ötesinde bir bayt olacaktır. Bence çizgi olmalıdır: if (left == 2) outbuf [outp ++] = base64EncodingTable [((raw [inp + 1] & 0x0F) << 2)];
John Lemberger

aşağıdaki satırı <code> char tmpbuf [2] = {0,0}; </code> olarak <code> unsigned char tmpbuf [3] = {0,0,0}; </code>
Satya

9

DVD'lerin mükemmel gelişiminde iki sorun vardır. Kodu şu şekilde değiştirin:

raw = tmpbuf;
inp = 0;
outbuf[outp++] = base64EncodingTable[(raw[inp] & 0xFC) >> 2];
outbuf[outp++] = base64EncodingTable[((raw[inp] & 0x03) << 4) | ((raw[inp+1] & 0xF0) >> 4)];
if ( left == 2 ) outbuf[outp++] = base64EncodingTable[((raw[inp+1] & 0x0F) << 2) | ((raw[inp+2] & 0xC0) >> 6)];
else outbuf[outp++] = '=';
outbuf[outp++] = '=';

9

Daha iyi çözüm:

NSData'da yerleşik bir fonksiyon var

[data base64Encoding]; //iOS < 7.0
[data base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength]; //iOS >= 7.0

Bunu, uygulamanın çalıştığı iOS sürümüne göre "[[UIDevice currentDevice] systemVersion] .floatValue" kullanarak yapabiliriz.
Nagaraj

2
1. Bu size hangi SDK'ya bağlandığınızı söylemez, bu bir çalışma zamanı kontrolüdür. 2. Bu doğrudan Apple'ın rehberliğine ters düşmektedir. Sistem sürümünü değil, bir özelliğin kullanılabilirliğini kontrol etmelisiniz.
quellish

6

Memnun insanlar hoşuma gitti. Son oyun biraz kusurlu olduğunu itiraf etmeliyim. Doğru bir şekilde inp = 0 ayarının yanı sıra, tmpbuf'un boyutunu da 3'e çıkarmalısınız.

unsigned char tmpbuf[3] = {0,0,0};

veya ham [inp + 2] orringlerini dışarıda bırakın; bu yığın için ham bir [inp + 2]! = 0 olsaydı, yine de döngüde olurduk ...

Her iki durumda da, netlik için son tablo arama bloğunu döngüdeki ile aynı tutmayı düşünebilirsiniz. Kullandığım son versiyonda yaptım

while ( outp%4 ) outbuf[outp++] = '=';

== eklemek için

Üzgünüm RFC ve malzeme kontrol etmedi, daha iyi bir iş yapmış olmalı!


3
burada zaten bir hesabınız var, çünkü önceki cevabınız aslında farklı bir hesap. Ayrıca, bunun bir düzenleme veya yorum olması gerekir.
Alastair Pitts

@alastair, çerezleri temizledikten sonra kaydolmadan her cevap gönderdiğinizde "hesap" alıyormuşsunuz gibi görünüyor. İlk "hesabıma" (aynı e-posta ve ip adresiyle bile) bağlanamadım, bu yüzden yeni bir cevap olarak koydum, bunun için üzgünüm. - yeni kayıt!
mvds

3
Kesin bir doğru sürüm olması için bu cevabı bir öncekine düzenleme şansınız var mı? Teşekkürler!
JosephH

6

İOS8 ve sonrasında - (NSString *)base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)optionsNSData kullanımı


3
#import "NSDataAdditions.h"
@implementation NSData (NSDataAdditions)

+ (NSData *) base64DataFromString: (NSString *)string {
  unsigned long ixtext, lentext;
  unsigned char ch, input[4], output[3];
  short i, ixinput;
  Boolean flignore, flendtext = false;
  const char *temporary;
  NSMutableData *result;

  if (!string)
    return [NSData data];

  ixtext = 0;
  temporary = [string UTF8String];
  lentext = [string length];
  result = [NSMutableData dataWithCapacity: lentext];
  ixinput = 0;

  while (true) {
    if (ixtext >= lentext)
      break;
    ch = temporary[ixtext++];
    flignore = false;

    if ((ch >= 'A') && (ch <= 'Z'))
      ch = ch - 'A';
    else if ((ch >= 'a') && (ch <= 'z'))
      ch = ch - 'a' + 26;
    else if ((ch >= '0') && (ch <= '9'))
      ch = ch - '0' + 52;
    else if (ch == '+')
      ch = 62;
    else if (ch == '=')
      flendtext = true;
    else if (ch == '/')
      ch = 63;
    else
      flignore = true;

    if (!flignore) {
      short ctcharsinput = 3;
      Boolean flbreak = false;

      if (flendtext) {
         if (ixinput == 0)
           break;              
         if ((ixinput == 1) || (ixinput == 2))
           ctcharsinput = 1;
         else
           ctcharsinput = 2;
         ixinput = 3;
         flbreak = true;
      }

      input[ixinput++] = ch;

      if (ixinput == 4){
        ixinput = 0;
        output[0] = (input[0] << 2) | ((input[1] & 0x30) >> 4);
        output[1] = ((input[1] & 0x0F) << 4) | ((input[2] & 0x3C) >> 2);
        output[2] = ((input[2] & 0x03) << 6) | (input[3] & 0x3F);
        for (i = 0; i < ctcharsinput; i++)
        [result appendBytes: &output[i] length: 1];
      }
    if (flbreak)
      break;
    }
  }
  return result;
}
@end


2

İşte NSData'da Kategori olarak kompakt bir Objective-C sürümü. Biraz düşünmek gerekiyor ...

@implementation NSData (DataUtils)

static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

- (NSString *)newStringInBase64FromData
{
 NSMutableString *dest = [[NSMutableString alloc] initWithString:@""];
 unsigned char * working = (unsigned char *)[self bytes];
 int srcLen = [self length];

 // tackle the source in 3's as conveniently 4 Base64 nibbles fit into 3 bytes
 for (int i=0; i<srcLen; i += 3)
 {
  // for each output nibble
  for (int nib=0; nib<4; nib++)
  {
   // nibble:nib from char:byt
   int byt = (nib == 0)?0:nib-1;
   int ix = (nib+1)*2;

   if (i+byt >= srcLen) break;

   // extract the top bits of the nibble, if valid
   unsigned char curr = ((working[i+byt] << (8-ix)) & 0x3F);

   // extract the bottom bits of the nibble, if valid
   if (i+nib < srcLen) curr |= ((working[i+nib] >> ix) & 0x3F);

   [dest appendFormat:@"%c", base64[curr]];
  }
 }

 return dest;
}

@end

Gerekirse dolgu, 'byt' kapsamını genişleterek ve dönüşten önce (2-byt) "=" karakterleriyle 'dest' ekleyerek eklenebilir.

Daha sonra NSString'e bir Kategori eklenebilir, böylece:

@implementation NSString (StringUtils)

- (NSString *)newStringInBase64FromString
{
 NSData *theData = [NSData dataWithBytes:[self UTF8String] length:[self length]]; 

 return [theData newStringInBase64FromData];
}

@end

2

iOS, iOS 4'ten beri yerleşik Base64 kodlama ve kod çözme yöntemlerine (libresolv kullanmadan) sahiptir. Ancak, yalnızca iOS 7 SDK'da bildirilmiştir. Apple belgeleri, iOS 4 ve daha üstünü hedeflerken kullanabileceğinizi belirtiyor.

NSData *myData = ... some data
NSString *base64String = [myData base64Encoding];
NSData *decodedData = [[NSData alloc] initWithBase64Encoding:base64String];

2

İşte bir NSData nesnesini Base 64'e dönüştürmek için bir örnek. Aynı zamanda nasıl gidileceğini de gösterir (base 64 kodlu NSData nesnesinin kodunu çözer):

NSData *dataTake2 = 
  [@"iOS Developer Tips" dataUsingEncoding:NSUTF8StringEncoding];

// Convert to Base64 data
NSData *base64Data = [dataTake2 base64EncodedDataWithOptions:0];

// Do something with the data...

// Now convert back from Base64
NSData *nsdataDecoded = [base64Data initWithBase64EncodedData:base64Data options:0];

1

iOS 7'de

        NSData *data=[[NSData alloc]init];
        [data base64Encoding];

Nagaraj bundan daha önce bahsetti. Yazısına ve iOS 4'ten beri orada olduğunu belirten açıklamalara bakın
jww

1

Aşağıdaki sınıfı kullanarak yaptım ..

@implementation Base64Converter
static char base64EncodingTable[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',  'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',    '8', '9', '+', '/'
};
+ (NSString *) base64StringFromData: (NSData *)data length: (int)length {

unsigned long ixtext, lentext;

long ctremaining;

unsigned char input[3], output[4];

short i, charsonline = 0, ctcopy;

const unsigned char *raw;

NSMutableString *result;

lentext = [data length];

if (lentext < 1)
    return @"";

result = [NSMutableString stringWithCapacity: lentext];

raw = [data bytes];

ixtext = 0;

while (true) {

    ctremaining = lentext - ixtext;

    if (ctremaining <= 0)
        break;

    for (i = 0; i < 3; i++) {
        unsigned long ix = ixtext + i;
        if (ix < lentext)
            input[i] = raw[ix];
        else
            input[i] = 0;
    }

    output[0] = (input[0] & 0xFC) >> 2;

    output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);

    output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);

    output[3] = input[2] & 0x3F;

    ctcopy = 4;

    switch (ctremaining) {
        case 1:
            ctcopy = 2;
            break;

        case 2:
            ctcopy = 3;
            break;
    }

    for (i = 0; i < ctcopy; i++)
        [result appendString: [NSString stringWithFormat: @"%c", base64EncodingTable[output[i]]]];

    for (i = ctcopy; i < 4; i++)
        [result appendString: @"="];

    ixtext += 3;

    charsonline += 4;

    if ((length > 0) && (charsonline >= length))
        charsonline = 0;
}
return result;
}
@end

Görüşme sırasında

 [Base64Converter base64StringFromData:dataval length:lengthval];

Bu kadar...


1

Bunun yararlı olacağını düşünüyorum

 + (NSString *)toBase64String:(NSString *)string {
    NSData *data = [string dataUsingEncoding: NSUnicodeStringEncoding];

    NSString *ret = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];

    return ret;
    }

    + (NSString *)fromBase64String:(NSString *)string {
NSData *aData = [string dataUsingEncoding:NSUTF8StringEncoding];
NSData *aDataDecoded = [[NSData alloc]initWithBase64EncodedString:string options:0];
NSString *decryptedStr = [[NSString alloc]initWithData:aDataDecoded encoding:NSUTF8StringEncoding];

return [decryptedStr autorelease];

}


NSStringUtil? Lütfen tam bir cevap verin?
Mohsin Khubaib Ahmed

1
Bu, herhangi bir Sınıfta yazmanız gereken iki yöntemdir ve onu çağırabilir ve parametre olarak String instaces iletebilirsiniz.
Mrug

0

Base64 indir

Bir resmi base64'e dönüştürmek için aşağıdaki kodu yapın

NSString *base64String=[UIImagePNGRepresentation(image) base64Encoding];

0

Gereksiniminize göre, dize ve görüntüyü gereksiniminize göre kodlayabileceğiniz / çözebileceğiniz Swift 4'ü kullanarak örnek bir demo oluşturdum .

  • Ayrıca ilgili operasyonların örnek yöntemlerini de ekledim.

    //
    //  Base64VC.swift
    //  SOF_SortArrayOfCustomObject
    //
    //  Created by Test User on 09/01/18.
    //  Copyright © 2018 Test User. All rights reserved.
    //
    
    import UIKit
    import Foundation
    
    class Base64VC: NSObject {
    
        //----------------------------------------------------------------
        // MARK:-
        // MARK:- String to Base64 Encode Methods
        //----------------------------------------------------------------
    
        func sampleStringEncodingAndDecoding() {
            if let base64String = self.base64Encode(string: "TestString") {
                print("Base64 Encoded String: \n\(base64String)")
                if let originalString = self.base64Decode(base64String: base64String) {
                    print("Base64 Decoded String: \n\(originalString)")
                }
            }
        }
    
    
        //----------------------------------------------------------------
    
        func base64Encode(string: String) -> String? {
            if let stringData = string.data(using: .utf8) {
                return stringData.base64EncodedString()
            }
            return nil
        }
    
        //----------------------------------------------------------------
    
        func base64Decode(base64String: String) -> String? {
            if let base64Data = Data(base64Encoded: base64String) {
                return String(data: base64Data, encoding: .utf8)
            }
            return nil
        }
    
    
        //----------------------------------------------------------------
        // MARK:-
        // MARK:- Image to Base64 Encode  Methods
        //----------------------------------------------------------------
    
        func sampleImageEncodingAndDecoding() {
            if let base64ImageString = self.base64Encode(image: UIImage.init(named: "yourImageName")!) {
                print("Base64 Encoded Image: \n\(base64ImageString)")
                if let originaImage = self.base64Decode(base64ImageString: base64ImageString) {
                    print("originalImageData \n\(originaImage)")
                }
            }
        }
    
        //----------------------------------------------------------------
    
        func base64Encode(image: UIImage) -> String? {
            if let imageData = UIImagePNGRepresentation(image) {
                return imageData.base64EncodedString()
            }
            return nil
        }
    
        //----------------------------------------------------------------
    
        func base64Decode(base64ImageString: String) -> UIImage? {
            if let base64Data = Data(base64Encoded: base64ImageString) {
                return UIImage(data: base64Data)!
            }
            return nil
        }
    
    
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.