Boyer Moore scan that proceeds backwards from the end of the file looking for ENDSIG
@throws NonScannableZipException
164303
private static boolean scanForEndSig(File file, FileChannel channel) throws IOException, NonScannableZipException {

        // TODO Consider just reading in MAX_REVERSE_SCAN bytes -- increased peak memory cost but less complex

        ByteBuffer bb = getByteBuffer(CHUNK_SIZE);
        long start = channel.size();
        long end = Math.max(0, start - MAX_REVERSE_SCAN);
        long channelPos = Math.max(0, start - CHUNK_SIZE);
        long lastChannelPos = channelPos;
        boolean firstRead = true;
        while (lastChannelPos >= end) {

            read(bb, channel, channelPos);

            int actualRead = bb.limit();
            if (firstRead) {
                long expectedRead = Math.min(CHUNK_SIZE, start);
                if (actualRead > expectedRead) {
                    // File is still growing
                    return false;
                }
                firstRead = false;
            }

            int bufferPos = actualRead -1;
            while (bufferPos >= SIG_PATTERN_LENGTH) {

                // Following is based on the Boyer Moore algorithm but simplified to reflect
                // a) the pattern is static
                // b) the pattern has no repeating bytes

                int patternPos;
                for (patternPos = SIG_PATTERN_LENGTH - 1;
                     patternPos >= 0 && ENDSIG_PATTERN[patternPos] == bb.get(bufferPos - patternPos);
                     --patternPos) {
                    // empty loop while bytes match
                }

                // Switch gives same results as checking the "good suffix array" in the Boyer Moore algorithm
                switch (patternPos) {
                    case -1: {
                        // Pattern matched. Confirm is this is the start of a valid end of central dir record
                        long startEndRecord = channelPos + bufferPos - SIG_PATTERN_LENGTH + 1;
                        if (validateEndRecord(file, channel, startEndRecord)) {
                            return true;
                        }
                        // wasn't a valid end record; continue scan
                        bufferPos -= 4;
                        break;
                    }
                    case 3: {
                        // No bytes matched; the common case.
                        // With our pattern, this is the only case where the Boyer Moore algorithm's "bad char array" may
                        // produce a shift greater than the "good suffix array" (which would shift 1 byte)
                        int idx = bb.get(bufferPos - patternPos) - Byte.MIN_VALUE;
                        bufferPos -= END_BAD_BYTE_SKIP[idx];
                        break;
                    }
                    default:
                        // 1 or more bytes matched
                        bufferPos -= 4;
                }
            }

            // Move back a full chunk. If we didn't read a full chunk, that's ok,
            // it means we read all data and the outer while loop will terminate
            if (channelPos <= bufferPos) {
                break;
            }
            lastChannelPos = channelPos;
            channelPos -= Math.min(channelPos - bufferPos, CHUNK_SIZE - bufferPos);
        }

        return false;
    }
147114
public function peekToEnd()
    {
        return substr($this->string, $this->scanOffset, strlen($this->string) - $this->scanOffset);        
    }
223137
def _readuntil(f, end=_TYPE_END):
	""""""
	buf = bytearray()
	byte = f.read(1)
	while byte != end:
		if byte == b'':
			raise ValueError('File ended unexpectedly. Expected end byte {}.'.format(end))
		buf += byte
		byte = f.read(1)
	return buf
1326866
def pre_scan(self):
        
        escape_re = re.compile(r'\\\n[\t ]+')
        self.source = escape_re.sub('', self.source)
50408
public void reverse(int start) {
    int end = size - 1;
    int num = end - start >> 1;
    for (int i = 0; i <= num; i++) {
      int j = start + i;
      int k = end - i;
      char c = buf[k];
      buf[k] = buf[j];
      buf[j] = c;
    }
  }
236325
public void endBranch(int endOffset)
    {
        if (mBranchBuffer != null) {
            if (endOffset > mBranchStartOffset) {
                appendBranched(mBranchStartOffset, endOffset);
            }
            // Let's also make sure no branching is done from this point on:
            mBranchBuffer = null;
        }
    }
