@Override
    protected char more() throws IOException, XmlPullParserException {
        final char codePoint  = super.more(); // note - this does NOT return a codepoint now, but simply a (double byte) character!
        boolean validCodepoint = false;
        boolean isLowSurrogate = Character.isLowSurrogate(codePoint);
        if (    (codePoint == 0x9) ||
                (codePoint == 0xA) ||
                (codePoint == 0xD) ||
                ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
                ((codePoint >= 0xE000) && (codePoint <= 0xFFFD))) {
            validCodepoint = true;
        }
        else if (highSurrogateSeen) {
            if (isLowSurrogate) {
                validCodepoint = true;
            } else {
                throw new XmlPullParserException("High surrogate followed by non low surrogate '0x" + String.format("%x", (int) codePoint) + "'");
            }
        }
        else if (isLowSurrogate) {
            throw new XmlPullParserException("Low surrogate '0x " + String.format("%x", (int) codePoint) + " without preceeding high surrogate");
        }
        else if (Character.isHighSurrogate(codePoint)) {
            highSurrogateSeen = true;
            // Return here so that highSurrogateSeen is not reset
            return codePoint;
        }
        // Always reset high surrogate seen
        highSurrogateSeen = false;
        if (validCodepoint)
            return codePoint;

        throw new XmlPullParserException("Illegal XML character '0x" + String.format("%x", (int) codePoint) + "'");
    }
Makes sure that each individual character is a valid XML character.

Note that when MXParser is being modified to handle multibyte chars correctly, this method needs to change (as
then, there are more codepoints to check).
xmppserver/src/main/java/org/jivesoftware/openfire/net/MXParser.java