Home Reference Source

js/models/Encoding.js

import EncodingRequest from '~/models/Request/Encoding';
import Encodings from '~/models/Request/Encodings';
import Query from '~/models/Query';

export const NATIVE_ENCODINGS = ['UTF-8', 'UTF-16', 'ISO-8859-1'];

/**
 * Represents an encoding
 */
export default class Encoding {
    /**
     * Encoding name. If not a valid encoding undefined behavior. Recommended to use fromName static
     * @param {string} name - associated name
     */
    constructor(name) {
        /**
         * The actual name of the encoding suitable for delivering to backend
         * @type {string}
         */
        this.name = name;
    }

    /** @type {string} */
    get displayName() {
        return this.name.replace(/_/g, '-').toUpperCase();
    }

    /**
     * Byte-length of a JS string in this encoding
     * @param {string} string
     * @return {number} postive integer
     */
    byteCount(string) {
        let byteLength = 0;
        switch(string) {
        case 'utf-8':
            for (let i = 0; i < s.length; i++) {
                let code = s.charCodeAt(i);
                if (code <= 0x7f) {
                    byteLength += 1;
                } else if (code <= 0x7ff) {
                    byteLength += 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)
                    byteLength += 4;
                    i++;
                } else if (code < 0xffff) {
                    byteLength += 3;
                } else {
                    byteLength += 4;
                }
            }
            break;

        case 'utf-16':
            byteLength = string.length;
            break;

        default:
            for (const char of string) {
                byteLength += 1;
            }
        }

        return byteLength;
    }

    /**
     * Obtains list of encodings through query
     * @return {Promise<Set<Encoding>>}
     */
    static async all() {
        if (Encoding._codepages !== null)
            return Encoding._codepages;

        const encodingNames = await new Encodings().run();
        let encodings = new Set();
        for (const encodingName of encodingNames) {
            encodings.add(Encoding.fromName(encodingName));
        }
        Encoding._codepages = new Set()
        return encodings;
    }
    static _codepages = null;

    /**
     * Obtains query
     * @return {Promise<Query<Encoding>>}
     */
    static async query() {
        if (Encoding._query !== null)
            return Encoding._query;

        return Encoding._quey = new Query(
            [...await Encoding.all()],
            (encoding) => encoding.name
        );
    }
    static _query = null;

    /**
     * Gets from an encoding name
     * @param {string} name
     * @return {Encoding}
     */
    static fromName(name) {
        if (Encoding._encodingCache.has(name))
            return Encoding._encodingCache.get(name);

        const encoding = new Encoding(name);
        Encoding._encodingCache.set(name, encoding);
        return encoding;
    }
    static _encodingCache = new Map();
}