Кодирование и декодирование в формате Base64
============================================

**Base64** - это группа схожих binary-to-text encoding схем, которые представляют двоичные данные в ASCII-формате методом перевода в radix-64 представление. Термин *Base64* происходит от a specific MIME content transfer encoding.

Кодирование Base64 широко используется в случаях, когда требуется перекодировать двоичные данные для передачи по каналу приспособленному для передачи текстовых данных. Это делается с целью защиты двоичных данных от любых возможных повреждений при передаче. Base64 широко используется во многих приложениях, включая электронную почту (MIME), и при сохранении больших объёмов данных в XML (en-US).

В языке JavaScript существуют две функции, для кодирования и декодирования данных в/из формат Base64 соответственно:

* `btoa()`
* `atob()` (en-US)

`Функция atob()` декодирует Base64-кодированную строку. В противоположность ей, функция `btoa()` создаёт Base64 кодированную ASCII строку из "строки" бинарных данных.

Обе функции `atob()` и `btoa()` работают со строками. Если вам необходимо работать с `ArrayBuffers`, обратитесь к этому параграфу.

Документация
------------

`data` URIs (en-US)

`data` URIs, описанные в RFC 2397, позволяют создателям контента встроить в документ маленькие файлы в виде строки (инлайном).

Base64

Wikipedia article about Base64 encoding.

`atob()` (en-US)

Decodes a string of data which has been encoded using base-64 encoding.

`btoa()`

Creates a base-64 encoded ASCII string from a "string" of binary data.

The "Unicode Problem"

In most browsers, calling `btoa()` on a Unicode string will cause a `Character Out Of Range` exception. This paragraph shows some solutions.

URIScheme

List of Mozilla supported URI schemes

`StringView`

In this article is published a library of ours whose aims are:

* creating a C-like interface for strings (i.e. array of characters codes — `ArrayBufferView` (en-US) in JavaScript) based upon the JavaScript `ArrayBuffer` (en-US) interface,
* creating a collection of methods for such string-like objects (since now: `stringView`s) which work **strictly on array of numbers** rather than on immutable JavaScript strings,
* working with other Unicode encodings, different from default JavaScript's UTF-16 `DOMString`s,

Tools
-----

* Rewriting `atob()` and `btoa()` using `TypedArray`s and UTF-8
* `StringView` – a C-like representation of strings based on typed arrays
Related Topics
--------------

* `ArrayBuffer` (en-US)
* Typed arrays
* `ArrayBufferView` (en-US)
* `Uint8Array` (en-US)
* `StringView` – a C-like representation of strings based on typed arrays
* `DOMString`
* `URI` (en-US)
* `encodeURI()`
The "Unicode Problem"
---------------------

Since `DOMString`s are 16-bit-encoded strings, in most browsers calling `window.btoa` on a Unicode string will cause a `Character Out Of Range` exception if a character exceeds the range of a 8-bit byte (0x00~0xFF). There are two possible methods to solve this problem:

* the first one is to escape the whole string (with UTF-8, see `encodeURIComponent`) and then encode it;
* the second one is to convert the UTF-16 `DOMString` to an UTF-8 array of characters and then encode it.

Here are the two possible methods.

### Solution #1 – escaping the string before encoding it


```js
function b64EncodeUnicode(str) {
  // first we use encodeURIComponent to get percent-encoded UTF-8,
  // then we convert the percent encodings into raw bytes which
  // can be fed into btoa.
  return btoa(
    encodeURIComponent(str).replace(
      /%([0-9A-F]{2})/g,
      function toSolidBytes(match, p1) {
        return String.fromCharCode("0x" + p1);
      },
    ),
  );
}

b64EncodeUnicode("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU="
b64EncodeUnicode("\n"); // "Cg=="
```


To decode the Base64-encoded value back into a String:


```js
function b64DecodeUnicode(str) {
  // Going backwards: from bytestream, to percent-encoding, to original string.
  return decodeURIComponent(
    atob(str)
      .split("")
      .map(function (c) {
        return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
      })
      .join(""),
  );
}

b64DecodeUnicode("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode"
b64DecodeUnicode("Cg=="); // "\n"
```


Unibabel implements common conversions using this strategy.

### Solution #2 – rewrite the DOMs `atob()` and `btoa()` using JavaScript's `TypedArray`s and UTF-8

Use a TextEncoder (en-US) polyfill such as TextEncoding (also includes legacy windows, mac, and ISO encodings), TextEncoderLite, combined with a Buffer and a Base64 implementation such as base64-js.

When a native `TextEncoder` implementation is not available, the most light-weight solution would be to use TextEncoderLite with base64-js. Use the browser implementation when you can.

The following function implements such a strategy. It assumes base64-js imported as `<script type="text/javascript" src="base64js.min.js"/>`. Note that TextEncoderLite only works with UTF-8.


```js
function Base64Encode(str, encoding = "utf-8") {
  var bytes = new (TextEncoder || TextEncoderLite)(encoding).encode(str);
  return base64js.fromByteArray(bytes);
}

function Base64Decode(str, encoding = "utf-8") {
  var bytes = base64js.toByteArray(str);
  return new (TextDecoder || TextDecoderLite)(encoding).decode(bytes);
}
```