http://stackoverflow.com/questions/13356493/decode-utf-8-with-javascript#13691499
496000
function toUtf8String(bytes, ignoreErrors) {
    bytes = bytes_1.arrayify(bytes);
    var result = '';
    var i = 0;
    // Invalid bytes are ignored
    while (i < bytes.length) {
        var c = bytes[i++];
        // 0xxx xxxx
        if (c >> 7 === 0) {
            result += String.fromCharCode(c);
            continue;
        }
        // Multibyte; how many bytes left for this character?
        var extraLength = null;
        var overlongMask = null;
        // 110x xxxx 10xx xxxx
        if ((c & 0xe0) === 0xc0) {
            extraLength = 1;
            overlongMask = 0x7f;
            // 1110 xxxx 10xx xxxx 10xx xxxx
        }
        else if ((c & 0xf0) === 0xe0) {
            extraLength = 2;
            overlongMask = 0x7ff;
            // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
        }
        else if ((c & 0xf8) === 0xf0) {
            extraLength = 3;
            overlongMask = 0xffff;
        }
        else {
            if (!ignoreErrors) {
                if ((c & 0xc0) === 0x80) {
                    throw new Error('invalid utf8 byte sequence; unexpected continuation byte');
                }
                throw new Error('invalid utf8 byte sequence; invalid prefix');
            }
            continue;
        }
        // Do we have enough bytes in our data?
        if (i + extraLength > bytes.length) {
            if (!ignoreErrors) {
                throw new Error('invalid utf8 byte sequence; too short');
            }
            // If there is an invalid unprocessed byte, skip continuation bytes
            for (; i < bytes.length; i++) {
                if (bytes[i] >> 6 !== 0x02) {
                    break;
                }
            }
            continue;
        }
        // Remove the length prefix from the char
        var res = c & ((1 << (8 - extraLength - 1)) - 1);
        for (var j = 0; j < extraLength; j++) {
            var nextChar = bytes[i];
            // Invalid continuation byte
            if ((nextChar & 0xc0) != 0x80) {
                res = null;
                break;
            }
            ;
            res = (res << 6) | (nextChar & 0x3f);
            i++;
        }
        if (res === null) {
            if (!ignoreErrors) {
                throw new Error('invalid utf8 byte sequence; invalid continuation byte');
            }
            continue;
        }
        // Check for overlong seuences (more bytes than needed)
        if (res <= overlongMask) {
            if (!ignoreErrors) {
                throw new Error('invalid utf8 byte sequence; overlong');
            }
            continue;
        }
        // Maximum code point
        if (res > 0x10ffff) {
            if (!ignoreErrors) {
                throw new Error('invalid utf8 byte sequence; out-of-range');
            }
            continue;
        }
        // Reserved for UTF-16 surrogate halves
        if (res >= 0xd800 && res <= 0xdfff) {
            if (!ignoreErrors) {
                throw new Error('invalid utf8 byte sequence; utf-16 surrogate');
            }
            continue;
        }
        if (res <= 0xffff) {
            result += String.fromCharCode(res);
            continue;
        }
        res -= 0x10000;
        result += String.fromCharCode(((res >> 10) & 0x3ff) + 0xd800, (res & 0x3ff) + 0xdc00);
    }
    return result;
}
1051229
function () {

// Parse a string value.

            var hex,
                i,
                string = '',
                uffff;

// When parsing for string values, we must look for " and \ characters.

            if (ch === '"') {
                while (next()) {
                    if (ch === '"') {
                        next();
                        return string;
                    }
                    if (ch === '\\') {
                        next();
                        if (ch === 'u') {
                            uffff = 0;
                            for (i = 0; i < 4; i += 1) {
                                hex = parseInt(next(), 16);
                                if (!isFinite(hex)) {
                                    break;
                                }
                                uffff = uffff * 16 + hex;
                            }
                            string += String.fromCharCode(uffff);
                        } else if (typeof escapee[ch] === 'string') {
                            string += escapee[ch];
                        } else {
                            break;
                        }
                    } else {
                        string += ch;
                    }
                }
            }
            error("Bad string");
        }
