iOS에서 base64 인코딩을 어떻게 수행합니까?


230

내가 할 싶습니다 base64인코딩 및 디코딩,하지만 난 아이폰에서 어떤 지원을 찾을 수 없습니다 SDK. base64라이브러리를 사용하거나 사용하지 않고 인코딩 및 디코딩을 어떻게 수행 할 수 있습니까?


1
이 게시물의 맨 아래에는 멋진 코드 샘플이 있습니다. 매우 독립적 인 ... BaseSixtyFour
Greg Bernhardt

@GregBernhardt 링크가 죽었습니다.
Cœur

답변:


116

이것은 Objective C 범주에 대한 좋은 사용 사례입니다 .

Base64 인코딩의 경우 :

#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 디코딩의 경우 :

#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와 같은 경우 다음을 수행 할 수 있어야합니다. static char base64EncodingTable [64] = "ABCDE [etc] 789 + /";
Artelius 2009

3
4 자만 가져 오는 이유를 찾았습니다. while () 루프를 반환하기 전에}가 있어야합니다. 편집 할 수는 있지만 할 수없는 것처럼 보입니다.
Larry Hipp 2016 년

3
분석기 버그가 아닙니다. 또한 코드는 해당 배열의 범위를 벗어난 inbuf [3]에 액세스하려고 시도합니다. 이 코드는 악취가납니다.
Mike Weller

1
길이 값은 무엇을 나타 냅니까?
MegaManX 2016 년

3
iOS7부터 Apple은 기본 base 64 인코딩 방법을 공개했습니다. 하위 호환성을 유지하면서 사용하는 방법에 대해서는 아래의 Rob의 답변을 참조하십시오.
코드 사령관

100

PHP Core 라이브러리에서 네이티브 Objective-C 코드로 포팅 (및 수정 / 개선) 된, 실제로 매우 빠른 구현 은 QSUtilities LibraryQSStrings 클래스 에서 사용할 수 있습니다 . 빠른 벤치 마크를 수행했습니다. 5.3MB 이미지 (JPEG) 파일은 인코딩하는 데 50ms 미만, 디코딩하는 데 약 140ms가 걸렸습니다.

전체 라이브러리에 대한 코드 (Base64 메서드 포함)는 GitHub에서 사용할 수 있습니다 .

또는 코드를 Base64 메서드 에만 적용 하려면 여기에 게시했습니다.

먼저 매핑 테이블이 필요합니다.

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
};

인코딩하려면 :

+ (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;
}

디코딩하려면 :

