Function: base64-decode-region

base64-decode-region is an interactive function defined in fns.c.

Signature

(base64-decode-region BEG END &optional BASE64URL IGNORE-INVALID)

Documentation

Base64-decode the region between BEG and END.

Return the length of the decoded data.

Note that after calling this function, the data in the region will represent bytes, not text. If you want to end up with text, you have to call decode-coding-region afterwards with an appropriate coding system.

If the region can't be decoded, signal an error and don't modify the buffer. Optional third argument BASE64URL determines whether to use the URL variant of the base 64 encoding, as defined in RFC 4648. If optional fourth argument IGNORE-INVALID is non-nil invalid characters are ignored instead of signaling an error.

View in manual

Probably introduced at or before Emacs version 20.4.

Key Bindings

Source Code

// Defined in /usr/src/emacs/src/fns.c
{
  ptrdiff_t ibeg, iend, length, allength;
  char *decoded;
  ptrdiff_t old_pos = PT;
  ptrdiff_t decoded_length;
  ptrdiff_t inserted_chars;
  bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
  USE_SAFE_ALLOCA;

  validate_region (&beg, &end);

  ibeg = CHAR_TO_BYTE (XFIXNAT (beg));
  iend = CHAR_TO_BYTE (XFIXNAT (end));

  length = iend - ibeg;

  /* We need to allocate enough room for decoding the text.  If we are
     working on a multibyte buffer, each decoded code may occupy at
     most two bytes.  */
  allength = multibyte ? length * 2 : length;
  decoded = SAFE_ALLOCA (allength);

  move_gap_both (XFIXNAT (beg), ibeg);
  decoded_length = base64_decode_1 ((char *) BYTE_POS_ADDR (ibeg),
				    decoded, length, !NILP (base64url),
				    multibyte, !NILP (ignore_invalid),
				    &inserted_chars);
  if (decoded_length > allength)
    emacs_abort ();

  if (decoded_length < 0)
    {
      /* The decoding wasn't possible. */
      error ("Invalid base64 data");
    }

  /* Now we have decoded the region, so we insert the new contents
     and delete the old.  (Insert first in order to preserve markers.)  */
  TEMP_SET_PT_BOTH (XFIXNAT (beg), ibeg);
  insert_1_both (decoded, inserted_chars, decoded_length, 0, 1, 0);
  signal_after_change (XFIXNAT (beg), 0, inserted_chars);
  SAFE_FREE ();

  /* Delete the original text.  */
  del_range_both (PT, PT_BYTE, XFIXNAT (end) + inserted_chars,
		  iend + decoded_length, 1);

  /* If point was outside of the region, restore it exactly; else just
     move to the beginning of the region.  */
  if (old_pos >= XFIXNAT (end))
    old_pos += inserted_chars - (XFIXNAT (end) - XFIXNAT (beg));
  else if (old_pos > XFIXNAT (beg))
    old_pos = XFIXNAT (beg);
  SET_PT (old_pos > ZV ? ZV : old_pos);

  return make_fixnum (inserted_chars);
}