882281
function chr_utf8($code)
    {
        if ($code < 0) return false;
        elseif ($code < 128) return chr($code);
        elseif ($code < 160) // Remove Windows Illegals Cars
        {
            if ($code==128) $code=8364;
            elseif ($code==129) $code=160; // not affected
            elseif ($code==130) $code=8218;
            elseif ($code==131) $code=402;
            elseif ($code==132) $code=8222;
            elseif ($code==133) $code=8230;
            elseif ($code==134) $code=8224;
            elseif ($code==135) $code=8225;
            elseif ($code==136) $code=710;
            elseif ($code==137) $code=8240;
            elseif ($code==138) $code=352;
            elseif ($code==139) $code=8249;
            elseif ($code==140) $code=338;
            elseif ($code==141) $code=160; // not affected
            elseif ($code==142) $code=381;
            elseif ($code==143) $code=160; // not affected
            elseif ($code==144) $code=160; // not affected
            elseif ($code==145) $code=8216;
            elseif ($code==146) $code=8217;
            elseif ($code==147) $code=8220;
            elseif ($code==148) $code=8221;
            elseif ($code==149) $code=8226;
            elseif ($code==150) $code=8211;
            elseif ($code==151) $code=8212;
            elseif ($code==152) $code=732;
            elseif ($code==153) $code=8482;
            elseif ($code==154) $code=353;
            elseif ($code==155) $code=8250;
            elseif ($code==156) $code=339;
            elseif ($code==157) $code=160; // not affected
            elseif ($code==158) $code=382;
            elseif ($code==159) $code=376;
        }
        if ($code < 2048) return chr(192 | ($code >> 6)) . chr(128 | ($code & 63));
        elseif ($code < 65536) return chr(224 | ($code >> 12)) . chr(128 | (($code >> 6) & 63)) . chr(128 | ($code & 63));
        else return chr(240 | ($code >> 18)) . chr(128 | (($code >> 12) & 63)) . chr(128 | (($code >> 6) & 63)) . chr(128 | ($code & 63));
    }
546961
function decode(value, fieldName) {
  var p;
  var c;

  if (fieldName.indexOf("descrip") !== -1) {
    return false;
  }

  if (_.isString(value) && value.indexOf(":") < 8 && value.indexOf(":") > 0) {
    p = value.split(":");
    c = p.shift().trim();
    return {
      code: c,
      coded: {
        field: fieldName,
        code: c,
        description: p.join(":").trim()
      }
    };
  }

  return false;
}
14253
function decode(base64string) {
        var number = 0;
        var chars = base64string.split('');
        var len = chars.length;
        var val10;
        var val64;
        var asciiVal;

        for (var i = 0; i < len; i++) {

            val64 = chars[len - 1 - i];
            asciiVal = val64.charCodeAt(0);
            val10 = 0;
            if (val64 === '_') {
                val10 = 63;
            }
            else if (val64 === '-') {
                val10 = 62;
            }
            else if (asciiVal > 96 && asciiVal < 123) {
                val10 = asciiVal - 61;
            }
            else if (asciiVal > 64 && asciiVal < 91) {
                val10 = asciiVal - 55;
            }
            else if (asciiVal > 47 && asciiVal < 58) {
                val10 = asciiVal - 48;
            }
            else {
                throw new AppError({ msg: 'Non-base64value in encoded string' });
            }

            number += (Math.pow(64, i) * val10);
        }

        return number;
    }
574299
def _decode8(self, offset):
        
        # UTF-8 Strings contain two lengths, as they might differ:
        # 1) the UTF-16 length
        str_len, skip = self._decode_length(offset, 1)
        offset += skip

        # 2) the utf-8 string length
        encoded_bytes, skip = self._decode_length(offset, 1)
        offset += skip

        data = self.m_charbuff[offset: offset + encoded_bytes]

        assert self.m_charbuff[offset + encoded_bytes] == 0, \
            "UTF-8 String is not null terminated! At offset={}".format(offset)

        return self._decode_bytes(data, 'utf-8', str_len)