215377
function scanTemplate() {
        var cooked = '', ch, start, rawOffset, terminated, head, tail, restore, unescaped;

        terminated = false;
        tail = false;
        start = index;
        head = (source[index] === '`');
        rawOffset = 2;

        ++index;

        while (index < length) {
            ch = source[index++];
            if (ch === '`') {
                rawOffset = 1;
                tail = true;
                terminated = true;
                break;
            } else if (ch === '$') {
                if (source[index] === '{') {
                    state.curlyStack.push('${');
                    ++index;
                    terminated = true;
                    break;
                }
                cooked += ch;
            } else if (ch === '\\') {
                ch = source[index++];
                if (!isLineTerminator(ch.charCodeAt(0))) {
                    switch (ch) {
                    case 'n':
                        cooked += '\n';
                        break;
                    case 'r':
                        cooked += '\r';
                        break;
                    case 't':
                        cooked += '\t';
                        break;
                    case 'u':
                    case 'x':
                        if (source[index] === '{') {
                            ++index;
                            cooked += scanUnicodeCodePointEscape();
                        } else {
                            restore = index;
                            unescaped = scanHexEscape(ch);
                            if (unescaped) {
                                cooked += unescaped;
                            } else {
                                index = restore;
                                cooked += ch;
                            }
                        }
                        break;
                    case 'b':
                        cooked += '\b';
                        break;
                    case 'f':
                        cooked += '\f';
                        break;
                    case 'v':
                        cooked += '\v';
                        break;

                    default:
                        if (ch === '0') {
                            if (isDecimalDigit(source.charCodeAt(index))) {
                                // Illegal: \01 \02 and so on
                                throwError(Messages.TemplateOctalLiteral);
                            }
                            cooked += '\0';
                        } else if (isOctalDigit(ch)) {
                            // Illegal: \1 \2
                            throwError(Messages.TemplateOctalLiteral);
                        } else {
                            cooked += ch;
                        }
                        break;
                    }
                } else {
                    ++lineNumber;
                    if (ch === '\r' && source[index] === '\n') {
                        ++index;
                    }
                    lineStart = index;
                }
            } else if (isLineTerminator(ch.charCodeAt(0))) {
                ++lineNumber;
                if (ch === '\r' && source[index] === '\n') {
                    ++index;
                }
                lineStart = index;
                cooked += '\n';
            } else {
                cooked += ch;
            }
        }

        if (!terminated) {
            throwUnexpectedToken();
        }

        if (!head) {
            state.curlyStack.pop();
        }

        return {
            type: Token.Template,
            value: {
                cooked: cooked,
                raw: source.slice(start + 1, index - rawOffset)
            },
            head: head,
            tail: tail,
            lineNumber: lineNumber,
            lineStart: lineStart,
            start: start,
            end: index
        };
    }
555678
private boolean isEndOfLine(int c) throws IOException {
        // check if we have \r\n...
        if (c == '\r') {
            if (in.lookAhead() == '\n') {
                // note: does not change c outside of this method !!
                c = in.read();
            }
        }
        return (c == '\n');
    }
1283930
public static boolean isCompleteZip(File file) throws IOException, NonScannableZipException {

        FileChannel channel = null;
        try {
            channel = new FileInputStream(file).getChannel();

            long size = channel.size();
            if (size < ENDLEN) { // Obvious case
                return false;
            }
            else if (validateEndRecord(file, channel, size - ENDLEN)) { // typical case where file is complete and end record has no comment
                return true;
            }

            // Either file is incomplete or the end of central directory record includes an arbitrary length comment
            // So, we have to scan backwards looking for an end of central directory record
            return scanForEndSig(file, channel);
        }
        finally {
            safeClose(channel);
        }
    }
1094769
static public void scanRoot(File root,
                                Set<String> suffixes,
                                List<String> excludes, List<String> includes,
                                List<String> excludeFiles, List<String> includeFiles,
                                Map<String,Source> foundFiles,
                                Map<String,Module> foundModules,
                                Module currentModule,
                                boolean permitSourcesWithoutPackage,
                                boolean inGensrc,
                                boolean inLinksrc)
        throws ProblemException {

        if (root == null) return;
        int root_prefix = root.getPath().length()+1;
        // This is the root source directory, it must not contain any Java sources files
        // because we do not allow Java source files without a package.
        // (Unless of course --permit-sources-without-package has been specified.)
        // It might contain other source files however, (for -tr and -copy) these will
        // always be included, since no package pattern can match the root directory.
        currentModule = addFilesInDir(root, root_prefix, root, suffixes, permitSourcesWithoutPackage,
                                       excludeFiles, includeFiles, false,
                                       foundFiles, foundModules, currentModule,
                                       inGensrc, inLinksrc);

        File[] dirfiles = root.listFiles();
        for (File d : dirfiles) {
            if (d.isDirectory()) {
                // Descend into the directory structure.
                scanDirectory(d, root_prefix, root, suffixes,
                              excludes, includes, excludeFiles, includeFiles,
                              false, foundFiles, foundModules, currentModule, inGensrc, inLinksrc);
            }
        }
    }
