ase '<':
            case '>':
            case '&':
            case '\"':
            case '\'':
            case '\r':
            case '\n':
            case '\u0009':
                return true;
            default:
                return c > 0x7F;
        }
    }

    // Check if processing is needed
    foreach( char c; xml ){
        if( needsReplacement( c )){
            goto Lprocess;
        }
    }
    return xml;
Lprocess:

    // yes, do a new string, start with +20 chars
    char[] res = new char[ xml.length + 20 ];
    res.length = 0;

    foreach( dchar c; xml ){

        if( !needsReplacement( c )){
            res ~= c;
        }
        else{
            res ~= '&';
            switch( c ){
                case '<': res ~= "lt"; break;
                case '>': res ~= "gt"; break;
                case '&': res ~= "amp"; break;
                case '\"': res ~= "quot"; break;
                case '\'': res ~= "apos"; break;
                case '\r': case '\n': case '\u0009':
                default:
                    char toHexDigit( int i ){
                        if( i < 10 ) return cast(char)('0'+i);
                        return cast(char)('A'+i-10);
                    }
                    res ~= "#x";
                    if( c <= 0xFF ){
                        res ~= toHexDigit(( c >> 4 ) & 0x0F );
                        res ~= toHexDigit(( c >> 0 ) & 0x0F );
                    }
                    else if( c <= 0xFFFF ){
                        res ~= toHexDigit(( c >> 12 ) & 0x0F );
                        res ~= toHexDigit(( c >> 8 ) & 0x0F );
                        res ~= toHexDigit(( c >> 4 ) & 0x0F );
                        res ~= toHexDigit(( c >> 0 ) & 0x0F );
                    }
                    else if( c <= 0xFFFFFF ){
                        res ~= toHexDigit(( c >> 20 ) & 0x0F );
                        res ~= toHexDigit(( c >> 16 ) & 0x0F );
                        res ~= toHexDigit(( c >> 12 ) & 0x0F );
                        res ~= toHexDigit(( c >> 8 )