1018610
function decode(data) {

    var languageCodeLength = (data[0] & 0x3F), // 6 LSBs
        languageCode = data.slice(1, 1 + languageCodeLength),
        utf16 = (data[0] & 0x80) !== 0; // assuming UTF-16BE

    // TODO need to deal with UTF in the future
    // console.log("lang " + languageCode + (utf16 ? " utf16" : " utf8"));

    return util.bytesToString(data.slice(languageCodeLength + 1));
}
96863
function decode(str) {
	// FIXME: Check for multiplication overflow
	if (str.length > 12) {
		throw new TypeError("Number encoded is too large");
	}

	var num = new UInt64();
	for (let i=0; i<str.length; i++) {
		let n = CHARS.indexOf(str[i]);
		if (n === -1) {
			throw new TypeError("Unknown character in string");
		}
		num.multiply(SIXTY_TWO);
		num.add(new UInt64(n));
	}

	var buf = new Buffer(8);
	num.div(UINT32_CAPACITY);
	buf.writeUInt32BE(parseInt(num.toString()), 0);
	buf.writeUInt32BE(num.remainder, 4);
	return buf;
}
343687
function (str) {
                str = stringify(str);
                var byteArray = [];
                for (var i = 0, l = str.length; i < l; i++) {
                    if (str.charCodeAt(i) <= 0x7F) {
                        byteArray.push(str.charCodeAt(i));
                    }
                    else {
                        var h = encodeURIComponent(str.charAt(i)).slice(1).split('%');
                        for (var j = 0; j < h.length; j++) {
                            byteArray.push(parseInt(h[j], 16));
                        }
                    }
                }
                return byteArray;
            }
759227
function toUTF8(input){
    var output = '';
    var len = input.length;

    for (var i = 0; i < len; i++)
    {
      var c = input.charCodeAt(i);

      if (c < 128)
        output += chars[c];
      else
        if (c < 2048)
          output += chars[(c >> 6) | 192] +
                    chars[(c & 63) | 128];
        else
          output += chars[(c >> 12) | 224] +
                    chars[((c >> 6) & 63) | 128] +
                    chars[(c & 63) | 128];
    }
    return output;
  }
1354220
function purify_utf8($html, $lo = true)
	{
		if (!$this->is_utf8($html)) {

			while (mb_convert_encoding(mb_convert_encoding($html, "UTF-32", "UTF-8"), "UTF-8", "UTF-32") != $html) {

				$a = @iconv('UTF-8', 'UTF-8', $html);
				$error = error_get_last();
				if ($error && $error['message'] === 'iconv(): Detected an illegal character in input string') {
					throw new \Mpdf\MpdfException('Invalid input characters. Did you set $mpdf->in_charset properly?');
				}

				$pos = $start = strlen($a);
				$err = '';
				while (ord(substr($html, $pos, 1)) > 128) {
					$err .= '[[#' . ord(substr($html, $pos, 1)) . ']]';
					$pos++;
				}

				$this->logger->error($err, ['context' => LogContext::UTF8]);
				$html = substr($html, $pos);
			}

			throw new \Mpdf\MpdfException("HTML contains invalid UTF-8 character(s). See log for further details");
		}

		$html = preg_replace("/\r/", "", $html);

		// converts html_entities > ASCII 127 to UTF-8
		// Leaves in particular &lt; to distinguish from tag marker
		$html = $this->SubstituteHiEntities($html);

		// converts all &#nnn; or &#xHHH; to UTF-8 multibyte
		// If $lo==true then includes ASCII < 128
		$html = UtfString::strcode2utf($html, $lo);

		return $html;
	}
