while (true) {
              if (op == null)
                  return isSet(opts, XMLSCHEMA_MODE) && offset != con.limit ? -1 : offset;
              if (offset > con.limit || offset < con.start)
                  return -1;
              switch (op.type) {
              case Op.CHAR:
                  if (isSet(opts, IGNORE_CASE)) {
                      int ch = op.getData();
                      if (dx > 0) {
                          if (offset >= con.limit || !matchIgnoreCase(ch,  target .setIndex(  offset ) ))
                              return -1;
                          offset ++;
                      } else {
                          int o1 = offset-1;
                          if (o1 >= con.limit || o1 < 0 || !matchIgnoreCase(ch,  target .setIndex(  o1 ) ))
                              return -1;
                          offset = o1;
                      }
                  } else {
                      int ch = op.getData();
                      if (dx > 0) {
                          if (offset >= con.limit || ch !=  target .setIndex(  offset ) )
                              return -1;
                          offset ++;
                      } else {
                          int o1 = offset-1;
                          if (o1 >= con.limit || o1 < 0 || ch !=  target .setIndex(  o1 ) )
                              return -1;
                          offset = o1;
                      }
                  }
                  op = op.next;
                  break;

              case Op.DOT:
                  if (dx > 0) {
                      if (offset >= con.limit)
                          return -1;
                      int ch =  target .setIndex(  offset ) ;
                      if (isSet(opts, SINGLE_LINE)) {
                          if (REUtil.isHighSurrogate(ch) && offset+1 < con.limit)
                              offset ++;
                      } else {
                          if (REUtil.isHighSurrogate(ch) && offset+1 < con.limit)
                              ch = REUtil.composeFromSurrogates(ch,  target .setIndex(  ++offset ) );
                          if (isEOLChar(ch))
                              return -1;
                      }
                      offset ++;
                  } else {
                      int o1 = offset-1;
                      if (o1 >= con.limit || o1 < 0)
                          return -1;
                      int ch =  target .setIndex(  o1 ) ;
                      if (isSet(opts, SINGLE_LINE)) {
                          if (REUtil.isLowSurrogate(ch) && o1-1 >= 0)
                              o1 --;
                      } else {
                          if (REUtil.isLowSurrogate(ch) && o1-1 >= 0)
                              ch = REUtil.composeFromSurrogates( target .setIndex(  --o1 ) , ch);
                          if (!isEOLChar(ch))
                              return -1;
                      }
                      offset = o1;
                  }
                  op = op.next;
                  break;

              case Op.RANGE:
              case Op.NRANGE:
                  if (dx > 0) {
                      if (offset >= con.limit)
                          return -1;
                      int ch =  target .setIndex(  offset ) ;
                      if (REUtil.isHighSurrogate(ch) && offset+1 < con.limit)
                          ch = REUtil.composeFromSurrogates(ch,  target .setIndex(  ++offset ) );
                      RangeToken tok = op.getToken();
                      if (isSet(opts, IGNORE_CASE)) {
                          tok = tok.getCaseInsensitiveToken();
                          if (!tok.match(ch)) {
                              if (ch >= 0x10000)  return -1;
                              char uch;
                              if (!tok.match(uch = Character.toUpperCase((char)ch))
                                  && !tok.match(Character.toLowerCase(uch)))
                                  return -1;
                          }
                      } else {
                          if (!tok.match(ch))  return -1;
                      }
                      offset ++;
                  } else {
                      int o1 = offset-1;
                      if (o1 >= con.limit || o1 < 0)
                          return -1;
                      int ch =  target .setIndex(  o1 ) ;
                      if (REUtil.isLowSurrogate(ch) && o1-1 >= 0)
                          ch = REUtil.composeFromSurrogates( target .setIndex(  --o1 ) , ch);
                      RangeToken tok = op.getToken();
                      if (isSet(opts, IGNORE_CASE)) {
                          tok = tok.getCaseInsensitiveToken();
                          if (!tok.match(ch)) {
                              if (ch >= 0x10000)  return -1;
                              char uch;
                              if (!tok.match(uch = Character.toUpperCase((char)ch))
                                  && !tok.match(Character.toLowerCase(uch)))
                                  return -1;
                          }
                      } else {
                          if (!tok.match(ch))  return -1;
                      }
                      offset = o1;
                  }
                  op = op.next;
                  break;

              case Op.ANCHOR:
                  boolean go = false;
                  switch (op.getData()) {
                  case '^':
                      if (isSet(opts, MULTIPLE_LINES)) {
                          if (!(offset == con.start
                                || offset > con.start && isEOLChar( target .setIndex(  offset-1 ) )))
                              return -1;
                      } else {
                          if (offset != con.start)
                              return -1;
                      }
                      break;

                  case '@':                         // Internal use only.
                      // The @ always matches line beginnings.
                      if (!(offset == con.start
                            || offset > con.start && isEOLChar( target .setIndex(  offset-1 ) )))
                          return -1;
                      break;

                  case '$':
                      if (isSet(opts, MULTIPLE_LINES)) {
                          if (!(offset == con.limit
                                || offset < con.limit && isEOLChar( target .setIndex(  offset ) )))
                              return -1;
                      } else {
                          if (!(offset == con.limit
                                || offset+1 == con.limit && isEOLChar( target .setIndex(  offset ) )
                                || offset+2 == con.limit &&  target .setIndex(  offset )  == CARRIAGE_RETURN
                                &&  target .setIndex(  offset+1 )  == LINE_FEED))
                              return -1;
                      }
                      break;

                  case 'A':
                      if (offset != con.start)  return -1;
                      break;

                  case 'Z':
                      if (!(offset == con.limit
                            || offset+1 == con.limit && isEOLChar( target .setIndex(  offset ) )
                            || offset+2 == con.limit &&  target .setIndex(  offset )  == CARRIAGE_RETURN
                            &&  target .setIndex(  offset+1 )  == LINE_FEED))
                          return -1;
                      break;

                  case 'z':
                      if (offset != con.limit)  return -1;
                      break;

                  case 'b':
                      if (con.length == 0)  return -1;
                      {
                          int after = getWordType(target, con.start, con.limit, offset, opts);
                          if (after == WT_IGNORE)  return -1;
                          int before = getPreviousWordType(target, con.start, con.limit, offset, opts);
                          if (after == before)  return -1;
                      }
                      break;

                  case 'B':
                      if (con.length == 0)
                          go = true;
                      else {
                          int after = getWordType(target, con.start, con.limit, offset, opts);
                          go = after == WT_IGNORE
                               || after == getPreviousWordType(target, con.start, con.limit, offset, opts);
                      }
                      if (!go)  return -1;
                      break;

                  case '<':
                      if (con.length == 0 || offset == con.limit)  return -1;
                      if (getWordType(target, con.start, con.limit, offset, opts) != WT_LETTER
                          || getPreviousWordType(target, con.start, con.limit, offset, opts) != WT_OTHER)
                          return -1;
                      break;

                  case '>':
                      if (con.length == 0 || offset == con.start)  return -1;
                      if (getWordType(target, con.start, con.limit, offset, opts) != WT_OTHER
                          || getPreviousWordType(target, con.start, con.limit, offset, opts) != WT_LETTER)
                          return -1;
                      break;
                  } // switch anchor type
                  op = op.next;
                  break;

              case Op.BACKREFERENCE:
                  {
                      int refno = op.getData();
                      if (refno <= 0 || refno >= this.nofparen)
                          throw new RuntimeException("Internal Error: Reference number must be more than zero: "+refno);
                      if (con.match.getBeginning(refno) < 0
                          || con.match.getEnd(refno) < 0)
                          return -1;                // ********
                      int o2 = con.match.getBeginning(refno);
                      int literallen = con.match.getEnd(refno)-o2;
                      if (!isSet(opts, IGNORE_CASE)) {
                          if (dx > 0) {
                              if (!regionMatches(target, offset, con.limit, o2, literallen))
                                  return -1;
                              offset += literallen;
                          } else {
                              if (!regionMatches(target, offset-literallen, con.limit, o2, literallen))
                                  return -1;
                              offset -= literallen;
                          }
                      } else {
                          if (dx > 0) {
                              if (!regionMatchesIgnoreCase(target, offset, con.limit, o2, literallen))
                                  return -1;
                              offset += literallen;
                          } else {
                              if (!regionMatchesIgnoreCase(target, offset-literallen, con.limit,
                                                           o2, literallen))
                                  return -1;
                              offset -= literallen;
                          }
                      }
                  }
                  op = op.next;
                  break;
              case Op.STRING:
                  {
                      String literal = op.getString();
                      int literallen = literal.length();
                      if (!isSet(opts, IGNORE_CASE)) {
                          if (dx > 0) {
                              if (!regionMatches(target, offset, con.limit, literal, literallen))
                                  return -1;
                              offset += literallen;
                          } else {
                              if (!regionMatches(target, offset-literallen, con.limit, literal, literallen))
                                  return -1;
                              offset -= literallen;
                          }
                      } else {
                          if (dx > 0) {
                              if (!regionMatchesIgnoreCase(target, offset, con.limit, literal, literallen))
                                  return -1;
                              offset += literallen;
                          } else {
                              if (!regionMatchesIgnoreCase(target, offset-literallen, con.limit,
                                                           literal, literallen))
                                  return -1;
                              offset -= literallen;
                          }
                      }
                  }
                  op = op.next;
                  break;

              case Op.CLOSURE:
                  {
                      /*
                       * Saves current position to avoid
                       * zero-width repeats.
                       */
                      int id = op.getData();
                      if (id >= 0) {
                          int previousOffset = con.offsets[id];
                          if (previousOffset < 0 || previousOffset != offset) {
                              con.offsets[id] = offset;
                          } else {
                              con.offsets[id] = -1;
                              op = op.next;
                              break;
                          }
                      }
                      
                      int ret = this. matchCharacterIterator (con, op.getChild(), offset, dx, opts);
                      if (id >= 0)  con.offsets[id] = -1;
                      if (ret >= 0)  return ret;
                      op = op.next;
                  }
                  break;

              case Op.QUESTION:
                  {
                      int ret = this. matchCharacterIterator (con, op.getChild(), offset, dx, opts);
                      if (ret >= 0)  return ret;
                      op = op.next;
                  }
                  break;

              case Op.NONGREEDYCLOSURE:
              case Op.NONGREEDYQUESTION:
                  {
                      int ret = this. matchCharacterIterator (con, op.next, offset, dx, opts);
                      if (ret >= 0)  return ret;
                      op = op.getChild();
                  }
                  break;

              case Op.UNION:
                  for (int i = 0;  i < op.size();  i ++) {
                      int ret = this. matchCharacterIterator (con, op.elementAt(i), offset, dx, opts);
                      if (DEBUG) {
                          System.err.println("UNION: "+i+", ret="+ret);
                      }
                      if (ret >= 0)  return ret;
                  }
                  return -1;

              case Op.CAPTURE:
                  int refno = op.getData();
                  if (con.match != null && refno > 0) {
                      int save = con.match.getBeginning(refno);
                      con.match.setBeginning(refno, offset);
                      int ret = this. matchCharacterIterator (con, op.next, offset, dx, opts);
                      if (ret < 0)  con.match.setBeginning(refno, save);
                      return ret;
                  } else if (con.match != null && refno < 0) {
                      int index = -refno;
                      int save = con.match.getEnd(index);
                      con.match.setEnd(index, offset);
                      int ret = this. matchCharacterIterator (con, op.next, offset, dx, opts);
                      if (ret < 0)  con.match.setEnd(index, save);
                      return ret;
                  }
                  op = op.next;
                  break;

              case Op.LOOKAHEAD:
                  if (0 > this. matchCharacterIterator (con, op.getChild(), offset, 1, opts))  return -1;
                  op = op.next;
                  break;
              case Op.NEGATIVELOOKAHEAD:
                  if (0 <= this. matchCharacterIterator (con, op.getChild(), offset, 1, opts))  return -1;
                  op = op.next;
                  break;
              case Op.LOOKBEHIND:
                  if (0 > this. matchCharacterIterator (con, op.getChild(), offset, -1, opts))  return -1;
                  op = op.next;
                  break;
              case Op.NEGATIVELOOKBEHIND:
                  if (0 <= this. matchCharacterIterator (con, op.getChild(), offset, -1, opts))  return -1;
                  op = op.next;
                  break;

              case Op.INDEPENDENT:
                  {
                      int ret = this. matchCharacterIterator (con, op.getChild(), offset, dx, opts);
                      if (ret < 0)  return ret;
                      offset = ret;
                      op = op.next;
                  }
                  break;

              case Op.MODIFIER:
                  {
                      int localopts = opts;
                      localopts |= op.getData();
                      localopts &= ~op.getData2();
                      //System.err.println("MODIFIER: "+Integer.toString(opts, 16)+" -> "+Integer.toString(localopts, 16));
                      int ret = this. matchCharacterIterator (con, op.getChild(), offset, dx, localopts);
                      if (ret < 0)  return ret;
                      offset = ret;
                      op = op.next;
                  }
                  break;

              case Op.CONDITION:
                  {
                      Op.ConditionOp cop = (Op.ConditionOp)op;
                      boolean matchp = false;
                      if (cop.refNumber > 0) {
                          if (cop.refNumber >= this.nofparen)
                              throw new RuntimeException("Internal Error: Reference number must be more than zero: "+cop.refNumber);
                          matchp = con.match.getBeginning(cop.refNumber) >= 0
                                   && con.match.getEnd(cop.refNumber) >= 0;
                      } else {
                          matchp = 0 <= this. matchCharacterIterator (con, cop.condition, offset, dx, opts);
                      }

                      if (matchp) {
                          op = cop.yes;
                      } else if (cop.no != null) {
                          op = cop.no;
                      } else {
                          op = cop.next;
                      }
                  }
                  break;

              default:
                  throw new RuntimeException("Unknown operation type: "+op.type);
              } // switch (op.type)
          } // while