Bug #967: Base 64
| From: | drew at elysium dot demon dot co dot uk | Date: | Thu, 03 Dec 1998 15:55:14 +0000 |
| Subject: | Bug #967: Base 64 | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-2645@lists.php.net to get a copy of this message | ||
From: drew@elysium.demon.co.uk
Operating system: Linux 2.0.xx
PHP version: 3.0.5
PHP Bug Type: Other
Bug description: Base 64
I have been base64 encoding some reasonably large files using the base64_encode function and the
encoded string gets returned as one long string. I had a look at RFC2045 (as mentioned in the
manual documenting either base64_encode or base64_decode) and it mentions that a line in the encoded
string should be no longer than 76 chars and also that when decoding an encoded string then
whitespace and newlines should be ignored. Anyway splitting a large base64 encoded string into 76
character lines is very slow if done in the following way :-
$encode = base64_Encode($data);
while (strLen($encode)) {
$mail .= subStr($encode, 0, 76);
$encode = subStr($encode, 76);
}
So I include a patch to make base64_encode & base64_decode a little more RFC2045 compliant,
please let me know if there are any problems with doing this. Included in this patch is a fix for
an extra byte problem in base64_decode (the j++ is done in the 'upper' case 3:, so its is
not needed in the 'lower' case 3: - I think)
--- base64.c.orig Thu Dec 3 14:45:13 1998
+++ base64.c Thu Dec 3 15:47:43 1998
@@ -45,19 +45,30 @@
'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '+', '/',
'\0'
};
static char base64_pad = '=';
+static char base64_newline = '\n';
unsigned char *_php3_base64_encode(const unsigned char *string, int length, int *ret_length) {
const unsigned char *current = string;
int i = 0;
- unsigned char *result = (unsigned char *)emalloc(((length + 3 - length % 3) * 4 / 3 + 1) *
sizeof(char));
+ size_t emalloc_length = 0;
+ unsigned char *result;
+
+ emalloc_length += ((length + 3 - length % 3) * 4 / 3 + 1) * sizeof(char);
+ emalloc_length += (((emalloc_length - 1) / 76) + 1) * sizeof(char);
+ result = (unsigned char *)emalloc(emalloc_length);
while (length > 2) { /* keep going until we have less than 24 bits */
result[i++] = base64_table[current[0] >> 2];
result[i++] = base64_table[((current[0] & 0x03) << 4) + (current[1]
>> 4)];
result[i++] = base64_table[((current[1] & 0x0f) << 2) + (current[2]
>> 6)];
result[i++] = base64_table[current[2] & 0x3f];
-
current += 3;
+ /* if we are a multiple of 57 bytes away from the start of the
+ source string (which translates into 76 bytes away from the
+ start of the destination) then add a line feed */
+ if (!((current - string) % 57))
+ result[i++] = base64_newline;
+
length -= 3; /* we just handle 3 octets of data */
}
@@ -75,10 +86,12 @@
result[i++] = base64_pad;
}
}
- if(ret_length) {
+ result[i++] = base64_newline;
+ result[i] = '\0';
+
+ if (ret_length) {
*ret_length = i;
}
- result[i] = '\0';
return result;
}
@@ -86,8 +99,12 @@
unsigned char *_php3_base64_decode(const unsigned char *string, int length, int *ret_length) {
const unsigned char *current = string;
int ch, i = 0, j = 0;
+ size_t emalloc_length = 0;
+ unsigned char *result;
+
+ emalloc_length = (length / 4 * 3 + 1) * sizeof(char);
+ result = (unsigned char *)emalloc(emalloc_length);
- unsigned char *result = (unsigned char *)emalloc((length / 4 * 3 + 1) * sizeof(char));
if (result == NULL) {
return NULL;
}
@@ -95,6 +112,7 @@
/* run through the whole string, converting as we go */
while ((ch = *current++) != '\0') {
if (ch == base64_pad) break;
+ if (ch == base64_newline || ch == ' ' || ch == '\t') continue;
ch = (int)strchr(base64_table, ch);
if (ch == 0) {
efree(result);
@@ -130,14 +148,13 @@
return NULL;
case 2:
j++;
- case 3:
- result[j++] = 0;
}
}
- if(ret_length) {
+ result[j] = '\0';
+
+ if (ret_length) {
*ret_length = j;
}
- result[j] = '\0';
return result;
}
--
PHP Development Mailing List http://www.php.net/
To unsubscribe send an empty message to php-dev-unsubscribe@lists.php.net
For help: php-dev-help@lists.php.net