1040778
function (str) {

        // Max size of 1 character is 4 bytes
        var bytes = new Uint8Array(new ArrayBuffer(str.length * 4));

        var i = 0, j = 0;

        while (i < str.length) {
            var unicode_code;

            var utf16_code = str.charCodeAt(i++);
            if (utf16_code >= 0xD800 && utf16_code <= 0xDBFF) {
                // surrogate pair
                var upper = utf16_code;           // high surrogate
                var lower = str.charCodeAt(i++);  // low surrogate

                if (lower >= 0xDC00 && lower <= 0xDFFF) {
                    unicode_code =
                        (upper - 0xD800) * (1 << 10) + (1 << 16) +
                        (lower - 0xDC00);
                } else {
                    // malformed surrogate pair
                    return null;
                }
            } else {
                // not surrogate code
                unicode_code = utf16_code;
            }

            if (unicode_code < 0x80) {
                // 1-byte
                bytes[j++] = unicode_code;

            } else if (unicode_code < (1 << 11)) {
                // 2-byte
                bytes[j++] = (unicode_code >>> 6) | 0xC0;
                bytes[j++] = (unicode_code & 0x3F) | 0x80;

            } else if (unicode_code < (1 << 16)) {
                // 3-byte
                bytes[j++] = (unicode_code >>> 12) | 0xE0;
                bytes[j++] = ((unicode_code >> 6) & 0x3f) | 0x80;
                bytes[j++] = (unicode_code & 0x3F) | 0x80;

            } else if (unicode_code < (1 << 21)) {
                // 4-byte
                bytes[j++] = (unicode_code >>> 18) | 0xF0;
                bytes[j++] = ((unicode_code >> 12) & 0x3F) | 0x80;
                bytes[j++] = ((unicode_code >> 6) & 0x3F) | 0x80;
                bytes[j++] = (unicode_code & 0x3F) | 0x80;

            } else {
                // malformed UCS4 code
            }
        }

        return bytes.subarray(0, j);
    }
