private static long scanForEndSig ( final File file , final FileChannel channel , final ScanContext context ) throws IOException { // 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 ; while ( lastChannelPos >= end ) { read ( bb , channel , channelPos ) ; int actualRead = bb . limit ( ) ; 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 && context . matches ( 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 : { final State state = context . state ; // 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 , context . getSig ( ) ) ) { if ( state == State . FOUND ) { return startEndRecord ; } else { return - 1 ; } } // 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 -= 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 - 1 ; }
Boyer Moore scan that proceeds backwards from the end of the file looking for endsig