﻿function UTF8needed(s) {
    var uc;
    for (var i = 0; i < s.length; ++i) {
        uc = s.charCodeAt(i);
        if (uc == 0x9d || uc > 0xff) return true;
    }
    return false;
}
function str2UTF8str(s) {
    var t, uc, res = '';
    for (var i = 0; i < s.length; ++i) {
        uc = s.charCodeAt(i);
        if ((t = nbits(uc)) < 8)
            res += String.fromCharCode(uc);
        else {
            t = Math.floor((t + 3) / 5);
            res += String.fromCharCode((-1 << (8 - t) & 0xff) | (uc >> (6 * --t)));
            while (t) res += String.fromCharCode(0x80 | (uc >> (6 * --t)) & 0x3f);
        }
    }
    return res;
}
function UTF8str2str(s) {
    var t, ca, cc, j = 0, res = "";
    while (j < s.length) {
        cc = ca = s.charCodeAt(j++);
        if (ca > 0xff) { alert("not an UTF8 string!"); return null; }
        if (ca & 0x80) {
            cc &= 0x7f; t = 0x40;
            if ((cc & t) != t) { alert("Not an UTF8 string (first)!"); return null; }
            while (cc & t && j < s.length) {
                if (((ca = s.charCodeAt(j++)) & 0xc0) != 0x80) { alert("Not an UTF8 string (middle)!"); return null; }
                cc = ((cc & ~t) << 6) | (ca & 0x3f); t <<= 5;
            }
            if (cc & t) { alert("Not an UTF8 string (end)!"); return null; }
        }
        res += String.fromCharCode(cc);
    }
    return res;
}
function UTF8encode(s) {
    if (UTF8needed(s)) return String.fromCharCode(0x9d) + str2UTF8str(s);
    return s;
}
function UTF8decode(s) {
    if (s.charCodeAt(0) == 0x9d) return UTF8str2str(s.substring(1));
    return s;
} 
