ext/iodine/fio.c
/**
This will decode a Base64 encoded string of a specified length (len) and
place the decoded data into the target byte buffer (target).

The target buffer MUST have enough room for the expected data.

A NULL byte will be appended to the target buffer. The function will return
the number of bytes written to the target buffer.

If the target buffer is NULL, the encoded string will be destructively edited
and the decoded data will be placed in the original string's buffer.

Base64 encoding always requires 4 bytes for each 3 bytes. Padding is added if
the raw data's length isn't devisable by 3. Hence, the target buffer should
be, at least, `base64_len/4*3 + 3` long.

Returns the number of bytes actually written to the target buffer (excluding
the NULL terminator byte).

If an error occurred, returns the number of bytes written up to the error. Test
`errno` for error (will be set to ERANGE).
*/
This will decode a Base64 encoded string of a specified length (len) and
place the decoded data into the target byte buffer (target).

The target buffer MUST have enough room for the expected data.

A NULL byte will be appended to the target buffer. The function will return
the number of bytes written to the target buffer.

If the target buffer is NULL, the encoded string will be destructively edited
and the decoded data will be placed in the original string's buffer.

Base64 encoding always requires 4 bytes for each 3 bytes. Padding is added if
the raw data's length isn't devisable by 3. Hence, the target buffer should
be, at least, `base64_len/4*3 + 3` long.

Returns the number of bytes actually written to the target buffer (excluding
the NULL terminator byte).