+ (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
마지막으로 정확하고 효율적인 구현입니다. 감사. 여기에있는 다른 코드 중 일부는 나를 두려워합니다.
Mike Weller

4
strResult인코더에서 할당 된 메모리 가 누출 된 것 같습니다. 그것은 단지 free()끝에 ( 그것이 돌아 오기 전이나 후에 NSString stringWithCString) 필요합니다
JosephH

2
당신에 encodeBase64WithData:방법에 대한 호출의 첫 번째 매개 변수하지 않습니다 calloc()필요가 널 터미네이터 (대한 계정에 1 씩 증가합니다 '\0') 당신이 마지막에 추가?
erikprice

1
사과가 이것을 제공하지 않는다는 사실로 인해 하나님은 새끼 고양이를 살해하고 싶어하십니다. 많은 고양이들 ...
dsingleton

2
나는 이것을 잠시 동안 사용하고 있으며 메모리 손상 관련 오류가 발생하고 guard malloc을 사용하기 시작할 때까지 훌륭하게 작동하는 것 같습니다. * objPointer = '\ 0'; 자신의 앱에서 사용하는 경우주의하십시오.
Mattia

72

역사적으로 우리는 이진 데이터에서 기본 64 문자열로 변환하는 많은 타사 기본 64 라이브러리 중 하나를 안내했지만 iOS 7에는 기본 기본 인코딩이 있습니다 (및 이전 버전의 iOS를 지원 해야하는 경우 이전에 비공개 iOS 4 방법을 노출합니다.

따라서 기본 64 표현 으로 변환 NSData하려면 NSString사용할 수 있습니다 base64EncodedStringWithOptions. 7.0 이전의 iOS 버전도 지원해야하는 경우 다음을 수행 할 수 있습니다.

NSString *string;

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

그리고 base 64를 NSString다시 변환하기 위해 NSData사용할 수 있습니다 initWithBase64EncodedString. 마찬가지로 7.0 이전의 iOS 버전을 지원해야하는 경우 다음을 수행 할 수 있습니다.

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
}

당신이 아이폰 OS 버전 7.0 이전과의 호환성을 필요로하지 않는 경우에 분명히, 그냥 사용에도 쉽게 base64EncodedStringWithOptions또는 initWithBase64EncodedString각각 이전의 iOS 버전에 대한 런타임 검사로 귀찮게하지 않습니다. 실제로 최소 대상이 iOS 7 이상일 때 위의 코드를 사용하면 실제로 사용되지 않는 메소드에 대한 컴파일러 경고가 표시됩니다. 따라서 iOS 7 이상에서는 다음을 사용하여 기본 64 문자열로 간단히 변환합니다.

NSString *string = [data base64EncodedStringWithOptions:kNilOptions];

다시 :

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

롭 고마워 " ... 그리고 이전에 개인 iOS 4 방법을 공개했다 "는 내용을 간략하게 설명해 주 시겠습니까?
phi

8
이 답변이 모든 사용자 정의 구현 아래에 묻혀있는 것은 부끄럽습니다. SO의 약점입니다. 원래 질문을 한 후에 더 적절한 해결책이 나왔을 수도 있습니다.이 솔루션은 이제 이전에 받아 들여진 것과 경쟁해야합니다.
jakev

항상 유용 이유는 최근 정답 : upvote에 해당
스티브 윌 포드 우드

이 같은 지옥 답변 :( 상단에없는 이유는, 내가 T__T 위의 모든 답변 처리 시간을 많이 소비
Alsh 컴파일러

33

iOS에는 base64 인코딩 및 디코딩 지원 기능이 내장되어 있습니다. 당신이 보면 resolv.h당신은 두 가지 기능을 참조해야 b64_ntop하고 b64_pton. Square SocketRocket 라이브러리는 objective-c에서 이러한 함수를 사용하는 방법에 대한 합리적인 예를 제공합니다.

이 기능은 임의의 인터넷 게시에서 찾을 수있는 많은 구현과 달리 테스트가 잘되고 안정적입니다. 에 링크하는 것을 잊지 마십시오 libresolv.dylib.


3
대박; 임의의 인터넷 사이트보다 훨씬 낫습니다! 이 문서로 작성된 기능을 사용하는 것이 걱정된다면 Apple 사이트에서 해당 기능의 소스를 확인할 수 있습니다 .
Jesse Rusak

1
이 사람은 그것에 대한 더 많은 배경을 제공합니다 : blog.montgomerie.net/ios-hidden-base64-routines
Mike

21

이것이 Google이 base64 인코딩 및 iPhone에서 가장 많이 사용하는 것으로 보이므로 위의 코드 스 니펫으로 내 경험을 공유하고 싶었습니다.

작동하지만 매우 느립니다. 임의의 이미지 (0.4mb)의 벤치 마크는 기본 iPhone에서 37 초가 걸렸습니다. 주된 이유는 아마도 모든 OOP 매직-단일 문자 NSString 등입니다. 인코딩이 완료된 후에 만 ​​자동 릴리스됩니다.

여기에 게시 된 또 다른 제안 (ab)은 openssl 라이브러리를 사용하며 과도하게 느껴집니다.

아래 코드는 70ms가 걸리며 500 배 속도가 빨라집니다. 이것은 base64 인코딩 만 수행합니다 (디코딩은 마주 치면 따라갑니다)

+ (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;
}

필요하지 않기 때문에 줄을 자르지 않았지만 추가하는 것은 쉽지 않습니다.

최적화에 관심이있는 사람들을 위해 : 목표는 메인 루프에서 일어나는 일을 최소화하는 것입니다. 따라서 마지막 3 바이트를 처리하는 모든 논리는 루프 외부에서 처리됩니다.

또한 버퍼로 /에서 추가로 복사하지 않고 내부 데이터 작업을 시도하십시오. 그리고 산술을 최소한으로 줄입니다.

테이블에서 항목을 조회하기 위해 조합 된 비트는 이동하지 않고 함께 정렬 될 때 겹치지 않습니다. 따라서 크게 개선 된 4 개의 256 바이트 룩업 테이블을 사용하고 다음과 같이 시프트를 제거 할 수 있습니다.

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];

물론 훨씬 더 나아갈 수는 있지만 여기서는 범위를 벗어납니다.


흠. 나는 이것을 작동시킬 수 없었다. 예상 값과 다른 base64 인코딩을 관찰했습니다. RFC 4648의 예제로 이것을 테스트 했습니까? tools.ietf.org/html/rfc4648
Alex Reynolds

3
어떤 base64EncodingTable1, base64EncodingTable2, base64EncodingTable3 및 base64EncodingTable4를 참조하려고 고심하고 있습니까?
Jamie Chapman

매우 유용하지만 입력 버퍼의 끝을 넘어 읽을 수 있습니다. (left == 2) 인 경우 raw [inp + 2]는 tmpbuf의 끝을 넘어 1 바이트가됩니다. 줄은 다음과 같아야합니다. if (left == 2) outbuf [outp ++] = base64EncodingTable [((raw [inp + 1] & 0x0F) << 2)];
John Lemberger

다음 라인 <code>를 변경 CHAR tmpbuf [2] = {0,0} </ 코드>를 <코드> 서명 숯불 tmpbuf [3] = {0,0,0} </ 코드>
사티

9

mvd의 뛰어난 개선에는 두 가지 문제가 있습니다. 다음과 같이 코드를 변경하십시오.

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

더 나은 솔루션 :

NSData에는 내장 함수가 있습니다

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

"[[UIDevice currentDevice] systemVersion] .floatValue"를 사용하여 앱이 실행중인 iOS 버전을 기반으로 할 수 있습니다.
Nagaraj

2
1. 그것은 당신이 어떤 SDK에 링크했는지 말하지 않을 것입니다, 그것은 런타임 점검입니다. 2. 이는 Apple의 지침과 직접적으로 관련이 있습니다. 시스템 버전이 아닌 기능의 가용성을 확인해야합니다.
quellish

6

기쁜 사람들은 그것을 좋아했습니다. 최종 게임은 내가 인정해야 할 약간의 결함이었다. inp = 0을 올바르게 설정하는 것 외에도 tmpbuf의 크기를 3으로 늘려야합니다.

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

또는 미가공 [inp + 2]의 오링을 제거 하거나 만약이 덩어리에 대해 raw [inp + 2]! = 0을 가지면 우리는 여전히 루프에있을 것입니다 ...

어느 쪽이 작동하든 명확성을 위해 최종 테이블 조회 블록을 루프의 블록과 동일하게 유지하는 것이 좋습니다. 내가 사용한 최종 버전에서 나는

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

==를 추가하려면

RFC와 내용을 확인하지 않아서 더 나은 작업을 수행해야합니다.


3
이전 답변이 실제로 다른 계정이므로 이미 계정이 있습니다. 또한 이것은 편집하거나 주석이어야합니다.
Alastair Pitts

@alastair, 쿠키를 청소 한 후 등록하지 않고 답변을 게시 할 때마다 "계정"이있는 것 같습니다. 첫 번째 "계정"(같은 이메일 및 IP 주소로도)에 연결할 수 없었기 때문에 새 답변으로 추가했습니다. 죄송합니다. -방금 등록했습니다!
mvds

3
이 답변을 이전 답변으로 편집하여 올바른 버전을 만들 수 있습니까? 감사!
JosephH

6

iOS8 이상 - (NSString *)base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)options에서 NSData 사용


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

