gt:         byte[] b = new byte[(int) (last - first) + 512];
context: /*
   * #%L
   * OME Bio-Formats package for reading and converting biological file formats.
   * %%
   * Copyright (C) 2005 - 2012 Open Microscopy Environment:
   *   - Board of Regents of the University of Wisconsin-Madison
   *   - Glencoe Software, Inc.
   *   - University of Dundee
   * %%
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as
   * published by the Free Software Foundation, either version 2 of the 
   * License, or (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public 
   * License along with this program.  If not, see
   * <http://www.gnu.org/licenses/gpl-2.0.html>.
   * #L%
   */
  
  package loci.formats.in;
  
  import java.io.IOException;
  import java.util.Vector;
  
  import loci.common.ByteArrayHandle;
  import loci.common.Location;
  import loci.common.RandomAccessInputStream;
  import loci.formats.ChannelSeparator;
  import loci.formats.CoreMetadata;
  import loci.formats.FormatException;
  import loci.formats.FormatReader;
  import loci.formats.FormatTools;
  import loci.formats.IFormatReader;
  import loci.formats.MetadataTools;
  import loci.formats.codec.CodecOptions;
  import loci.formats.codec.LZOCodec;
  import loci.formats.meta.MetadataStore;
  import ome.xml.model.primitives.PositiveFloat;
  
  /**
   * OpenlabReader is the file format reader for Openlab LIFF files.
   *
   * <dl><dt><b>Source code:</b></dt>
   * <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/bio-formats/src/loci/formats/in/OpenlabReader.java">Trac</a>,
   * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/in/OpenlabReader.java;hb=HEAD">Gitweb</a></dd></dl>
   *
   * @author Melissa Linkert melissa at glencoesoftware.com
   * @author Eric Kjellman egkjellman at wisc.edu
   * @author Curtis Rueden ctrueden at wisc.edu
   * @author Jim Paris jim at jtan.com
   */
  public class OpenlabReader extends FormatReader {
  
    // -- Constants --
  
    public static final long LIFF_MAGIC_BYTES = 0xffff696d7072L;
  
    /** Image types. */
    private static final int MAC_1_BIT = 1;
    private static final int MAC_4_GREYS = 2;
    private static final int MAC_16_GREYS = 3;
    private static final int MAC_16_COLORS = 4;
    private static final int MAC_256_GREYS = 5;
    private static final int MAC_256_COLORS = 6;
    private static final int MAC_16_BIT_COLOR = 7;
    private static final int MAC_24_BIT_COLOR = 8;
    private static final int DEEP_GREY_9 = 9;
    private static final int DEEP_GREY_10 = 10;
    private static final int DEEP_GREY_11 = 11;
    private static final int DEEP_GREY_12 = 12;
    private static final int DEEP_GREY_13 = 13;
    private static final int DEEP_GREY_14 = 14;
    private static final int DEEP_GREY_15 = 15;
    private static final int DEEP_GREY_16 = 16;
  
    /** Tag types. */
    private static final int IMAGE_TYPE_1 = 67;
    private static final int IMAGE_TYPE_2 = 68;
    private static final int CALIBRATION = 69;
    private static final int USER = 72;
  
    // -- Static fields --
  
    /** Helper reader to read PICT data. */
    private PictReader pict = new PictReader();
  
    // -- Fields --
  
    /** LIFF version (should be 2 or 5). */
    private int version;
  
    /** Number of series. */
    private int numSeries;
  
    private PlaneInfo[] planes;
    private float xcal, ycal;
  
    private long nextTag = 0;
    private int tag = 0, subTag = 0;
    private String fmt = "";
    private int[][] planeOffsets;
  
    private Vector<byte[][]> luts;
    private int lastPlane = 0;
  
    private String gain, detectorOffset, xPos, yPos, zPos;
    private boolean specialPlateNames = false;
  
    // -- Constructor --
  
    /** Constructs a new OpenlabReader. */
    public OpenlabReader() {
      super("Openlab LIFF", "liff");
      suffixNecessary = false;
      domains = new String[] {FormatTools.UNKNOWN_DOMAIN};
    }
  
    // -- IFormatReader API methods --
  
    /* @see loci.formats.IFormatReader#getOptimalTileHeight() */
    public int getOptimalTileHeight() {
      FormatTools.assertId(currentId, true, 1);
      return getSizeY();
    }
  
    /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */
    public boolean isThisType(RandomAccessInputStream stream) throws IOException {
      final int blockLen = 8;
      if (!FormatTools.validStream(stream, blockLen, false)) return false;
      return stream.readLong() == LIFF_MAGIC_BYTES;
    }
  
    /* @see loci.formats.IFormatReader#get8BitLookupTable() */
    public byte[][] get8BitLookupTable() {
      if (luts != null) {
        if (getSeries() < planeOffsets.length &&
          lastPlane < planeOffsets[getSeries()].length)
        {
          return luts.get(planeOffsets[getSeries()][lastPlane]);
        }
        else if (lastPlane < luts.size()) {
          return luts.get(lastPlane);
        }
      }
      return null;
    }
  
    /**
     * @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int)
     */
    public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h)
      throws FormatException, IOException
    {
      FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h);
  
      lastPlane = no;
  
      PlaneInfo planeInfo = null;
      if (specialPlateNames) {
        planeInfo = getPlane(getZCTCoords(no));
      }
      else if (no < planeOffsets[getSeries()].length) {
        int index = planeOffsets[getSeries()][no];
        planeInfo = planes[index];
      }
      if (planeInfo == null) return buf;
  
      long first = planeInfo.planeOffset;
      long last = first + FormatTools.getPlaneSize(this) * 2;
  
      int bpp = FormatTools.getBytesPerPixel(getPixelType());
  
      if (!planeInfo.pict) {
        if (version == 2) {
          in.seek(first);
          readPlane(in, x, y, w, h, buf);
        }
        else {
          in.seek(first + 16);
          int bytes = bpp * getRGBChannelCount();
          byte[] b = new byte[(int) (last - first)];
          in.read(b);
  
          CodecOptions options = new CodecOptions();
          options.width = getSizeX();
          options.height = getSizeY();
          options.bitsPerSample = bytes * 8;
          options.maxBytes = getSizeX() * getSizeY() * bytes;
          b = new LZOCodec().decompress(b, options);
  
          if (getSizeX() * getSizeY() * 4 <= b.length) {
            for (int yy=y; yy<h + y; yy++) {
              for (int xx=x; xx<w + x; xx++) {
                System.arraycopy(b, (yy*(getSizeX()+4) + xx)*4 + 1, buf,
                  ((yy - y)*w + xx - x)*3, 3);
              }
            }
          }
          else {
            int src = b.length / getSizeY();
            if (src - (getSizeX() * bytes) != 16) src = getSizeX() * bytes;
            int dest = w * bytes;
            for (int row=0; row<h; row++) {
              System.arraycopy(b, (row + y)*src + x*bytes, buf, row*dest, dest);
            }
          }
          b = null;
        }
        if (planeInfo.volumeType == MAC_256_GREYS ||
          planeInfo.volumeType == MAC_256_COLORS)
        {
          for (int i=0; i<buf.length; i++) {
            buf[i] = (byte) (~buf[i] & 0xff);
          }
        }
      }
      else {
        // PICT plane
        Exception exc = null;
        if (getPixelType() == FormatTools.UINT8) {
          in.seek(first);
  