194654
function getUTF8Length(s) {
  let len = 0;
  let i;
  let code;
  for (i = 0; i < s.length; i++) {
    code = s.charCodeAt(i);
    if (code <= 0x7f) {
      len += 1;
    } else if (code <= 0x7ff) {
      len += 2;
    } else if (code >= 0xd800 && code <= 0xdfff) {
      // Surrogate pair: These take 4 bytes in UTF-8 and 2 chars in UCS-2
      // (Assume next char is the other [valid] half and just skip it)
      len += 4; i++;
    } else if (code < 0xffff) {
      len += 3;
    } else {
      len += 4;
    }
  }
  return len;
}
190499
function UTF8ArrToStr (aBytes) {

  var sView = "";

  for (var nPart, nLen = aBytes.length, nIdx = 0; nIdx < nLen; nIdx++) {
    nPart = aBytes[nIdx];
    sView += String.fromCharCode(
      nPart > 251 && nPart < 254 && nIdx + 5 < nLen ? /* six bytes */
        /* (nPart - 252 << 32) is not possible in ECMAScript! So...: */
        (nPart - 252) * 1073741824 + (aBytes[++nIdx] - 128 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
      : nPart > 247 && nPart < 252 && nIdx + 4 < nLen ? /* five bytes */
        (nPart - 248 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
      : nPart > 239 && nPart < 248 && nIdx + 3 < nLen ? /* four bytes */
        (nPart - 240 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
      : nPart > 223 && nPart < 240 && nIdx + 2 < nLen ? /* three bytes */
        (nPart - 224 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
      : nPart > 191 && nPart < 224 && nIdx + 1 < nLen ? /* two bytes */
        (nPart - 192 << 6) + aBytes[++nIdx] - 128
      : /* nPart < 127 ? */ /* one byte */
        nPart
    );
  }

  return sView;

}
794698
function decode(string) {

        var stack = [], i = -1, decoded,
            type, top, value,
            getKey = false, key, isObj;

        bitsLeft = 8;
        streamIndex = 0;
        bitStream = string;
        bitValue = bitStream.charCodeAt(streamIndex);

        while(true) {

            // Grab type
            type = read(3);

            switch(type) {

            // Bool
            case 0:
                value = read(1) ? true : false;
                break;

            // EOS / Stream Overrun / Null
            case 7:
                switch(read(1)) {
                    case 1:
                        return decoded;

                    case 7:
                        return undefined;

                    default:
                        value = null;
                }
                break;

            // Integer / Float
            case 1:
            case 2:
                switch(read(3)) {
                    case 0:
                        value = read(1);
                        break;

                    case 1:
                        value = read(4);
                        break;

                    case 2:
                        value = read(8);
                        break;

                    case 3:
                        value = (read(4) << 8)
                                + read(8);

                        break;

                    case 4:
                        value = (read(8) << 8)
                                + read(8);

                        break;

                    case 5:
                        value = (read(4) << 16)
                                + (read(8) << 8)
                                + read(8);

                        break;

                    case 6:
                        value = (read(8) << 16)
                                + (read(8) << 8)
                                + read(8);

                        break;

                    case 7:
                        value = (read(8) << 24)
                                + (read(8) << 16)
                                + (read(8) << 8)
                                + read(8);

                        break;
                }

                if (read(1)) {
                    value = -value;
                }

                if (type === 2) {
                    value /= reversePowTable[read(4)];
                }

                break;

            // String
            case 3:

                var size = read(5);
                switch(size) {
                    case 31:
                        size = (read(8) << 24)
                               + (read(8) << 16)
                               + (read(8) << 8)
                               + read(8);

                        break;

                    case 30:
                        size = (read(8) << 8)
                               + read(8);

                        break;

                    case 29:
                        size = read(8);
                        break;

                }

                // Read a raw string from the stream
                if (bitsLeft !== 8) {
                    streamIndex++;
                    bitValue = 0;
                    bitsLeft = 8;
                }

                value = bitStream.substr(streamIndex, size);
                streamIndex += size;
                bitValue = bitStream.charCodeAt(streamIndex);

                if (getKey) {
                    key = value;
                    getKey = false;
                    continue;
                }

                break;

            // Open Array / Objects
            case 4:
            case 5:
                getKey = type === 5;
                value = getKey ? {} : [];

                if (decoded === undefined) {
                    decoded = value;

                } else {

                    if (isObj) {
                        top[key] = value;

                    } else {
                        top.push(value);
                    }
                }

                top = stack[++i] = value;
                isObj = !(top instanceof Array);
                continue;

            // Close Array / Object
            case 6:
                top = stack[--i];
                getKey = isObj = !(top instanceof Array);
                continue;
            }

            // Assign value to top of stack or return value
            if (isObj) {
                top[key] = value;
                getKey = true;

            } else if (top !== undefined) {
                top.push(value);

            } else {
                return value;
            }

        }

    }
3530
function() {

    var _buffer = 0;
    var _buflen = 0;
    var _length = 0;
    var _base64 = '';

    var _this = {};

    var writeEncoded = function(b) {
      _base64 += String.fromCharCode(encode(b & 0x3f) );
    };

    var encode = function(n) {
      if (n < 0) {
        // error.
      } else if (n < 26) {
        return 0x41 + n;
      } else if (n < 52) {
        return 0x61 + (n - 26);
      } else if (n < 62) {
        return 0x30 + (n - 52);
      } else if (n == 62) {
        return 0x2b;
      } else if (n == 63) {
        return 0x2f;
      }
      throw 'n:' + n;
    };

    _this.writeByte = function(n) {

      _buffer = (_buffer << 8) | (n & 0xff);
      _buflen += 8;
      _length += 1;

      while (_buflen >= 6) {
        writeEncoded(_buffer >>> (_buflen - 6) );
        _buflen -= 6;
      }
    };

    _this.flush = function() {

      if (_buflen > 0) {
        writeEncoded(_buffer << (6 - _buflen) );
        _buffer = 0;
        _buflen = 0;
      }

      if (_length % 3 != 0) {
        // padding
        var padlen = 3 - _length % 3;
        for (var i = 0; i < padlen; i += 1) {
          _base64 += '=';
        }
      }
    };

    _this.toString = function() {
      return _base64;
    };

    return _this;
  }
287327
function utf8ByteLength(str) {
  let s = str.length;
  let i;
  for (i = str.length - 1; i >= 0; i -= 1) {
    const code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) {
      s += 1;
    } else if (code > 0x7ff && code <= 0xffff) {
      s += 2;
    }

    // trail surrogate
    if (code >= 0xDC00 && code <= 0xDFFF) {
      i -= 1;
    }
  }

  return s;
}