55137
int nextIndexOf(char c) {
        // doesn't handle scanning for surrogates
        bufferUp();
        for (int i = bufPos; i < bufLength; i++) {
            if (c == charBuf[i])
                return i - bufPos;
        }
        return -1;
    }
1052806
@SuppressWarnings("fallthrough")
    private boolean findSection(int offset, Position pos)
    {
        int i = offset, len = rawBytes.length;
        int last = offset;
        int next;
        boolean allBlank = true;

        pos.endOfFirstLine = -1;

        while (i < len) {
            byte b = rawBytes[i];
            switch(b) {
            case '\r':
                if (pos.endOfFirstLine == -1)
                    pos.endOfFirstLine = i-1;
                if ((i < len) &&  (rawBytes[i+1] == '\n'))
                    i++;
                /* fall through */
            case '\n':
                if (pos.endOfFirstLine == -1)
                    pos.endOfFirstLine = i-1;
                if (allBlank || (i == len-1)) {
                    if (i == len-1)
                        pos.endOfSection = i;
                    else
                        pos.endOfSection = last;
                    pos.startOfNext = i+1;
                    return true;
                }
                else {
                    // start of a new line
                    last = i;
                    allBlank = true;
                }
                break;
            default:
                allBlank = false;
                break;
            }
            i++;
        }
        return false;
    }
971830
@Override
    public int previous() {
        int result;
        int startPos;

        CharacterIterator text = getText();

        fLastStatusIndexValid = false;

        // if we have cached break positions and we're still in the range
        // covered by them, just move one step backward in the cache
        if (fCachedBreakPositions != null) {
            if (fPositionInCache > 0) {
                --fPositionInCache;
                // If we're at the beginning of the cache, need to reevaluate the
                // rule status
                if (fPositionInCache <= 0) {
                    fLastStatusIndexValid = false;
                }
                int pos = fCachedBreakPositions[fPositionInCache];
                text.setIndex(pos);
                return pos;
            } else {
                reset();
            }
        }

        // if we're already sitting at the beginning of the text, return DONE
        startPos = current();
        if (fText == null || startPos == fText.getBeginIndex()) {
            fLastRuleStatusIndex  = 0;
            fLastStatusIndexValid = true;
            return BreakIterator.DONE;
        }

        // Rules with an exact reverse table are handled here.
        if (fRData.fSRTable != null || fRData.fSFTable != null) {
            result =  handlePrevious(fRData.fRTable);
            if (fDictionaryCharCount > 0) {
                result = checkDictionary(result, startPos, true);
            }
            return result;
        }

        // old rule syntax
        // set things up.  handlePrevious() will back us up to some valid
        // break position before the current position (we back our internal
        // iterator up one step to prevent handlePrevious() from returning
        // the current position), but not necessarily the last one before
        // where we started

        int       start = current();

        previous32(fText);
        int       lastResult    = handlePrevious(fRData.fRTable);
        if (lastResult == BreakIterator.DONE) {
            lastResult = fText.getBeginIndex();
            fText.setIndex(lastResult);
        }
        result = lastResult;
        int      lastTag       = 0;
        boolean  breakTagValid = false;

        // iterate forward from the known break position until we pass our
        // starting point.  The last break position before the starting
        // point is our return value

        for (;;) {
            result         = next();
            if (result == BreakIterator.DONE || result >= start) {
                break;
            }
            lastResult     = result;
            lastTag        = fLastRuleStatusIndex;
            breakTagValid  = true;
        }

        // fLastBreakTag wants to have the value for section of text preceding
        // the result position that we are to return (in lastResult.)  If
        // the backwards rules overshot and the above loop had to do two or more
        // handleNext()s to move up to the desired return position, we will have a valid
        // tag value. But, if handlePrevious() took us to exactly the correct result position,
        // we wont have a tag value for that position, which is only set by handleNext().

        // Set the current iteration position to be the last break position
        // before where we started, and then return that value.
        fText.setIndex(lastResult);
        fLastRuleStatusIndex  = lastTag;       // for use by getRuleStatus()
        fLastStatusIndexValid = breakTagValid;
        return lastResult;
    }
