content: package org.apache.lucene.index;
  
  /**
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import org.apache.lucene.store.IndexInput;
  import org.apache.lucene.store.IndexOutput;
  import java.io.IOException;
  
  /* IndexInput that knows how to read the byte slices written
   * by Posting and PostingVector.  We read the bytes in
   * each slice until we hit the end of that slice at which
   * point we read the forwarding address of the next slice
   * and then jump to it.*/
  final class ByteSliceReader extends IndexInput {
    ByteBlockPool pool;
    int bufferUpto;
    byte[] buffer;
    public int upto;
    int limit;
    int level;
    public int bufferOffset;
  
    public int endIndex;
  
    public void init(ByteBlockPool pool, int startIndex, int endIndex) {
  
      assert endIndex-startIndex >= 0;
      assert startIndex >= 0;
      assert endIndex >= 0;
  
      this.pool = pool;
      this.endIndex = endIndex;
  
      level = 0;
      bufferUpto = startIndex / DocumentsWriter.BYTE_BLOCK_SIZE;
      bufferOffset = bufferUpto * DocumentsWriter.BYTE_BLOCK_SIZE;
      buffer = pool.buffers[bufferUpto];
      upto = startIndex & DocumentsWriter.BYTE_BLOCK_MASK;
  
      final int firstSize = ByteBlockPool.levelSizeArray[0];
  
      if (startIndex+firstSize >= endIndex) {
        // There is only this one slice to read
        limit = endIndex & DocumentsWriter.BYTE_BLOCK_MASK;
      } else
        limit = upto+firstSize-4;
    }
  
    public boolean eof() {
      assert upto + bufferOffset <= endIndex;
      return upto + bufferOffset == endIndex;
    }
  
    @Override
    public byte readByte() {
      assert !eof();
      assert upto <= limit;
      if (upto == limit)
        nextSlice();
      return buffer[upto++];
    }
  
    public long writeTo(IndexOutput out) throws IOException {
      long size = 0;
      while(true) {
        if (limit + bufferOffset == endIndex) {
          assert endIndex - bufferOffset >= upto;
          out.writeBytes(buffer, upto, limit-upto);
          size += limit-upto;
          break;
        } else {
          out.writeBytes(buffer, upto, limit-upto);
          size += limit-upto;
          nextSlice();
        }
      }
  
      return size;
    }
  
    public void nextSlice() {
  
      // Skip to our next slice
      final int nextIndex = ((buffer[limit]&0xff)<<24) + ((buffer[1+limit]&0xff)<<16) + ((buffer[2+limit]&0xff)<<8) + (buffer[3+limit]&0xff);
  
      level = ByteBlockPool.nextLevelArray[level];
      final int newSize = ByteBlockPool.levelSizeArray[level];
  
      bufferUpto = nextIndex / DocumentsWriter.BYTE_BLOCK_SIZE;
      bufferOffset = bufferUpto * DocumentsWriter.BYTE_BLOCK_SIZE;
  
      buffer = pool.buffers[bufferUpto];
      upto = nextIndex & DocumentsWriter.BYTE_BLOCK_MASK;
  
      if (nextIndex + newSize >= endIndex) {
        // We are advancing to the final slice
        assert endIndex - nextIndex > 0;
        limit = endIndex - bufferOffset;
      } else {
        // This is not the final slice (subtract 4 for the
        // forwarding address at the end of this new slice)
        limit = upto+newSize-4;
      }
    }
  
    @Override
    public void readBytes(byte[] b, int offset, int len) {
      while(len > 0) {
        final int numLeft = limit-upto;
        if (numLeft < len) {
          // Read entire slice
          System.arraycopy(buffer, upto, b, offset, numLeft);
          offset += numLeft;
          len -= numLeft;
          nextSlice();
        } else {
          // This slice is the last one
          System.arraycopy(buffer, upto, b, offset, len);
          upto += len;
          break;
        }
      }
    }
  
    @Override
    public long getFilePointer() {throw new RuntimeException("not implemented");}
    @Override
    public long length() {throw new RuntimeException("not implemented");}
    @Override
    public void seek(long pos) {throw new RuntimeException("not implemented");}
    @Override
    public void close() {throw new RuntimeException("not implemented");}
  }
  
  