1 /* 2 * Copyright 2011-2013 Haiku, Inc. All rights reserved. 3 * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved. 4 */ 5 6 7 #include <mail_encoding.h> 8 9 #include <ctype.h> 10 #include <string.h> 11 #include <SupportDefs.h> 12 13 14 static const char kBase64Alphabet[64] = { 15 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 16 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 17 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 18 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 19 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 20 '+', 21 '/' 22 }; 23 24 25 ssize_t 26 encode_base64(char *out, const char *in, off_t length, int headerMode) 27 { 28 uint32 concat; 29 int i = 0; 30 int k = 0; 31 int lineLength = 4; 32 // Stop before it actually gets too long 33 34 while (i < length) { 35 concat = ((in[i] & 0xff) << 16); 36 37 if ((i+1) < length) 38 concat |= ((in[i+1] & 0xff) << 8); 39 if ((i+2) < length) 40 concat |= (in[i+2] & 0xff); 41 42 i += 3; 43 44 out[k++] = kBase64Alphabet[(concat >> 18) & 63]; 45 out[k++] = kBase64Alphabet[(concat >> 12) & 63]; 46 out[k++] = kBase64Alphabet[(concat >> 6) & 63]; 47 out[k++] = kBase64Alphabet[concat & 63]; 48 49 if (i >= length) { 50 int v; 51 for (v = 0; v <= (i - length); v++) 52 out[k-v] = '='; 53 } 54 55 lineLength += 4; 56 57 // No line breaks in header mode, since the text is part of a Subject: 58 // line or some other single header line. The header code will do word 59 // wrapping separately from this encoding stuff. 60 if (!headerMode && lineLength > BASE64_LINELENGTH) { 61 out[k++] = '\r'; 62 out[k++] = '\n'; 63 64 lineLength = 4; 65 } 66 } 67 68 return k; 69 } 70 71 72 ssize_t 73 decode_base64(char *out, const char *in, off_t length) 74 { 75 uint32 concat, value; 76 int lastOutLine = 0; 77 int i, j; 78 int outIndex = 0; 79 80 for (i = 0; i < length; i += 4) { 81 concat = 0; 82 83 for (j = 0; j < 4 && (i + j) < length; j++) { 84 value = in[i + j]; 85 86 if (value == '\n' || value == '\r') { 87 // jump over line breaks 88 lastOutLine = outIndex; 89 i++; 90 j--; 91 continue; 92 } 93 94 if ((value >= 'A') && (value <= 'Z')) 95 value -= 'A'; 96 else if ((value >= 'a') && (value <= 'z')) 97 value = value - 'a' + 26; 98 else if ((value >= '0') && (value <= '9')) 99 value = value - '0' + 52; 100 else if (value == '+') 101 value = 62; 102 else if (value == '/') 103 value = 63; 104 else if (value == '=') 105 break; 106 else { 107 // there is an invalid character in this line - we will 108 // ignore the whole line and go to the next 109 outIndex = lastOutLine; 110 while (i < length && in[i] != '\n' && in[i] != '\r') 111 i++; 112 concat = 0; 113 } 114 115 value = value << ((3-j)*6); 116 117 concat |= value; 118 } 119 120 if (j > 1) 121 out[outIndex++] = (concat & 0x00ff0000) >> 16; 122 if (j > 2) 123 out[outIndex++] = (concat & 0x0000ff00) >> 8; 124 if (j > 3) 125 out[outIndex++] = (concat & 0x000000ff); 126 } 127 128 return outIndex; 129 } 130 131 132 #if __GNUC__ <= 2 133 // BeOS-ABI compatible wrappers. 134 ssize_t encode_base64(char *out, char *in, off_t length) 135 { 136 return encode_base64(out, in, length, 0); 137 } 138 139 ssize_t decode_base64(char *out, const char *in, off_t length, 140 bool /*replace_cr*/) 141 { 142 return decode_base64(out, in, length); 143 } 144 #endif // __GNUC__ <= 2 145