다음은 NSData의 범주로서 컴팩트 한 Objective-C 버전입니다. 그것에 대해 약간의 생각이 필요합니다 ...

@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

필요한 경우 'byt'범위를 넓히고 리턴하기 전에 (2-byt) "="문자로 'dest'를 추가하여 패딩을 추가 할 수 있습니다.

그런 다음 카테고리를 NSString에 추가 할 수 있습니다.

@implementation NSString (StringUtils)

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

 return [theData newStringInBase64FromData];
}

@end

2

iOS는 iOS 4부터 기본 Base64 인코딩 및 디코딩 방법 (libresolv를 사용하지 않음)을 가지고 있습니다. 그러나 iOS 7 SDK에서만 선언되었습니다. Apple 설명서에는 iOS 4 이상을 대상으로 할 때 사용할 수 있다고 명시되어 있습니다.

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

2

다음은 NSData 객체를 Base 64로 변환하는 예입니다. 다른 방법 (기본 64 인코딩 NSData 객체를 디코딩)으로 이동하는 방법도 보여줍니다.

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에서

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

나가라지는 이미 이것을 언급했다. 그의 게시물과 iOS 4 이후로 그 내용을 언급 한 의견을 참조하십시오.
jww

1

다음 클래스를 사용하여 수행했습니다.

@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

전화를 거는 동안

 [Base64Converter base64StringFromData:dataval length:lengthval];

그게 다야 ...


1

도움이 될 것 같아요

 + (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? 완전한 답변을 제공 하시겠습니까?
Mohsin Khubaib Ahmed

1
이것은 모든 클래스에서 작성해야하는 두 가지 방법으로,이를 호출하여 String instaces를 매개 변수로 전달할 수 있습니다.
머그컵

0

Base64 다운로드

이미지를 base64로 변환하려면 다음 코드를 수행하십시오.

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

0

귀하의 요구 사항에 따라 Swift 4 를 사용하여 샘플 데모를 만들었습니다.이 데모에서는 요구 사항에 따라 문자열과 이미지를 인코딩 / 디코딩 할 수 있습니다.

  • 또한 관련 작업의 샘플 방법을 추가했습니다.

    //
    //  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
        }
    
    
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.