void read(Tokeniser t, CharacterReader r) {
      if (r.isEmpty()) {
        t.eofError(this);
        t.transition(Data);
        return;
      }

      char c = r.consume();
      switch (c) {
        case '-':
          t.emit(c);
          t.transition(ScriptDataEscapedDashDash);
          break;
        case '<':
          t.transition(ScriptDataEscapedLessthanSign);
          break;
        case nullChar:
          t.error(this);
          t.emit(replacementChar);
          t.transition(ScriptDataEscaped);
          break;
        default:
          t.emit(c);
          t.transition(ScriptDataEscaped);
      }
    }
 void read(Tokeniser t, CharacterReader r) {
   char c = r.current();
   switch (c) {
     case '-':
       t.emit(c);
       t.advanceTransition(ScriptDataDoubleEscapedDash);
       break;
     case '<':
       t.emit(c);
       t.advanceTransition(ScriptDataDoubleEscapedLessthanSign);
       break;
     case nullChar:
       t.error(this);
       r.advance();
       t.emit(replacementChar);
       break;
     case eof:
       t.eofError(this);
       t.transition(Data);
       break;
     default:
       String data = r.consumeToAny('-', '<', nullChar);
       t.emit(data);
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   char c = r.consume();
   switch (c) {
     case '-':
       t.emit(c);
       break;
     case '<':
       t.emit(c);
       t.transition(ScriptDataDoubleEscapedLessthanSign);
       break;
     case '>':
       t.emit(c);
       t.transition(ScriptData);
       break;
     case nullChar:
       t.error(this);
       t.emit(replacementChar);
       t.transition(ScriptDataDoubleEscaped);
       break;
     case eof:
       t.eofError(this);
       t.transition(Data);
       break;
     default:
       t.emit(c);
       t.transition(ScriptDataDoubleEscaped);
   }
 }
    void read(Tokeniser t, CharacterReader r) {
      if (r.matchesLetter()) {
        String name = r.consumeLetterSequence();
        t.dataBuffer.append(name.toLowerCase());
        t.emit(name);
        return;
      }

      char c = r.consume();
      switch (c) {
        case '\t':
        case '\n':
        case '\r':
        case '\f':
        case ' ':
        case '/':
        case '>':
          if (t.dataBuffer.toString().equals("script")) t.transition(ScriptDataEscaped);
          else t.transition(ScriptDataDoubleEscaped);
          t.emit(c);
          break;
        default:
          r.unconsume();
          t.transition(ScriptDataDoubleEscaped);
      }
    }
    void read(Tokeniser t, CharacterReader r) {
      if (r.isEmpty()) {
        t.eofError(this);
        t.transition(Data);
        return;
      }

      switch (r.current()) {
        case '-':
          t.emit('-');
          t.advanceTransition(ScriptDataEscapedDash);
          break;
        case '<':
          t.advanceTransition(ScriptDataEscapedLessthanSign);
          break;
        case nullChar:
          t.error(this);
          r.advance();
          t.emit(replacementChar);
          break;
        default:
          String data = r.consumeToAny('-', '<', nullChar);
          t.emit(data);
      }
    }
 void read(Tokeniser t, CharacterReader r) {
   if (r.matchesLetter()) {
     t.createTempBuffer();
     t.dataBuffer.append(Character.toLowerCase(r.current()));
     t.emit("<" + r.current());
     t.advanceTransition(ScriptDataDoubleEscapeStart);
   } else if (r.matches('/')) {
     t.createTempBuffer();
     t.advanceTransition(ScriptDataEscapedEndTagOpen);
   } else {
     t.emit('<');
     t.transition(ScriptDataEscaped);
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   switch (r.current()) {
     case nullChar:
       t.error(this);
       r.advance();
       t.emit(replacementChar);
       break;
     case eof:
       t.emit(new Token.EOF());
       break;
     default:
       String data = r.consumeTo(nullChar);
       t.emit(data);
       break;
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   switch (r.consume()) {
     case '/':
       t.createTempBuffer();
       t.transition(ScriptDataEndTagOpen);
       break;
     case '!':
       t.emit("<!");
       t.transition(ScriptDataEscapeStart);
       break;
     default:
       t.emit("<");
       r.unconsume();
       t.transition(ScriptData);
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   if (r.matches('-')) {
     t.emit('-');
     t.advanceTransition(ScriptDataEscapedDashDash);
   } else {
     t.transition(ScriptData);
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   if (r.matchesLetter()) {
     t.createTagPending(false);
     t.transition(ScriptDataEndTagName);
   } else {
     t.emit("</");
     t.transition(ScriptData);
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   if (r.matches('/')) {
     t.createTempBuffer();
     t.advanceTransition(RawtextEndTagOpen);
   } else {
     t.emit('<');
     t.transition(Rawtext);
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   if (r.matches('/')) {
     t.emit('/');
     t.createTempBuffer();
     t.advanceTransition(ScriptDataDoubleEscapeEnd);
   } else {
     t.transition(ScriptDataDoubleEscaped);
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   switch (r.current()) {
     case '<':
       t.advanceTransition(ScriptDataLessthanSign);
       break;
     case nullChar:
       t.error(this);
       r.advance();
       t.emit(replacementChar);
       break;
     case eof:
       t.emit(new Token.EOF());
       break;
     default:
       String data = r.consumeToAny('<', nullChar);
       t.emit(data);
       break;
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   // todo: handle bogus comment starting from eof. when does that trigger?
   // rewind to capture character that lead us here
   r.unconsume();
   Token.Comment comment = new Token.Comment();
   comment.data.append(r.consumeTo('>'));
   // todo: replace nullChar with replaceChar
   t.emit(comment);
   t.advanceTransition(Data);
 }
 void read(Tokeniser t, CharacterReader r) {
   if (r.matchesLetter()) {
     t.createTagPending(false);
     t.tagPending.appendTagName(Character.toLowerCase(r.current()));
     t.dataBuffer.append(r.current());
     t.advanceTransition(ScriptDataEscapedEndTagName);
   } else {
     t.emit("</");
     t.transition(ScriptDataEscaped);
   }
 }
 // in data state, gather characters until a character reference or tag is found
 void read(Tokeniser t, CharacterReader r) {
   switch (r.current()) {
     case '&':
       t.advanceTransition(CharacterReferenceInData);
       break;
     case '<':
       t.advanceTransition(TagOpen);
       break;
     case nullChar:
       t.error(this); // NOT replacement character (oddly?)
       t.emit(r.consume());
       break;
     case eof:
       t.emit(new Token.EOF());
       break;
     default:
       String data = r.consumeToAny('&', '<', nullChar);
       t.emit(data);
       break;
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   if (r.isEmpty()) {
     t.eofError(this);
     t.emit("</");
     t.transition(Data);
   } else if (r.matchesLetter()) {
     t.createTagPending(false);
     t.transition(TagName);
   } else if (r.matches('>')) {
     t.error(this);
     t.advanceTransition(Data);
   } else {
     t.error(this);
     t.advanceTransition(BogusComment);
   }
 }
 // from < in rcdata
 void read(Tokeniser t, CharacterReader r) {
   if (r.matches('/')) {
     t.createTempBuffer();
     t.advanceTransition(RCDATAEndTagOpen);
   } else if (r.matchesLetter() && !r.containsIgnoreCase("</" + t.appropriateEndTagName())) {
     // diverge from spec: got a start tag, but there's no appropriate end tag (</title>), so
     // rather than
     // consuming to EOF; break out here
     t.tagPending = new Token.EndTag(t.appropriateEndTagName());
     t.emitTagPending();
     r.unconsume(); // undo "<"
     t.transition(Data);
   } else {
     t.emit("<");
     t.transition(Rcdata);
   }
 }
 // from < in data
 void read(Tokeniser t, CharacterReader r) {
   switch (r.current()) {
     case '!':
       t.advanceTransition(MarkupDeclarationOpen);
       break;
     case '/':
       t.advanceTransition(EndTagOpen);
       break;
     case '?':
       t.advanceTransition(BogusComment);
       break;
     default:
       if (r.matchesLetter()) {
         t.createTagPending(true);
         t.transition(TagName);
       } else {
         t.error(this);
         t.emit('<'); // char that got us here
         t.transition(Data);
       }
       break;
   }
 }
 void read(Tokeniser t, CharacterReader r) {
   String data = r.consumeTo("]]>");
   t.emit(data);
   r.matchConsume("]]>");
   t.transition(Data);
 }
 void read(Tokeniser t, CharacterReader r) {
   Character c = t.consumeCharacterReference(null, false);
   if (c == null) t.emit('&');
   else t.emit(c);
   t.transition(Rcdata);
 }
 private void anythingElse(Tokeniser t, CharacterReader r) {
   t.emit("</" + t.dataBuffer.toString());
   t.transition(ScriptDataEscaped);
 }
 private void anythingElse(Tokeniser t, CharacterReader r) {
   t.emit("</" + t.dataBuffer.toString());
   t.transition(Rawtext);
 }