If an error occurred, returns the number of bytes written up to the error. Test
`errno` for error (will be set to ERANGE).
This will decode a Base64 encoded string of a specified length ( len ) and place the decoded data into the target byte buffer ( target ) . The target buffer MUST have enough room for the expected data . A NULL byte will be appended to the target buffer . The function will return the number of bytes written to the target buffer . If the target buffer is NULL the encoded string will be destructively edited and the decoded data will be placed in the original string ' s buffer . Base64 encoding always requires 4 bytes for each 3 bytes . Padding is added if the raw data ' s length isn ' t devisable by 3 . Hence the target buffer should be at least ` base64_len / 4 * 3 + 3 ` long . Returns the number of bytes actually written to the target buffer ( excluding the NULL terminator byte ) . If an error occurred returns the number of bytes written up to the error . Test ` errno ` for error ( will be set to ERANGE ) .
int fio_base64_decode(char *target, char *encoded, int base64_len) {
  if (!target)
    target = encoded;
  if (base64_len <= 0) {
    target[0] = 0;
    return 0;
  }
  int written = 0;
  uint8_t tmp1, tmp2, tmp3, tmp4;
  while (base64_len &&
         !base64_decodes[*(uint8_t *)(encoded + (base64_len - 1))]) {
    base64_len--;
  }
  while (base64_len && isspace((*(uint8_t *)encoded))) {
    base64_len--;
    encoded++;
  }
  while (base64_len >= 4) {
    if (!base64_len) {
      return written;
    }
    tmp1 = *(uint8_t *)(encoded++);
    tmp2 = *(uint8_t *)(encoded++);
    tmp3 = *(uint8_t *)(encoded++);
    tmp4 = *(uint8_t *)(encoded++);
    if (!base64_decodes[tmp1] || !base64_decodes[tmp2] ||
        !base64_decodes[tmp3] || !base64_decodes[tmp4]) {
      errno = ERANGE;
      goto finish;
    }
    *(target++) = (BITVAL(tmp1) << 2) | (BITVAL(tmp2) >> 4);
    *(target++) = (BITVAL(tmp2) << 4) | (BITVAL(tmp3) >> 2);
    *(target++) = (BITVAL(tmp3) << 6) | (BITVAL(tmp4));
    base64_len -= 4;
    written += 3;
    while (base64_len && isspace((*encoded))) {
      base64_len--;
      encoded++;
    }
  }
  tmp1 = 0;
  tmp2 = 0;
  tmp3 = 0;
  tmp4 = 0;
  switch (base64_len) {
  case 1:
    tmp1 = *(uint8_t *)(encoded++);
    if (!base64_decodes[tmp1]) {
      errno = ERANGE;
      goto finish;
    }
    *(target++) = BITVAL(tmp1);
    written += 1;
    break;
  case 2:
    tmp1 = *(uint8_t *)(encoded++);
    tmp2 = *(uint8_t *)(encoded++);
    if (!base64_decodes[tmp1] || !base64_decodes[tmp2]) {
      errno = ERANGE;
      goto finish;
    }
    *(target++) = (BITVAL(tmp1) << 2) | (BITVAL(tmp2) >> 6);
    *(target++) = (BITVAL(tmp2) << 4);
    written += 2;
    break;
  case 3:
    tmp1 = *(uint8_t *)(encoded++);
    tmp2 = *(uint8_t *)(encoded++);
    tmp3 = *(uint8_t *)(encoded++);
    if (!base64_decodes[tmp1] || !base64_decodes[tmp2] ||
        !base64_decodes[tmp3]) {
      errno = ERANGE;
      goto finish;
    }
    *(target++) = (BITVAL(tmp1) << 2) | (BITVAL(tmp2) >> 6);
    *(target++) = (BITVAL(tmp2) << 4) | (BITVAL(tmp3) >> 2);
    *(target++) = BITVAL(tmp3) << 6;
    written += 3;
    break;
  }
finish:
  if (encoded[-1] == '=') {
    target--;
    written--;
    if (encoded[-2] == '=') {
      target--;
      written--;
    }
    if (written < 0)
      written = 0;
  }
  *target = 0;
  return written;
}
int fio_base64_decode ( char * target , char * encoded , int base64_len ) { if ( ! target ) target = encoded ; if ( base64_len <= 0 ) { target [ 0 ] = 0 ; return 0 ; } int written = 0 ; uint8_t tmp1 , tmp2 , tmp3 , tmp4 ; while ( base64_len && ! base64_decodes [ * ( uint8_t * ) ( encoded + ( base64_len - 1 ) ) ] ) { base64_len -- ; } while ( base64_len && isspace ( ( * ( uint8_t * ) encoded ) ) ) { base64_len -- ; encoded ++ ; } while ( base64_len >= 4 ) { if ( ! base64_len ) { return written ; } tmp1 = * ( uint8_t * ) ( encoded ++ ) ; tmp2 = * ( uint8_t * ) ( encoded ++ ) ; tmp3 = * ( uint8_t * ) ( encoded ++ ) ; tmp4 = * ( uint8_t * ) ( encoded ++ ) ; if ( ! base64_decodes [ tmp1 ] || ! base64_decodes [ tmp2 ] || ! base64_decodes [ tmp3 ] || ! base64_decodes [ tmp4 ] ) { errno = ERANGE ; goto finish ; } * ( target ++ ) = ( BITVAL ( tmp1 ) << 2 ) | ( BITVAL ( tmp2 ) >> 4 ) ; * ( target ++ ) = ( BITVAL ( tmp2 ) << 4 ) | ( BITVAL ( tmp3 ) >> 2 ) ; * ( target ++ ) = ( BITVAL ( tmp3 ) << 6 ) | ( BITVAL ( tmp4 ) ) ; base64_len -= 4 ; written += 3 ; while ( base64_len && isspace ( ( * encoded ) ) ) { base64_len -- ; encoded ++ ; } } tmp1 = 0 ; tmp2 = 0 ; tmp3 = 0 ; tmp4 = 0 ; switch ( base64_len ) { case 1 : tmp1 = * ( uint8_t * ) ( encoded ++ ) ; if ( ! base64_decodes [ tmp1 ] ) { errno = ERANGE ; goto finish ; } * ( target ++ ) = BITVAL ( tmp1 ) ; written += 1 ; break ; case 2 : tmp1 = * ( uint8_t * ) ( encoded ++ ) ; tmp2 = * ( uint8_t * ) ( encoded ++ ) ; if ( ! base64_decodes [ tmp1 ] || ! base64_decodes [ tmp2 ] ) { errno = ERANGE ; goto finish ; } * ( target ++ ) = ( BITVAL ( tmp1 ) << 2 ) | ( BITVAL ( tmp2 ) >> 6 ) ; * ( target ++ ) = ( BITVAL ( tmp2 ) << 4 ) ; written += 2 ; break ; case 3 : tmp1 = * ( uint8_t * ) ( encoded ++ ) ; tmp2 = * ( uint8_t * ) ( encoded ++ ) ; tmp3 = * ( uint8_t * ) ( encoded ++ ) ; if ( ! base64_decodes [ tmp1 ] || ! base64_decodes [ tmp2 ] || ! base64_decodes [ tmp3 ] ) { errno = ERANGE ; goto finish ; } * ( target ++ ) = ( BITVAL ( tmp1 ) << 2 ) | ( BITVAL ( tmp2 ) >> 6 ) ; * ( target ++ ) = ( BITVAL ( tmp2 ) << 4 ) | ( BITVAL ( tmp3 ) >> 2 ) ; * ( target ++ ) = BITVAL ( tmp3 ) << 6 ; written += 3 ; break ; } finish : if ( encoded [ -1 ] == ' ' ) { target -- ; written -- ; if ( encoded [ -2 ] == ' ' ) { target -- ; written -- ; } if ( written < 0 ) written = 0 ; } * target = 0 ; return written ; }
This will decode a Base64 encoded string of a specified length (len) and
place the decoded data into the target byte buffer (target).
This will decode a Base64 encoded string of a specified length ( len ) and place the decoded data into the target byte buffer ( target ) .
// skip unknown data at end // skip white space // make sure we don't loop forever. // count written bytes // skip white space // deal with the "tail" of the mis-encoded stream - this shouldn't happen