551210
@Override
    public int preceding(int offset) {
        CharacterIterator text = getText();

        // if we have no cached break positions, or "offset" is outside the
        // range covered by the cache, we can just call the inherited routine
        // (which will eventually call other routines in this class that may
        // refresh the cache)
        if (fCachedBreakPositions == null || offset <= fCachedBreakPositions[0] ||
                offset > fCachedBreakPositions[fCachedBreakPositions.length - 1]) {
            fCachedBreakPositions = null;
            return rulesPreceding(offset);
        }

        // on the other hand, if "offset" is within the range covered by the cache,
        // then all we have to do is search the cache for the last break position
        // before "offset"
        else {
            fPositionInCache = 0;
            while (fPositionInCache < fCachedBreakPositions.length
                   && offset > fCachedBreakPositions[fPositionInCache])
                ++fPositionInCache;
            --fPositionInCache;
            text.setIndex(fCachedBreakPositions[fPositionInCache]);
            return text.getIndex();
        }
    }
569800
public void scan(String source)  {
    String input = source + "\n%_FEATURE_END_%";
    byte[] data = null;
    try {
      data = input.getBytes("UTF-8");
    } catch(UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
    int cs, p = 0, pe = data.length;
    int eof = pe;

    int lineNumber = 1;
    int lastNewline = 0;

    int contentStart = -1;
    int currentLine = -1;
    int docstringContentTypeStart = -1;
    int docstringContentTypeEnd = -1;
    int startCol = -1;
    int nextKeywordStart = -1;
    int keywordStart = -1;
    String keyword = null;
    List<String> currentRow = null;

    
// line 657 "java/src/main/java/gherkin/lexer/Fr.java"
	{
	cs = lexer_start;
	}

// line 185 "ragel/i18n/fr.java.rl"
    
// line 664 "java/src/main/java/gherkin/lexer/Fr.java"
	{
	int _klen;
	int _trans = 0;
	int _acts;
	int _nacts;
	int _keys;
	int _goto_targ = 0;

	_goto: while (true) {
	switch ( _goto_targ ) {
	case 0:
	if ( p == pe ) {
		_goto_targ = 4;
		continue _goto;
	}
	if ( cs == 0 ) {
		_goto_targ = 5;
		continue _goto;
	}
case 1:
	_match: do {
	_keys = _lexer_key_offsets[cs];
	_trans = _lexer_index_offsets[cs];
	_klen = _lexer_single_lengths[cs];
	if ( _klen > 0 ) {
		int _lower = _keys;
		int _mid;
		int _upper = _keys + _klen - 1;
		while (true) {
			if ( _upper < _lower )
				break;

			_mid = _lower + ((_upper-_lower) >> 1);
			if ( data[p] < _lexer_trans_keys[_mid] )
				_upper = _mid - 1;
			else if ( data[p] > _lexer_trans_keys[_mid] )
				_lower = _mid + 1;
			else {
				_trans += (_mid - _keys);
				break _match;
			}
		}
		_keys += _klen;
		_trans += _klen;
	}

	_klen = _lexer_range_lengths[cs];
	if ( _klen > 0 ) {
		int _lower = _keys;
		int _mid;
		int _upper = _keys + (_klen<<1) - 2;
		while (true) {
			if ( _upper < _lower )
				break;

			_mid = _lower + (((_upper-_lower) >> 1) & ~1);
			if ( data[p] < _lexer_trans_keys[_mid] )
				_upper = _mid - 2;
			else if ( data[p] > _lexer_trans_keys[_mid+1] )
				_lower = _mid + 2;
			else {
				_trans += ((_mid - _keys)>>1);
				break _match;
			}
		}
		_trans += _klen;
	}
	} while (false);

	_trans = _lexer_indicies[_trans];
	cs = _lexer_trans_targs[_trans];

	if ( _lexer_trans_actions[_trans] != 0 ) {
		_acts = _lexer_trans_actions[_trans];
		_nacts = (int) _lexer_actions[_acts++];
		while ( _nacts-- > 0 )
	{
			switch ( _lexer_actions[_acts++] )
			{
	case 0:
// line 16 "ragel/i18n/fr.java.rl"
	{
      contentStart = p;
      currentLine = lineNumber;
      if(keyword != null) {
        startCol = p - lastNewline - (keyword.length() + 1);
      }
    }
	break;
	case 1:
// line 24 "ragel/i18n/fr.java.rl"
	{
      currentLine = lineNumber;
      startCol = p - lastNewline;
    }
	break;
	case 2:
// line 29 "ragel/i18n/fr.java.rl"
	{
      contentStart = p;
    }
	break;
	case 3:
// line 33 "ragel/i18n/fr.java.rl"
	{
      docstringContentTypeStart = p;
    }
	break;
	case 4:
// line 37 "ragel/i18n/fr.java.rl"
	{
      docstringContentTypeEnd = p;
    }
	break;
	case 5:
// line 41 "ragel/i18n/fr.java.rl"
	{
      String con = unindent(startCol, substring(data, contentStart, nextKeywordStart-1).replaceFirst("(\\r?\\n)?([\\t ])*\\Z", "").replace("\\\"\\\"\\\"", "\"\"\""));
      String conType = substring(data, docstringContentTypeStart, docstringContentTypeEnd).trim();
      listener.docString(conType, con, currentLine);
    }
	break;
	case 6:
// line 47 "ragel/i18n/fr.java.rl"
	{
      String[] nameDescription = nameAndUnindentedDescription(startCol, keywordContent(data, p, eof, nextKeywordStart, contentStart));
      listener.feature(keyword, nameDescription[0], nameDescription[1], currentLine);
      if(nextKeywordStart != -1) p = nextKeywordStart - 1;
      nextKeywordStart = -1;
    }
	break;
	case 7:
// line 54 "ragel/i18n/fr.java.rl"
	{
      String[] nameDescription = nameAndUnindentedDescription(startCol, keywordContent(data, p, eof, nextKeywordStart, contentStart));
      listener.background(keyword, nameDescription[0], nameDescription[1], currentLine);
      if(nextKeywordStart != -1) p = nextKeywordStart - 1;
      nextKeywordStart = -1;
    }
	break;
	case 8:
// line 61 "ragel/i18n/fr.java.rl"
	{
      String[] nameDescription = nameAndUnindentedDescription(startCol, keywordContent(data, p, eof, nextKeywordStart, contentStart));
      listener.scenario(keyword, nameDescription[0], nameDescription[1], currentLine);
      if(nextKeywordStart != -1) p = nextKeywordStart - 1;
      nextKeywordStart = -1;
    }
	break;
	case 9:
// line 68 "ragel/i18n/fr.java.rl"
	{
      String[] nameDescription = nameAndUnindentedDescription(startCol, keywordContent(data, p, eof, nextKeywordStart, contentStart));
      listener.scenarioOutline(keyword, nameDescription[0], nameDescription[1], currentLine);
      if(nextKeywordStart != -1) p = nextKeywordStart - 1;
      nextKeywordStart = -1;
    }
	break;
	case 10:
// line 75 "ragel/i18n/fr.java.rl"
	{
      String[] nameDescription = nameAndUnindentedDescription(startCol, keywordContent(data, p, eof, nextKeywordStart, contentStart));
      listener.examples(keyword, nameDescription[0], nameDescription[1], currentLine);
      if(nextKeywordStart != -1) p = nextKeywordStart - 1;
      nextKeywordStart = -1;
    }
	break;
	case 11:
// line 82 "ragel/i18n/fr.java.rl"
	{
      listener.step(keyword, substring(data, contentStart, p).trim(), currentLine);
    }
	break;
	case 12:
// line 86 "ragel/i18n/fr.java.rl"
	{
      listener.comment(substring(data, contentStart, p).trim(), lineNumber);
      keywordStart = -1;
    }
	break;
	case 13:
// line 91 "ragel/i18n/fr.java.rl"
	{
      listener.tag(substring(data, contentStart, p).trim(), currentLine);
      keywordStart = -1;
    }
	break;
	case 14:
// line 96 "ragel/i18n/fr.java.rl"
	{
      lineNumber++;
    }
	break;
	case 15:
// line 100 "ragel/i18n/fr.java.rl"
	{
      lastNewline = p + 1;
    }
	break;
	case 16:
// line 104 "ragel/i18n/fr.java.rl"
	{
      if(keywordStart == -1) keywordStart = p;
    }
	break;
	case 17:
// line 108 "ragel/i18n/fr.java.rl"
	{
      keyword = substring(data, keywordStart, p).replaceFirst(":$","");
      keywordStart = -1;
    }
	break;
	case 18:
// line 113 "ragel/i18n/fr.java.rl"
	{
      nextKeywordStart = p;
    }
	break;
	case 19:
// line 117 "ragel/i18n/fr.java.rl"
	{
      p = p - 1;
      currentRow = new ArrayList<String>();
      currentLine = lineNumber;
    }
	break;
	case 20:
// line 123 "ragel/i18n/fr.java.rl"
	{
      contentStart = p;
    }
	break;
	case 21:
// line 127 "ragel/i18n/fr.java.rl"
	{
      String con = substring(data, contentStart, p).trim();
      currentRow.add(con
        .replace("\\|", "|")
        .replace("\\n", "\n")
        .replace("\\\\", "\\")
      );
    }
	break;
	case 22:
// line 136 "ragel/i18n/fr.java.rl"
	{
      listener.row(currentRow, currentLine);
    }
	break;
	case 23:
// line 140 "ragel/i18n/fr.java.rl"
	{
      if(cs < lexer_first_final) {
        String content = currentLineContent(data, lastNewline);
        throw new LexingError("Lexing error on line " + lineNumber + ": '" + content + "'. See http://wiki.github.com/cucumber/gherkin/lexingerror for more information.");
      } else {
        listener.eof();
      }
    }
	break;
// line 925 "java/src/main/java/gherkin/lexer/Fr.java"
			}
		}
	}

case 2:
	if ( cs == 0 ) {
		_goto_targ = 5;
		continue _goto;
	}
	if ( ++p != pe ) {
		_goto_targ = 1;
		continue _goto;
	}
case 4:
	if ( p == eof )
	{
	int __acts = _lexer_eof_actions[cs];
	int __nacts = (int) _lexer_actions[__acts++];
	while ( __nacts-- > 0 ) {
		switch ( _lexer_actions[__acts++] ) {
	case 23:
// line 140 "ragel/i18n/fr.java.rl"
	{
      if(cs < lexer_first_final) {
        String content = currentLineContent(data, lastNewline);
        throw new LexingError("Lexing error on line " + lineNumber + ": '" + content + "'. See http://wiki.github.com/cucumber/gherkin/lexingerror for more information.");
      } else {
        listener.eof();
      }
    }
	break;
// line 957 "java/src/main/java/gherkin/lexer/Fr.java"
		}
	}
	}

case 5:
	}
	break; }
	}

// line 186 "ragel/i18n/fr.java.rl"
  }
574787
int getShort(final long off) throws IOException, InterruptedException {
        if (off < 0 || off > zipFileSlice.len - 2) {
            throw new IndexOutOfBoundsException();
        }
        if (read(off, scratch, 0, 2) < 2) {
            throw new EOFException("Unexpected EOF");
        }
        return ((scratch[1] & 0xff) << 8) | (scratch[0] & 0xff);
    }
910528
public long skip(long n) throws IllegalArgumentException, IOException {

        if (lookaheadChar == UNDEFINED) {
            lookaheadChar = super.read();
        }

        // illegal argument
        if (n < 0) {
            throw new IllegalArgumentException("negative argument not supported");
        }

        // no skipping
        if (n == 0 || lookaheadChar == END_OF_STREAM) {
            return 0;
        }

        // skip and reread the lookahead-char
        long skiped = 0;
        if (n > 1) {
            skiped = super.skip(n - 1);
        }
        lookaheadChar = super.read();
        // fixme uh: we should check the skiped sequence for line-terminations...
        lineCounter = Integer.MIN_VALUE;
        return skiped + 1;
    }