1 /*
   2  * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.imageio.plugins.bmp;
  27 
  28 import java.awt.Point;
  29 import java.awt.Rectangle;
  30 import java.awt.Transparency;
  31 import java.awt.color.ColorSpace;
  32 import java.awt.color.ICC_ColorSpace;
  33 import java.awt.color.ICC_Profile;
  34 import java.awt.image.BufferedImage;
  35 import java.awt.image.ColorModel;
  36 import java.awt.image.ComponentColorModel;
  37 import java.awt.image.ComponentSampleModel;
  38 import java.awt.image.DataBuffer;
  39 import java.awt.image.DataBufferByte;
  40 import java.awt.image.DataBufferInt;
  41 import java.awt.image.DataBufferUShort;
  42 import java.awt.image.DirectColorModel;
  43 import java.awt.image.IndexColorModel;
  44 import java.awt.image.MultiPixelPackedSampleModel;
  45 import java.awt.image.PixelInterleavedSampleModel;
  46 import java.awt.image.Raster;
  47 import java.awt.image.SampleModel;
  48 import java.awt.image.SinglePixelPackedSampleModel;
  49 import java.awt.image.WritableRaster;
  50 
  51 import javax.imageio.IIOException;
  52 import javax.imageio.ImageIO;
  53 import javax.imageio.ImageReader;
  54 import javax.imageio.ImageReadParam;
  55 import javax.imageio.ImageTypeSpecifier;
  56 import javax.imageio.metadata.IIOMetadata;
  57 import javax.imageio.spi.ImageReaderSpi;
  58 import javax.imageio.stream.ImageInputStream;
  59 import javax.imageio.event.IIOReadProgressListener;
  60 import javax.imageio.event.IIOReadUpdateListener;
  61 import javax.imageio.event.IIOReadWarningListener;
  62 
  63 import java.io.*;
  64 import java.nio.*;
  65 import java.security.AccessController;
  66 import java.security.PrivilegedAction;
  67 import java.util.ArrayList;
  68 import java.util.Iterator;
  69 import java.util.StringTokenizer;
  70 
  71 import com.sun.imageio.plugins.common.ImageUtil;
  72 import com.sun.imageio.plugins.common.I18N;
  73 
  74 /** This class is the Java Image IO plugin reader for BMP images.
  75  *  It may subsample the image, clip the image, select sub-bands,
  76  *  and shift the decoded image origin if the proper decoding parameter
  77  *  are set in the provided {@code ImageReadParam}.
  78  *
  79  *  This class supports Microsoft Windows Bitmap Version 3-5,
  80  *  as well as OS/2 Bitmap Version 2.x (for single-image BMP file).
  81  *  It also supports undocumented DIB header of type BITMAPV2INFOHEADER
  82  *  & BITMAPV3INFOHEADER.
  83  */
  84 public class BMPImageReader extends ImageReader implements BMPConstants {
  85     // BMP Image types
  86     private static final int VERSION_2_1_BIT = 0;
  87     private static final int VERSION_2_4_BIT = 1;
  88     private static final int VERSION_2_8_BIT = 2;
  89     private static final int VERSION_2_24_BIT = 3;
  90 
  91     private static final int VERSION_3_1_BIT = 4;
  92     private static final int VERSION_3_4_BIT = 5;
  93     private static final int VERSION_3_8_BIT = 6;
  94     private static final int VERSION_3_24_BIT = 7;
  95 
  96     private static final int VERSION_3_NT_16_BIT = 8;
  97     private static final int VERSION_3_NT_32_BIT = 9;
  98 
  99     // All VERSION_3_EXT_* are for BITMAPV2INFOHEADER & BITMAPV3INFOHEADER
 100     private static final int VERSION_3_EXT_1_BIT = 10;
 101     private static final int VERSION_3_EXT_4_BIT = 11;
 102     private static final int VERSION_3_EXT_8_BIT = 12;
 103     private static final int VERSION_3_EXT_16_BIT = 13;
 104     private static final int VERSION_3_EXT_24_BIT = 14;
 105     private static final int VERSION_3_EXT_32_BIT = 15;
 106 
 107     private static final int VERSION_4_1_BIT = 16;
 108     private static final int VERSION_4_4_BIT = 17;
 109     private static final int VERSION_4_8_BIT = 18;
 110     private static final int VERSION_4_16_BIT = 19;
 111     private static final int VERSION_4_24_BIT = 20;
 112     private static final int VERSION_4_32_BIT = 21;
 113 
 114     private static final int VERSION_3_XP_EMBEDDED = 22;
 115     private static final int VERSION_3_EXT_EMBEDDED = 23;
 116     private static final int VERSION_4_XP_EMBEDDED = 24;
 117     private static final int VERSION_5_XP_EMBEDDED = 25;
 118 
 119     // BMP variables
 120     private long bitmapFileSize;
 121     private long bitmapOffset;
 122     private long bitmapStart;
 123     private long compression;
 124     private long imageSize;
 125     private byte[] palette;
 126     private int imageType;
 127     private int numBands;
 128     private boolean isBottomUp;
 129     private int bitsPerPixel;
 130     private int redMask, greenMask, blueMask, alphaMask;
 131 
 132     private SampleModel sampleModel, originalSampleModel;
 133     private ColorModel colorModel, originalColorModel;
 134 
 135     /** The input stream where reads from */
 136     private ImageInputStream iis = null;
 137 
 138     /** Indicates whether the header is read. */
 139     private boolean gotHeader = false;
 140 
 141     /** The original image width. */
 142     private int width;
 143 
 144     /** The original image height. */
 145     private int height;
 146 
 147     /** The destination region. */
 148     private Rectangle destinationRegion;
 149 
 150     /** The source region. */
 151     private Rectangle sourceRegion;
 152 
 153     /** The metadata from the stream. */
 154     private BMPMetadata metadata;
 155 
 156     /** The destination image. */
 157     private BufferedImage bi;
 158 
 159     /** Indicates whether subsampled, subregion is required, and offset is
 160      *  defined
 161      */
 162     private boolean noTransform = true;
 163 
 164     /** Indicates whether subband is selected. */
 165     private boolean seleBand = false;
 166 
 167     /** The scaling factors. */
 168     private int scaleX, scaleY;
 169 
 170     /** source and destination bands. */
 171     private int[] sourceBands, destBands;
 172 
 173     /** Constructs {@code BMPImageReader} from the provided
 174      *  {@code ImageReaderSpi}.
 175      */
 176     public BMPImageReader(ImageReaderSpi originator) {
 177         super(originator);
 178     }
 179 
 180     /** Overrides the method defined in the superclass. */
 181     public void setInput(Object input,
 182                          boolean seekForwardOnly,
 183                          boolean ignoreMetadata) {
 184         super.setInput(input, seekForwardOnly, ignoreMetadata);
 185         iis = (ImageInputStream) input; // Always works
 186         if(iis != null)
 187             iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
 188         resetHeaderInfo();
 189     }
 190 
 191     /** Overrides the method defined in the superclass. */
 192     public int getNumImages(boolean allowSearch) throws IOException {
 193         if (iis == null) {
 194             throw new IllegalStateException(I18N.getString("GetNumImages0"));
 195         }
 196         if (seekForwardOnly && allowSearch) {
 197             throw new IllegalStateException(I18N.getString("GetNumImages1"));
 198         }
 199         return 1;
 200     }
 201 
 202     @Override
 203     public int getWidth(int imageIndex) throws IOException {
 204         checkIndex(imageIndex);
 205         try {
 206             readHeader();
 207         } catch (IllegalArgumentException e) {
 208             throw new IIOException(I18N.getString("BMPImageReader6"), e);
 209         }
 210         return width;
 211     }
 212 
 213     public int getHeight(int imageIndex) throws IOException {
 214         checkIndex(imageIndex);
 215         try {
 216             readHeader();
 217         } catch (IllegalArgumentException e) {
 218             throw new IIOException(I18N.getString("BMPImageReader6"), e);
 219         }
 220         return height;
 221     }
 222 
 223     private void checkIndex(int imageIndex) {
 224         if (imageIndex != 0) {
 225             throw new IndexOutOfBoundsException(I18N.getString("BMPImageReader0"));
 226         }
 227     }
 228 
 229     /**
 230      * Process the image header.
 231      *
 232      * @exception IllegalStateException if source stream is not set.
 233      *
 234      * @exception IOException if image stream is corrupted.
 235      *
 236      * @exception IllegalArgumentException if the image stream does not contain
 237      *             a BMP image, or if a sample model instance to describe the
 238      *             image can not be created.
 239      */
 240     protected void readHeader() throws IOException, IllegalArgumentException {
 241         if (gotHeader)
 242             return;
 243 
 244         if (iis == null) {
 245             throw new IllegalStateException("Input source not set!");
 246         }
 247         int profileData = 0, profileSize = 0;
 248 
 249         this.metadata = new BMPMetadata();
 250         iis.mark();
 251 
 252         // read and check the magic marker
 253         byte[] marker = new byte[2];
 254         iis.read(marker);
 255         if (marker[0] != 0x42 || marker[1] != 0x4d)
 256             throw new IllegalArgumentException(I18N.getString("BMPImageReader1"));
 257 
 258         // Read file size
 259         bitmapFileSize = iis.readUnsignedInt();
 260         // skip the two reserved fields
 261         iis.skipBytes(4);
 262 
 263         // Offset to the bitmap from the beginning
 264         bitmapOffset = iis.readUnsignedInt();
 265         // End File Header
 266 
 267         // Start BitmapCoreHeader
 268         long size = iis.readUnsignedInt();
 269 
 270         if (size == 12) {
 271             width = iis.readShort();
 272             height = iis.readShort();
 273         } else {
 274             width = iis.readInt();
 275             height = iis.readInt();
 276         }
 277 
 278         metadata.width = width;
 279         metadata.height = height;
 280 
 281         int planes = iis.readUnsignedShort();
 282         bitsPerPixel = iis.readUnsignedShort();
 283 
 284         //metadata.colorPlane = planes;
 285         metadata.bitsPerPixel = (short)bitsPerPixel;
 286 
 287         // As BMP always has 3 rgb bands, except for Version 5,
 288         // which is bgra
 289         numBands = 3;
 290 
 291         if (size == 12) {
 292             // Windows 2.x and OS/2 1.x
 293             metadata.bmpVersion = VERSION_2;
 294 
 295             // Classify the image type
 296             if (bitsPerPixel == 1) {
 297                 imageType = VERSION_2_1_BIT;
 298             } else if (bitsPerPixel == 4) {
 299                 imageType = VERSION_2_4_BIT;
 300             } else if (bitsPerPixel == 8) {
 301                 imageType = VERSION_2_8_BIT;
 302             } else if (bitsPerPixel == 24) {
 303                 imageType = VERSION_2_24_BIT;
 304             } else {
 305                 throw new IIOException(I18N.getString("BMPImageReader8"));
 306             }
 307 
 308             // Read in the palette
 309             int numberOfEntries = (int)((bitmapOffset - 14 - size) / 3);
 310             int sizeOfPalette = numberOfEntries*3;
 311             palette = new byte[sizeOfPalette];
 312             iis.readFully(palette, 0, sizeOfPalette);
 313             metadata.palette = palette;
 314             metadata.paletteSize = numberOfEntries;
 315         } else {
 316             compression = iis.readUnsignedInt();
 317             imageSize = iis.readUnsignedInt();
 318             long xPelsPerMeter = iis.readInt();
 319             long yPelsPerMeter = iis.readInt();
 320             long colorsUsed = iis.readUnsignedInt();
 321             long colorsImportant = iis.readUnsignedInt();
 322 
 323             metadata.compression = (int)compression;
 324             metadata.xPixelsPerMeter = (int)xPelsPerMeter;
 325             metadata.yPixelsPerMeter = (int)yPelsPerMeter;
 326             metadata.colorsUsed = (int)colorsUsed;
 327             metadata.colorsImportant = (int)colorsImportant;
 328 
 329             if (size == 40) {
 330                 // Windows 3.x and Windows NT
 331                 switch((int)compression) {
 332 
 333                 case BI_JPEG:
 334                 case BI_PNG:
 335                     metadata.bmpVersion = VERSION_3;
 336                     imageType = VERSION_3_XP_EMBEDDED;
 337                     break;
 338 
 339                 case BI_RGB:  // No compression
 340                 case BI_RLE8:  // 8-bit RLE compression
 341                 case BI_RLE4:  // 4-bit RLE compression
 342 
 343                     // Read in the palette
 344                     if (bitmapOffset < (size + 14)) {
 345                         throw new IIOException(I18N.getString("BMPImageReader7"));
 346                     }
 347                     int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
 348                     int sizeOfPalette = numberOfEntries * 4;
 349                     palette = new byte[sizeOfPalette];
 350                     iis.readFully(palette, 0, sizeOfPalette);
 351 
 352                     metadata.palette = palette;
 353                     metadata.paletteSize = numberOfEntries;
 354 
 355                     if (bitsPerPixel == 1) {
 356                         imageType = VERSION_3_1_BIT;
 357                     } else if (bitsPerPixel == 4) {
 358                         imageType = VERSION_3_4_BIT;
 359                     } else if (bitsPerPixel == 8) {
 360                         imageType = VERSION_3_8_BIT;
 361                     } else if (bitsPerPixel == 24) {
 362                         imageType = VERSION_3_24_BIT;
 363                     } else if (bitsPerPixel == 16) {
 364                         imageType = VERSION_3_NT_16_BIT;
 365 
 366                         redMask = 0x7C00;
 367                         greenMask = 0x3E0;
 368                         blueMask =  (1 << 5) - 1;// 0x1F;
 369                         metadata.redMask = redMask;
 370                         metadata.greenMask = greenMask;
 371                         metadata.blueMask = blueMask;
 372                     } else if (bitsPerPixel == 32) {
 373                         imageType = VERSION_3_NT_32_BIT;
 374                         redMask   = 0x00FF0000;
 375                         greenMask = 0x0000FF00;
 376                         blueMask  = 0x000000FF;
 377                         metadata.redMask = redMask;
 378                         metadata.greenMask = greenMask;
 379                         metadata.blueMask = blueMask;
 380                     } else {
 381                         throw new
 382                             IIOException(I18N.getString("BMPImageReader8"));
 383                     }
 384 
 385                     metadata.bmpVersion = VERSION_3;
 386                     break;
 387 
 388                 case BI_BITFIELDS:
 389 
 390                     if (bitsPerPixel == 16) {
 391                         imageType = VERSION_3_NT_16_BIT;
 392                     } else if (bitsPerPixel == 32) {
 393                         imageType = VERSION_3_NT_32_BIT;
 394                     } else {
 395                         throw new
 396                             IIOException(I18N.getString("BMPImageReader8"));
 397                     }
 398 
 399                     // BitsField encoding
 400                     redMask = (int)iis.readUnsignedInt();
 401                     greenMask = (int)iis.readUnsignedInt();
 402                     blueMask = (int)iis.readUnsignedInt();
 403                     metadata.redMask = redMask;
 404                     metadata.greenMask = greenMask;
 405                     metadata.blueMask = blueMask;
 406 
 407                     if (colorsUsed != 0) {
 408                         // there is a palette
 409                         sizeOfPalette = (int)colorsUsed*4;
 410                         palette = new byte[sizeOfPalette];
 411                         iis.readFully(palette, 0, sizeOfPalette);
 412 
 413                         metadata.palette = palette;
 414                         metadata.paletteSize = (int)colorsUsed;
 415                     }
 416                     metadata.bmpVersion = VERSION_3_NT;
 417 
 418                     break;
 419                 default:
 420                     throw new
 421                         IIOException(I18N.getString("BMPImageReader2"));
 422                 }
 423             } else if (size == 52 || size == 56) {
 424                 // BITMAPV2INFOHEADER or BITMAPV3INFOHEADER
 425                 redMask = (int)iis.readUnsignedInt();
 426                 greenMask = (int)iis.readUnsignedInt();
 427                 blueMask = (int)iis.readUnsignedInt();
 428                 if (size == 56) {
 429                     alphaMask = (int)iis.readUnsignedInt();
 430                 }
 431 
 432                 metadata.bmpVersion = VERSION_3_EXT;
 433                 // Read in the palette
 434                 int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
 435                 int sizeOfPalette = numberOfEntries*4;
 436                 palette = new byte[sizeOfPalette];
 437                 iis.readFully(palette, 0, sizeOfPalette);
 438                 metadata.palette = palette;
 439                 metadata.paletteSize = numberOfEntries;
 440 
 441                 switch((int)compression) {
 442 
 443                     case BI_JPEG:
 444                     case BI_PNG:
 445                         imageType = VERSION_3_EXT_EMBEDDED;
 446                         break;
 447                     default:
 448                         if (bitsPerPixel == 1) {
 449                             imageType = VERSION_3_EXT_1_BIT;
 450                         } else if (bitsPerPixel == 4) {
 451                             imageType = VERSION_3_EXT_4_BIT;
 452                         } else if (bitsPerPixel == 8) {
 453                             imageType = VERSION_3_EXT_8_BIT;
 454                         } else if (bitsPerPixel == 16) {
 455                             imageType = VERSION_3_EXT_16_BIT;
 456                             if ((int)compression == BI_RGB) {
 457                                 redMask = 0x7C00;
 458                                 greenMask = 0x3E0;
 459                                 blueMask = 0x1F;
 460                             }
 461                         } else if (bitsPerPixel == 24) {
 462                             imageType = VERSION_3_EXT_24_BIT;
 463                         } else if (bitsPerPixel == 32) {
 464                             imageType = VERSION_3_EXT_32_BIT;
 465                             if ((int)compression == BI_RGB) {
 466                                 redMask   = 0x00FF0000;
 467                                 greenMask = 0x0000FF00;
 468                                 blueMask  = 0x000000FF;
 469                             }
 470                         } else {
 471                             throw new
 472                             IIOException(I18N.getString("BMPImageReader8"));
 473                         }
 474 
 475                         metadata.redMask = redMask;
 476                         metadata.greenMask = greenMask;
 477                         metadata.blueMask = blueMask;
 478                         metadata.alphaMask = alphaMask;
 479                 }
 480             } else if (size == 108 || size == 124) {
 481                 // Windows 4.x BMP
 482                 if (size == 108)
 483                     metadata.bmpVersion = VERSION_4;
 484                 else if (size == 124)
 485                     metadata.bmpVersion = VERSION_5;
 486 
 487                 // rgb masks, valid only if comp is BI_BITFIELDS
 488                 redMask = (int)iis.readUnsignedInt();
 489                 greenMask = (int)iis.readUnsignedInt();
 490                 blueMask = (int)iis.readUnsignedInt();
 491                 // Only supported for 32bpp BI_RGB argb
 492                 alphaMask = (int)iis.readUnsignedInt();
 493                 long csType = iis.readUnsignedInt();
 494                 int redX = iis.readInt();
 495                 int redY = iis.readInt();
 496                 int redZ = iis.readInt();
 497                 int greenX = iis.readInt();
 498                 int greenY = iis.readInt();
 499                 int greenZ = iis.readInt();
 500                 int blueX = iis.readInt();
 501                 int blueY = iis.readInt();
 502                 int blueZ = iis.readInt();
 503                 long gammaRed = iis.readUnsignedInt();
 504                 long gammaGreen = iis.readUnsignedInt();
 505                 long gammaBlue = iis.readUnsignedInt();
 506 
 507                 if (size == 124) {
 508                     metadata.intent = iis.readInt();
 509                     profileData = iis.readInt();
 510                     profileSize = iis.readInt();
 511                     iis.skipBytes(4);
 512                 }
 513 
 514                 metadata.colorSpace = (int)csType;
 515 
 516                 if (csType == LCS_CALIBRATED_RGB) {
 517                     // All the new fields are valid only for this case
 518                     metadata.redX = redX;
 519                     metadata.redY = redY;
 520                     metadata.redZ = redZ;
 521                     metadata.greenX = greenX;
 522                     metadata.greenY = greenY;
 523                     metadata.greenZ = greenZ;
 524                     metadata.blueX = blueX;
 525                     metadata.blueY = blueY;
 526                     metadata.blueZ = blueZ;
 527                     metadata.gammaRed = (int)gammaRed;
 528                     metadata.gammaGreen = (int)gammaGreen;
 529                     metadata.gammaBlue = (int)gammaBlue;
 530                 }
 531 
 532                 // Read in the palette
 533                 int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
 534                 int sizeOfPalette = numberOfEntries*4;
 535                 palette = new byte[sizeOfPalette];
 536                 iis.readFully(palette, 0, sizeOfPalette);
 537                 metadata.palette = palette;
 538                 metadata.paletteSize = numberOfEntries;
 539 
 540                 switch ((int)compression) {
 541                 case BI_JPEG:
 542                 case BI_PNG:
 543                     if (size == 108) {
 544                         imageType = VERSION_4_XP_EMBEDDED;
 545                     } else if (size == 124) {
 546                         imageType = VERSION_5_XP_EMBEDDED;
 547                     }
 548                     break;
 549                 default:
 550                     if (bitsPerPixel == 1) {
 551                         imageType = VERSION_4_1_BIT;
 552                     } else if (bitsPerPixel == 4) {
 553                         imageType = VERSION_4_4_BIT;
 554                     } else if (bitsPerPixel == 8) {
 555                         imageType = VERSION_4_8_BIT;
 556                     } else if (bitsPerPixel == 16) {
 557                         imageType = VERSION_4_16_BIT;
 558                         if ((int)compression == BI_RGB) {
 559                             redMask = 0x7C00;
 560                             greenMask = 0x3E0;
 561                             blueMask = 0x1F;
 562                         }
 563                     } else if (bitsPerPixel == 24) {
 564                         imageType = VERSION_4_24_BIT;
 565                     } else if (bitsPerPixel == 32) {
 566                         imageType = VERSION_4_32_BIT;
 567                         if ((int)compression == BI_RGB) {
 568                             redMask   = 0x00FF0000;
 569                             greenMask = 0x0000FF00;
 570                             blueMask  = 0x000000FF;
 571                         }
 572                     } else {
 573                         throw new
 574                             IIOException(I18N.getString("BMPImageReader8"));
 575                     }
 576 
 577                     metadata.redMask = redMask;
 578                     metadata.greenMask = greenMask;
 579                     metadata.blueMask = blueMask;
 580                     metadata.alphaMask = alphaMask;
 581                 }
 582             } else {
 583                 throw new
 584                     IIOException(I18N.getString("BMPImageReader3"));
 585             }
 586         }
 587 
 588         if (height > 0) {
 589             // bottom up image
 590             isBottomUp = true;
 591         } else {
 592             // top down image
 593             isBottomUp = false;
 594             height = Math.abs(height);
 595         }
 596 
 597         // Reset Image Layout so there's only one tile.
 598         //Define the color space
 599         ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
 600         if (metadata.colorSpace == PROFILE_LINKED ||
 601             metadata.colorSpace == PROFILE_EMBEDDED) {
 602 
 603             iis.mark();
 604             iis.skipBytes(profileData - size);
 605             byte[] profile = new byte[profileSize];
 606             iis.readFully(profile, 0, profileSize);
 607             iis.reset();
 608 
 609             try {
 610                 if (metadata.colorSpace == PROFILE_LINKED &&
 611                     isLinkedProfileAllowed() &&
 612                     !isUncOrDevicePath(profile))
 613                 {
 614                     String path = new String(profile, "windows-1252");
 615 
 616                     colorSpace =
 617                         new ICC_ColorSpace(ICC_Profile.getInstance(path));
 618                 } else {
 619                     colorSpace =
 620                         new ICC_ColorSpace(ICC_Profile.getInstance(profile));
 621                 }
 622             } catch (Exception e) {
 623                 colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
 624             }
 625         }
 626 
 627         if (bitsPerPixel == 0 ||
 628             compression == BI_JPEG || compression == BI_PNG )
 629         {
 630             // the colorModel and sampleModel will be initialzed
 631             // by the  reader of embedded image
 632             colorModel = null;
 633             sampleModel = null;
 634         } else if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
 635             // When number of bitsPerPixel is <= 8, we use IndexColorModel.
 636             numBands = 1;
 637 
 638             if (bitsPerPixel == 8) {
 639                 int[] bandOffsets = new int[numBands];
 640                 for (int i = 0; i < numBands; i++) {
 641                     bandOffsets[i] = numBands -1 -i;
 642                 }
 643                 sampleModel =
 644                     new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
 645                                                     width, height,
 646                                                     numBands,
 647                                                     numBands * width,
 648                                                     bandOffsets);
 649             } else {
 650                 // 1 and 4 bit pixels can be stored in a packed format.
 651                 sampleModel =
 652                     new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
 653                                                     width, height,
 654                                                     bitsPerPixel);
 655             }
 656 
 657             // Create IndexColorModel from the palette.
 658             byte[] r, g, b;
 659             if (imageType == VERSION_2_1_BIT ||
 660                 imageType == VERSION_2_4_BIT ||
 661                 imageType == VERSION_2_8_BIT) {
 662 
 663 
 664                 size = palette.length/3;
 665 
 666                 if (size > 256) {
 667                     size = 256;
 668                 }
 669 
 670                 int off;
 671                 r = new byte[(int)size];
 672                 g = new byte[(int)size];
 673                 b = new byte[(int)size];
 674                 for (int i=0; i<(int)size; i++) {
 675                     off = 3 * i;
 676                     b[i] = palette[off];
 677                     g[i] = palette[off+1];
 678                     r[i] = palette[off+2];
 679                 }
 680             } else {
 681                 size = palette.length/4;
 682 
 683                 if (size > 256) {
 684                     size = 256;
 685                 }
 686 
 687                 int off;
 688                 r = new byte[(int)size];
 689                 g = new byte[(int)size];
 690                 b = new byte[(int)size];
 691                 for (int i=0; i<size; i++) {
 692                     off = 4 * i;
 693                     b[i] = palette[off];
 694                     g[i] = palette[off+1];
 695                     r[i] = palette[off+2];
 696                 }
 697             }
 698 
 699             if (ImageUtil.isIndicesForGrayscale(r, g, b))
 700                 colorModel =
 701                     ImageUtil.createColorModel(null, sampleModel);
 702             else
 703                 colorModel = new IndexColorModel(bitsPerPixel, (int)size, r, g, b);
 704         } else if (bitsPerPixel == 16) {
 705             numBands = 3;
 706             sampleModel =
 707                 new SinglePixelPackedSampleModel(DataBuffer.TYPE_USHORT,
 708                                                  width, height,
 709                                                  new int[] {redMask, greenMask, blueMask});
 710 
 711             colorModel =
 712                 new DirectColorModel(colorSpace,
 713                                      16, redMask, greenMask, blueMask, 0,
 714                                      false, DataBuffer.TYPE_USHORT);
 715 
 716         } else if (bitsPerPixel == 32) {
 717             numBands = alphaMask == 0 ? 3 : 4;
 718 
 719             // The number of bands in the SampleModel is determined by
 720             // the length of the mask array passed in.
 721             int[] bitMasks = numBands == 3 ?
 722                 new int[] {redMask, greenMask, blueMask} :
 723                 new int[] {redMask, greenMask, blueMask, alphaMask};
 724 
 725                 sampleModel =
 726                     new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT,
 727                                                      width, height,
 728                                                      bitMasks);
 729 
 730                 colorModel =
 731                     new DirectColorModel(colorSpace,
 732                                          32, redMask, greenMask, blueMask, alphaMask,
 733                                          false, DataBuffer.TYPE_INT);
 734         } else {
 735             numBands = 3;
 736             // Create SampleModel
 737             int[] bandOffsets = new int[numBands];
 738             for (int i = 0; i < numBands; i++) {
 739                 bandOffsets[i] = numBands -1 -i;
 740             }
 741 
 742             sampleModel =
 743                 new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
 744                                                 width, height,
 745                                                 numBands,
 746                                                 numBands * width,
 747                                                 bandOffsets);
 748 
 749             colorModel =
 750                 ImageUtil.createColorModel(colorSpace, sampleModel);
 751         }
 752 
 753         originalSampleModel = sampleModel;
 754         originalColorModel = colorModel;
 755 
 756         // Reset to the start of bitmap; then jump to the
 757         //start of image data
 758         iis.reset();
 759         iis.skipBytes(bitmapOffset);
 760         bitmapStart = iis.getStreamPosition();
 761 
 762         gotHeader = true;
 763     }
 764 
 765     public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
 766       throws IOException {
 767         checkIndex(imageIndex);
 768         try {
 769             readHeader();
 770         } catch (IllegalArgumentException e) {
 771             throw new IIOException(I18N.getString("BMPImageReader6"), e);
 772         }
 773         ArrayList<ImageTypeSpecifier> list = new ArrayList<>(1);
 774         list.add(new ImageTypeSpecifier(originalColorModel,
 775                                         originalSampleModel));
 776         return list.iterator();
 777     }
 778 
 779     public ImageReadParam getDefaultReadParam() {
 780         return new ImageReadParam();
 781     }
 782 
 783     public IIOMetadata getImageMetadata(int imageIndex)
 784       throws IOException {
 785         checkIndex(imageIndex);
 786         if (metadata == null) {
 787             try {
 788                 readHeader();
 789             } catch (IllegalArgumentException e) {
 790                 throw new IIOException(I18N.getString("BMPImageReader6"), e);
 791             }
 792         }
 793         return metadata;
 794     }
 795 
 796     public IIOMetadata getStreamMetadata() throws IOException {
 797         return null;
 798     }
 799 
 800     public boolean isRandomAccessEasy(int imageIndex) throws IOException {
 801         checkIndex(imageIndex);
 802         try {
 803             readHeader();
 804         } catch (IllegalArgumentException e) {
 805             throw new IIOException(I18N.getString("BMPImageReader6"), e);
 806         }
 807         return metadata.compression == BI_RGB;
 808     }
 809 
 810     public BufferedImage read(int imageIndex, ImageReadParam param)
 811         throws IOException {
 812 
 813         if (iis == null) {
 814             throw new IllegalStateException(I18N.getString("BMPImageReader5"));
 815         }
 816 
 817         checkIndex(imageIndex);
 818         clearAbortRequest();
 819         processImageStarted(imageIndex);
 820         if (abortRequested()) {
 821             processReadAborted();
 822             return bi;
 823         }
 824 
 825         if (param == null)
 826             param = getDefaultReadParam();
 827 
 828         //read header
 829         try {
 830             readHeader();
 831         } catch (IllegalArgumentException e) {
 832             throw new IIOException(I18N.getString("BMPImageReader6"), e);
 833         }
 834 
 835         sourceRegion = new Rectangle(0, 0, 0, 0);
 836         destinationRegion = new Rectangle(0, 0, 0, 0);
 837 
 838         computeRegions(param, this.width, this.height,
 839                        param.getDestination(),
 840                        sourceRegion,
 841                        destinationRegion);
 842 
 843         scaleX = param.getSourceXSubsampling();
 844         scaleY = param.getSourceYSubsampling();
 845 
 846         // If the destination band is set used it
 847         sourceBands = param.getSourceBands();
 848         destBands = param.getDestinationBands();
 849 
 850         seleBand = (sourceBands != null) && (destBands != null);
 851         noTransform =
 852             destinationRegion.equals(new Rectangle(0, 0, width, height)) ||
 853             seleBand;
 854 
 855         if (!seleBand) {
 856             sourceBands = new int[numBands];
 857             destBands = new int[numBands];
 858             for (int i = 0; i < numBands; i++)
 859                 destBands[i] = sourceBands[i] = i;
 860         }
 861 
 862         // If the destination is provided, then use it.  Otherwise, create new one
 863         bi = param.getDestination();
 864 
 865         // Get the image data.
 866         WritableRaster raster = null;
 867 
 868         if (bi == null) {
 869             if (sampleModel != null && colorModel != null) {
 870                 sampleModel =
 871                     sampleModel.createCompatibleSampleModel(destinationRegion.x +
 872                                                             destinationRegion.width,
 873                                                             destinationRegion.y +
 874                                                             destinationRegion.height);
 875                 if (seleBand)
 876                     sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
 877                 raster = Raster.createWritableRaster(sampleModel, new Point());
 878                 bi = new BufferedImage(colorModel, raster, false, null);
 879             }
 880         } else {
 881             raster = bi.getWritableTile(0, 0);
 882             sampleModel = bi.getSampleModel();
 883             colorModel = bi.getColorModel();
 884 
 885             noTransform &=  destinationRegion.equals(raster.getBounds());
 886         }
 887 
 888         byte[] bdata = null; // buffer for byte data
 889         short[] sdata = null; // buffer for short data
 890         int[] idata = null; // buffer for int data
 891 
 892         // the sampleModel can be null in case of embedded image
 893         if (sampleModel != null) {
 894             if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
 895                 bdata = ((DataBufferByte)raster.getDataBuffer()).getData();
 896             else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
 897                 sdata = ((DataBufferUShort)raster.getDataBuffer()).getData();
 898             else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
 899                 idata = ((DataBufferInt)raster.getDataBuffer()).getData();
 900         }
 901 
 902         iis.seek(bitmapStart);
 903 
 904         // There should only be one tile.
 905         switch(imageType) {
 906 
 907         case VERSION_2_1_BIT:
 908             // no compression
 909             read1Bit(bdata);
 910             break;
 911 
 912         case VERSION_2_4_BIT:
 913             // no compression
 914             read4Bit(bdata);
 915             break;
 916 
 917         case VERSION_2_8_BIT:
 918             // no compression
 919             read8Bit(bdata);
 920             break;
 921 
 922         case VERSION_2_24_BIT:
 923             // no compression
 924             read24Bit(bdata);
 925             break;
 926 
 927         case VERSION_3_1_BIT:
 928             // 1-bit images cannot be compressed.
 929             read1Bit(bdata);
 930             break;
 931 
 932         case VERSION_3_4_BIT:
 933             switch((int)compression) {
 934             case BI_RGB:
 935                 read4Bit(bdata);
 936                 break;
 937 
 938             case BI_RLE4:
 939                 readRLE4(bdata);
 940                 break;
 941 
 942             default:
 943                 throw new
 944                     IIOException(I18N.getString("BMPImageReader1"));
 945             }
 946             break;
 947 
 948         case VERSION_3_8_BIT:
 949             switch((int)compression) {
 950             case BI_RGB:
 951                 read8Bit(bdata);
 952                 break;
 953 
 954             case BI_RLE8:
 955                 readRLE8(bdata);
 956                 break;
 957 
 958             default:
 959                 throw new
 960                     IIOException(I18N.getString("BMPImageReader1"));
 961             }
 962 
 963             break;
 964 
 965         case VERSION_3_24_BIT:
 966             // 24-bit images are not compressed
 967             read24Bit(bdata);
 968             break;
 969 
 970         case VERSION_3_NT_16_BIT:
 971             read16Bit(sdata);
 972             break;
 973 
 974         case VERSION_3_NT_32_BIT:
 975             read32Bit(idata);
 976             break;
 977 
 978         case VERSION_3_XP_EMBEDDED:
 979         case VERSION_3_EXT_EMBEDDED:
 980         case VERSION_4_XP_EMBEDDED:
 981         case VERSION_5_XP_EMBEDDED:
 982             bi = readEmbedded((int)compression, bi, param);
 983             break;
 984 
 985         case VERSION_3_EXT_1_BIT:
 986         case VERSION_4_1_BIT:
 987             read1Bit(bdata);
 988             break;
 989 
 990         case VERSION_3_EXT_4_BIT:
 991         case VERSION_4_4_BIT:
 992             switch((int)compression) {
 993 
 994             case BI_RGB:
 995                 read4Bit(bdata);
 996                 break;
 997 
 998             case BI_RLE4:
 999                 readRLE4(bdata);
1000                 break;
1001 
1002             default:
1003                 throw new
1004                     IIOException(I18N.getString("BMPImageReader1"));
1005             }
1006             break;
1007 
1008         case VERSION_3_EXT_8_BIT:
1009         case VERSION_4_8_BIT:
1010             switch((int)compression) {
1011 
1012             case BI_RGB:
1013                 read8Bit(bdata);
1014                 break;
1015 
1016             case BI_RLE8:
1017                 readRLE8(bdata);
1018                 break;
1019 
1020             default:
1021                 throw new
1022                     IIOException(I18N.getString("BMPImageReader1"));
1023             }
1024             break;
1025 
1026         case VERSION_3_EXT_16_BIT:
1027         case VERSION_4_16_BIT:
1028             read16Bit(sdata);
1029             break;
1030 
1031         case VERSION_3_EXT_24_BIT:
1032         case VERSION_4_24_BIT:
1033             read24Bit(bdata);
1034             break;
1035 
1036         case VERSION_3_EXT_32_BIT:
1037         case VERSION_4_32_BIT:
1038             read32Bit(idata);
1039             break;
1040         }
1041 
1042         if (abortRequested())
1043             processReadAborted();
1044         else
1045             processImageComplete();
1046 
1047         return bi;
1048     }
1049 
1050     public boolean canReadRaster() {
1051         return true;
1052     }
1053 
1054     public Raster readRaster(int imageIndex,
1055                              ImageReadParam param) throws IOException {
1056         BufferedImage bi = read(imageIndex, param);
1057         return bi.getData();
1058     }
1059 
1060     private void resetHeaderInfo() {
1061         gotHeader = false;
1062         bi = null;
1063         sampleModel = originalSampleModel = null;
1064         colorModel = originalColorModel = null;
1065     }
1066 
1067     public void reset() {
1068         super.reset();
1069         iis = null;
1070         resetHeaderInfo();
1071     }
1072 
1073     // Deal with 1 Bit images using IndexColorModels
1074     private void read1Bit(byte[] bdata) throws IOException {
1075         int bytesPerScanline = (width + 7) / 8;
1076         int padding = bytesPerScanline % 4;
1077         if (padding != 0) {
1078             padding = 4 - padding;
1079         }
1080 
1081         int lineLength = bytesPerScanline + padding;
1082 
1083         if (noTransform) {
1084             int j = isBottomUp ? (height -1)*bytesPerScanline : 0;
1085 
1086             for (int i=0; i<height; i++) {
1087                 iis.readFully(bdata, j, bytesPerScanline);
1088                 iis.skipBytes(padding);
1089                 j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
1090                 processImageUpdate(bi, 0, i,
1091                                    destinationRegion.width, 1, 1, 1,
1092                                    new int[]{0});
1093                 processImageProgress(100.0F * i/destinationRegion.height);
1094                 if (abortRequested()) {
1095                     break;
1096                 }
1097             }
1098         } else {
1099             byte[] buf = new byte[lineLength];
1100             int lineStride =
1101                 ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
1102 
1103             if (isBottomUp) {
1104                 int lastLine =
1105                     sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1106                 iis.skipBytes(lineLength * (height - 1 - lastLine));
1107             } else
1108                 iis.skipBytes(lineLength * sourceRegion.y);
1109 
1110             int skipLength = lineLength * (scaleY - 1);
1111 
1112             // cache the values to avoid duplicated computation
1113             int[] srcOff = new int[destinationRegion.width];
1114             int[] destOff = new int[destinationRegion.width];
1115             int[] srcPos = new int[destinationRegion.width];
1116             int[] destPos = new int[destinationRegion.width];
1117 
1118             for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
1119                  i < destinationRegion.x + destinationRegion.width;
1120                  i++, j++, x += scaleX) {
1121                 srcPos[j] = x >> 3;
1122                 srcOff[j] = 7 - (x & 7);
1123                 destPos[j] = i >> 3;
1124                 destOff[j] = 7 - (i & 7);
1125             }
1126 
1127             int k = destinationRegion.y * lineStride;
1128             if (isBottomUp)
1129                 k += (destinationRegion.height - 1) * lineStride;
1130 
1131             for (int j = 0, y = sourceRegion.y;
1132                  j < destinationRegion.height; j++, y+=scaleY) {
1133                 iis.read(buf, 0, lineLength);
1134                 for (int i = 0; i < destinationRegion.width; i++) {
1135                     //get the bit and assign to the data buffer of the raster
1136                     int v = (buf[srcPos[i]] >> srcOff[i]) & 1;
1137                     bdata[k + destPos[i]] |= v << destOff[i];
1138                 }
1139 
1140                 k += isBottomUp ? -lineStride : lineStride;
1141                 iis.skipBytes(skipLength);
1142                 processImageUpdate(bi, 0, j,
1143                                    destinationRegion.width, 1, 1, 1,
1144                                    new int[]{0});
1145                 processImageProgress(100.0F*j/destinationRegion.height);
1146                 if (abortRequested()) {
1147                     break;
1148                 }
1149             }
1150         }
1151     }
1152 
1153     // Method to read a 4 bit BMP image data
1154     private void read4Bit(byte[] bdata) throws IOException {
1155 
1156         int bytesPerScanline = (width + 1) / 2;
1157 
1158         // Padding bytes at the end of each scanline
1159         int padding = bytesPerScanline % 4;
1160         if (padding != 0)
1161             padding = 4 - padding;
1162 
1163         int lineLength = bytesPerScanline + padding;
1164 
1165         if (noTransform) {
1166             int j = isBottomUp ? (height -1) * bytesPerScanline : 0;
1167 
1168             for (int i=0; i<height; i++) {
1169                 iis.readFully(bdata, j, bytesPerScanline);
1170                 iis.skipBytes(padding);
1171                 j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
1172                 processImageUpdate(bi, 0, i,
1173                                    destinationRegion.width, 1, 1, 1,
1174                                    new int[]{0});
1175                 processImageProgress(100.0F * i/destinationRegion.height);
1176                 if (abortRequested()) {
1177                     break;
1178                 }
1179             }
1180         } else {
1181             byte[] buf = new byte[lineLength];
1182             int lineStride =
1183                 ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
1184 
1185             if (isBottomUp) {
1186                 int lastLine =
1187                     sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1188                 iis.skipBytes(lineLength * (height - 1 - lastLine));
1189             } else
1190                 iis.skipBytes(lineLength * sourceRegion.y);
1191 
1192             int skipLength = lineLength * (scaleY - 1);
1193 
1194             // cache the values to avoid duplicated computation
1195             int[] srcOff = new int[destinationRegion.width];
1196             int[] destOff = new int[destinationRegion.width];
1197             int[] srcPos = new int[destinationRegion.width];
1198             int[] destPos = new int[destinationRegion.width];
1199 
1200             for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
1201                  i < destinationRegion.x + destinationRegion.width;
1202                  i++, j++, x += scaleX) {
1203                 srcPos[j] = x >> 1;
1204                 srcOff[j] = (1 - (x & 1)) << 2;
1205                 destPos[j] = i >> 1;
1206                 destOff[j] = (1 - (i & 1)) << 2;
1207             }
1208 
1209             int k = destinationRegion.y * lineStride;
1210             if (isBottomUp)
1211                 k += (destinationRegion.height - 1) * lineStride;
1212 
1213             for (int j = 0, y = sourceRegion.y;
1214                  j < destinationRegion.height; j++, y+=scaleY) {
1215                 iis.read(buf, 0, lineLength);
1216                 for (int i = 0; i < destinationRegion.width; i++) {
1217                     //get the bit and assign to the data buffer of the raster
1218                     int v = (buf[srcPos[i]] >> srcOff[i]) & 0x0F;
1219                     bdata[k + destPos[i]] |= v << destOff[i];
1220                 }
1221 
1222                 k += isBottomUp ? -lineStride : lineStride;
1223                 iis.skipBytes(skipLength);
1224                 processImageUpdate(bi, 0, j,
1225                                    destinationRegion.width, 1, 1, 1,
1226                                    new int[]{0});
1227                 processImageProgress(100.0F*j/destinationRegion.height);
1228                 if (abortRequested()) {
1229                     break;
1230                 }
1231             }
1232         }
1233     }
1234 
1235     // Method to read 8 bit BMP image data
1236     private void read8Bit(byte[] bdata) throws IOException {
1237 
1238         // Padding bytes at the end of each scanline
1239         int padding = width % 4;
1240         if (padding != 0) {
1241             padding = 4 - padding;
1242         }
1243 
1244         int lineLength = width + padding;
1245 
1246         if (noTransform) {
1247             int j = isBottomUp ? (height -1) * width : 0;
1248 
1249             for (int i=0; i<height; i++) {
1250                 iis.readFully(bdata, j, width);
1251                 iis.skipBytes(padding);
1252                 j += isBottomUp ? -width : width;
1253                 processImageUpdate(bi, 0, i,
1254                                    destinationRegion.width, 1, 1, 1,
1255                                    new int[]{0});
1256                 processImageProgress(100.0F * i/destinationRegion.height);
1257                 if (abortRequested()) {
1258                     break;
1259                 }
1260             }
1261         } else {
1262             byte[] buf = new byte[lineLength];
1263             int lineStride =
1264                 ((ComponentSampleModel)sampleModel).getScanlineStride();
1265 
1266             if (isBottomUp) {
1267                 int lastLine =
1268                     sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1269                 iis.skipBytes(lineLength * (height - 1 - lastLine));
1270             } else
1271                 iis.skipBytes(lineLength * sourceRegion.y);
1272 
1273             int skipLength = lineLength * (scaleY - 1);
1274 
1275             int k = destinationRegion.y * lineStride;
1276             if (isBottomUp)
1277                 k += (destinationRegion.height - 1) * lineStride;
1278             k += destinationRegion.x;
1279 
1280             for (int j = 0, y = sourceRegion.y;
1281                  j < destinationRegion.height; j++, y+=scaleY) {
1282                 iis.read(buf, 0, lineLength);
1283                 for (int i = 0, m = sourceRegion.x;
1284                      i < destinationRegion.width; i++, m += scaleX) {
1285                     //get the bit and assign to the data buffer of the raster
1286                     bdata[k + i] = buf[m];
1287                 }
1288 
1289                 k += isBottomUp ? -lineStride : lineStride;
1290                 iis.skipBytes(skipLength);
1291                 processImageUpdate(bi, 0, j,
1292                                    destinationRegion.width, 1, 1, 1,
1293                                    new int[]{0});
1294                 processImageProgress(100.0F*j/destinationRegion.height);
1295                 if (abortRequested()) {
1296                     break;
1297                 }
1298             }
1299         }
1300     }
1301 
1302     // Method to read 24 bit BMP image data
1303     private void read24Bit(byte[] bdata) throws IOException {
1304         // Padding bytes at the end of each scanline
1305         // width * bitsPerPixel should be divisible by 32
1306         int padding = width * 3 % 4;
1307         if ( padding != 0)
1308             padding = 4 - padding;
1309 
1310         int lineStride = width * 3;
1311         int lineLength = lineStride + padding;
1312 
1313         if (noTransform) {
1314             int j = isBottomUp ? (height -1) * width * 3 : 0;
1315 
1316             for (int i=0; i<height; i++) {
1317                 iis.readFully(bdata, j, lineStride);
1318                 iis.skipBytes(padding);
1319                 j += isBottomUp ? -lineStride : lineStride;
1320                 processImageUpdate(bi, 0, i,
1321                                    destinationRegion.width, 1, 1, 1,
1322                                    new int[]{0});
1323                 processImageProgress(100.0F * i/destinationRegion.height);
1324                 if (abortRequested()) {
1325                     break;
1326                 }
1327             }
1328         } else {
1329             byte[] buf = new byte[lineLength];
1330             lineStride =
1331                 ((ComponentSampleModel)sampleModel).getScanlineStride();
1332 
1333             if (isBottomUp) {
1334                 int lastLine =
1335                     sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1336                 iis.skipBytes(lineLength * (height - 1 - lastLine));
1337             } else
1338                 iis.skipBytes(lineLength * sourceRegion.y);
1339 
1340             int skipLength = lineLength * (scaleY - 1);
1341 
1342             int k = destinationRegion.y * lineStride;
1343             if (isBottomUp)
1344                 k += (destinationRegion.height - 1) * lineStride;
1345             k += destinationRegion.x * 3;
1346 
1347             for (int j = 0, y = sourceRegion.y;
1348                  j < destinationRegion.height; j++, y+=scaleY) {
1349                 iis.read(buf, 0, lineLength);
1350                 for (int i = 0, m = 3 * sourceRegion.x;
1351                      i < destinationRegion.width; i++, m += 3 * scaleX) {
1352                     //get the bit and assign to the data buffer of the raster
1353                     int n = 3 * i + k;
1354                     for (int b = 0; b < destBands.length; b++)
1355                         bdata[n + destBands[b]] = buf[m + sourceBands[b]];
1356                 }
1357 
1358                 k += isBottomUp ? -lineStride : lineStride;
1359                 iis.skipBytes(skipLength);
1360                 processImageUpdate(bi, 0, j,
1361                                    destinationRegion.width, 1, 1, 1,
1362                                    new int[]{0});
1363                 processImageProgress(100.0F*j/destinationRegion.height);
1364                 if (abortRequested()) {
1365                     break;
1366                 }
1367             }
1368         }
1369     }
1370 
1371     private void read16Bit(short[] sdata) throws IOException {
1372         // Padding bytes at the end of each scanline
1373         // width * bitsPerPixel should be divisible by 32
1374         int padding = width * 2 % 4;
1375 
1376         if ( padding != 0)
1377             padding = 4 - padding;
1378 
1379         int lineLength = width + padding / 2;
1380 
1381         if (noTransform) {
1382             int j = isBottomUp ? (height -1) * width : 0;
1383             for (int i=0; i<height; i++) {
1384                 iis.readFully(sdata, j, width);
1385                 iis.skipBytes(padding);
1386 
1387                 j += isBottomUp ? -width : width;
1388                 processImageUpdate(bi, 0, i,
1389                                    destinationRegion.width, 1, 1, 1,
1390                                    new int[]{0});
1391                 processImageProgress(100.0F * i/destinationRegion.height);
1392                 if (abortRequested()) {
1393                     break;
1394                 }
1395             }
1396         } else {
1397             short[] buf = new short[lineLength];
1398             int lineStride =
1399                 ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
1400 
1401             if (isBottomUp) {
1402                 int lastLine =
1403                     sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1404                 iis.skipBytes(lineLength * (height - 1 - lastLine) << 1);
1405             } else
1406                 iis.skipBytes(lineLength * sourceRegion.y << 1);
1407 
1408             int skipLength = lineLength * (scaleY - 1) << 1;
1409 
1410             int k = destinationRegion.y * lineStride;
1411             if (isBottomUp)
1412                 k += (destinationRegion.height - 1) * lineStride;
1413             k += destinationRegion.x;
1414 
1415             for (int j = 0, y = sourceRegion.y;
1416                  j < destinationRegion.height; j++, y+=scaleY) {
1417                 iis.readFully(buf, 0, lineLength);
1418                 for (int i = 0, m = sourceRegion.x;
1419                      i < destinationRegion.width; i++, m += scaleX) {
1420                     //get the bit and assign to the data buffer of the raster
1421                     sdata[k + i] = buf[m];
1422                 }
1423 
1424                 k += isBottomUp ? -lineStride : lineStride;
1425                 iis.skipBytes(skipLength);
1426                 processImageUpdate(bi, 0, j,
1427                                    destinationRegion.width, 1, 1, 1,
1428                                    new int[]{0});
1429                 processImageProgress(100.0F*j/destinationRegion.height);
1430                 if (abortRequested()) {
1431                     break;
1432                 }
1433             }
1434         }
1435     }
1436 
1437     private void read32Bit(int[] idata) throws IOException {
1438         if (noTransform) {
1439             int j = isBottomUp ? (height -1) * width : 0;
1440 
1441             for (int i=0; i<height; i++) {
1442                 iis.readFully(idata, j, width);
1443                 j += isBottomUp ? -width : width;
1444                 processImageUpdate(bi, 0, i,
1445                                    destinationRegion.width, 1, 1, 1,
1446                                    new int[]{0});
1447                 processImageProgress(100.0F * i/destinationRegion.height);
1448                 if (abortRequested()) {
1449                     break;
1450                 }
1451             }
1452         } else {
1453             int[] buf = new int[width];
1454             int lineStride =
1455                 ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
1456 
1457             if (isBottomUp) {
1458                 int lastLine =
1459                     sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1460                 iis.skipBytes(width * (height - 1 - lastLine) << 2);
1461             } else
1462                 iis.skipBytes(width * sourceRegion.y << 2);
1463 
1464             int skipLength = width * (scaleY - 1) << 2;
1465 
1466             int k = destinationRegion.y * lineStride;
1467             if (isBottomUp)
1468                 k += (destinationRegion.height - 1) * lineStride;
1469             k += destinationRegion.x;
1470 
1471             for (int j = 0, y = sourceRegion.y;
1472                  j < destinationRegion.height; j++, y+=scaleY) {
1473                 iis.readFully(buf, 0, width);
1474                 for (int i = 0, m = sourceRegion.x;
1475                      i < destinationRegion.width; i++, m += scaleX) {
1476                     //get the bit and assign to the data buffer of the raster
1477                     idata[k + i] = buf[m];
1478                 }
1479 
1480                 k += isBottomUp ? -lineStride : lineStride;
1481                 iis.skipBytes(skipLength);
1482                 processImageUpdate(bi, 0, j,
1483                                    destinationRegion.width, 1, 1, 1,
1484                                    new int[]{0});
1485                 processImageProgress(100.0F*j/destinationRegion.height);
1486                 if (abortRequested()) {
1487                     break;
1488                 }
1489             }
1490         }
1491     }
1492 
1493     private void readRLE8(byte[] bdata) throws IOException {
1494         // If imageSize field is not provided, calculate it.
1495         int imSize = (int)imageSize;
1496         if (imSize == 0) {
1497             imSize = (int)(bitmapFileSize - bitmapOffset);
1498         }
1499 
1500         int padding = 0;
1501         // If width is not 32 bit aligned, then while uncompressing each
1502         // scanline will have padding bytes, calculate the amount of padding
1503         int remainder = width % 4;
1504         if (remainder != 0) {
1505             padding = 4 - remainder;
1506         }
1507 
1508         // Read till we have the whole image
1509         byte[] values = new byte[imSize];
1510         int bytesRead = 0;
1511         iis.readFully(values, 0, imSize);
1512 
1513         // Since data is compressed, decompress it
1514         decodeRLE8(imSize, padding, values, bdata);
1515     }
1516 
1517     private boolean copyRLE8ScanlineToDst(int lineNo,
1518                                           byte[] val,
1519                                           byte[] bdata) {
1520         // Return value
1521         boolean isSuccess = false;
1522 
1523         // Reusing the code to copy 1 row of pixels or scanline to required
1524         // destination buffer.
1525         if (lineNo >= sourceRegion.y &&
1526             lineNo < sourceRegion.y + sourceRegion.height) {
1527             if (noTransform) {
1528                 int pos = lineNo * width;
1529                 for(int i = 0; i < width; i++)
1530                     bdata[pos++] = val[i];
1531                 processImageUpdate(bi, 0, lineNo,
1532                                    destinationRegion.width, 1, 1, 1,
1533                                    new int[]{0});
1534                 isSuccess = true;
1535             } else if ((lineNo - sourceRegion.y) % scaleY == 0) {
1536                 int lineStride =
1537                     ((ComponentSampleModel)sampleModel).getScanlineStride();
1538                 int currentLine = (lineNo - sourceRegion.y) / scaleY +
1539                     destinationRegion.y;
1540                 int pos = currentLine * lineStride;
1541                 pos += destinationRegion.x;
1542                 for (int i = sourceRegion.x;
1543                      i < sourceRegion.x + sourceRegion.width;
1544                      i += scaleX)
1545                     bdata[pos++] = val[i];
1546                 processImageUpdate(bi, 0, currentLine,
1547                                    destinationRegion.width, 1, 1, 1,
1548                                    new int[]{0});
1549                 isSuccess = true;
1550             }
1551             // Ensure to reset the scanline buffer once the copy is complete.
1552             for(int scIndex = 0; scIndex < width; scIndex++) {
1553                 val[scIndex] = 0;
1554             }
1555         }
1556 
1557         return isSuccess;
1558     }
1559 
1560     private void decodeRLE8(int imSize,
1561                             int padding,
1562                             byte[] values,
1563                             byte[] bdata) throws IOException {
1564 
1565         byte[] val = new byte[width];
1566         int count = 0, l = 0;
1567         int value;
1568         boolean flag = false;
1569         int lineNo = isBottomUp ? height - 1 : 0;
1570         int finished = 0;
1571 
1572         // Ensure image source has sufficient data to decode
1573         while ((count + 1) < imSize) {
1574             value = values[count++] & 0xff;
1575             if (value == 0) {
1576                 switch(values[count++] & 0xff) {
1577 
1578                 case 0:
1579                     // End-of-scanline marker
1580                     // Copy the decoded scanline to destination
1581                     if (copyRLE8ScanlineToDst(lineNo, val, bdata)) {
1582                         finished++;
1583                     }
1584                     processImageProgress(100.0F * finished / destinationRegion.height);
1585                     lineNo += isBottomUp ? -1 : 1;
1586                     l = 0;
1587 
1588                     if (abortRequested()) {
1589                         flag = true;
1590                     }
1591                     break;
1592 
1593                 case 1:
1594                     // End-of-RLE marker
1595                     flag = true;
1596 
1597                     // Check if the last decoded scanline was copied to
1598                     // destination bitmap
1599                     if (l != 0) {
1600                         // Copy the decoded scanline to destination
1601                         if (copyRLE8ScanlineToDst(lineNo, val, bdata)) {
1602                             finished++;
1603                         }
1604                         processImageProgress(100.0F * finished / destinationRegion.height);
1605                         lineNo += isBottomUp ? -1 : 1;
1606                         l = 0;
1607                     }
1608                     break;
1609 
1610                 case 2:
1611                     // delta or vector marker
1612                     if ((count+1) < imSize) {
1613                         int xoff = values[count++] & 0xff;
1614                         int yoff = values[count++] & 0xff;
1615 
1616                         // Check if the yOffset shifts the decoding to another
1617                         // row. In such cases, the decoded pixels in scanline
1618                         // buffer-val must be copied to the destination image.
1619                         if (yoff != 0) {
1620                             // Copy the decoded scanline to destination
1621                             if (copyRLE8ScanlineToDst(lineNo, val, bdata)) {
1622                                 finished++;
1623                             }
1624                             processImageProgress(100.0F * finished
1625                                                  / destinationRegion.height);
1626                             lineNo += isBottomUp ? -yoff : yoff;
1627                         }
1628 
1629                         // Move to the position xoff, yoff down
1630                         l += xoff + yoff*width;
1631                         l %= width;
1632                     }
1633                     break;
1634 
1635                 default:
1636                     int end = values[count-1] & 0xff;
1637                     byte readByte = 0;
1638                     // Ensure to check if the source index-count, does not
1639                     // exceed the source image size
1640                     for (int i=0; (i < end) && (count < imSize); i++) {
1641                         readByte = (byte)(values[count++] & 0xff);
1642                         // Ensure to check if scanline index-l, does not
1643                         // exceed the scanline buffer size (width of image)
1644                         if (l < width) {
1645                             val[l++] = readByte;
1646                         }
1647                     }
1648 
1649                     // Whenever end pixels can fit into odd number of bytes,
1650                     // an extra padding byte will be present, so skip that.
1651                     if ((end & 1) == 1) {
1652                         count++;
1653                     }
1654                     break;
1655                 }
1656             } else {
1657                 // Encoded mode
1658                 // Ensure to check if the source index-count, does not
1659                 // exceed the source image size
1660                 if (count < imSize) {
1661                     for (int i=0; (i < value) && (l < width); i++) {
1662                         val[l++] = (byte)(values[count] & 0xff);
1663                     }
1664                 }
1665 
1666                 count++;
1667             }
1668 
1669             // If End-of-RLE data, then exit the while loop
1670             if (flag) {
1671                 break;
1672             }
1673         }
1674     }
1675 
1676     private void readRLE4(byte[] bdata) throws IOException {
1677 
1678         // If imageSize field is not specified, calculate it.
1679         int imSize = (int)imageSize;
1680         if (imSize == 0) {
1681             imSize = (int)(bitmapFileSize - bitmapOffset);
1682         }
1683 
1684         int padding = 0;
1685         // If width is not 32 byte aligned, then while uncompressing each
1686         // scanline will have padding bytes, calculate the amount of padding
1687         int remainder = width % 4;
1688         if (remainder != 0) {
1689             padding = 4 - remainder;
1690         }
1691 
1692         // Read till we have the whole image
1693         byte[] values = new byte[imSize];
1694         iis.readFully(values, 0, imSize);
1695 
1696         // Decompress the RLE4 compressed data.
1697         decodeRLE4(imSize, padding, values, bdata);
1698     }
1699 
1700     private boolean copyRLE4ScanlineToDst(int lineNo,
1701                                           byte[] val,
1702                                           byte[] bdata) throws IOException {
1703         // Return value
1704         boolean isSuccess = false;
1705 
1706         // Reusing the code to copy 1 row of pixels or scanline to required
1707         // destination buffer.
1708         if (lineNo >= sourceRegion.y &&
1709             lineNo < sourceRegion.y + sourceRegion.height) {
1710             if (noTransform) {
1711                 int pos = lineNo * (width + 1 >> 1);
1712                 for(int i = 0, j = 0; i < width >> 1; i++)
1713                     bdata[pos++] =
1714                         (byte)((val[j++] << 4) | val[j++]);
1715                 if ((width & 1) == 1)
1716                     bdata[pos] |= val[width - 1] << 4;
1717 
1718                 processImageUpdate(bi, 0, lineNo,
1719                                    destinationRegion.width, 1, 1, 1,
1720                                    new int[]{0});
1721                 isSuccess = true;
1722             } else if ((lineNo - sourceRegion.y) % scaleY == 0) {
1723                 int lineStride =
1724                     ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
1725                 int currentLine = (lineNo - sourceRegion.y) / scaleY +
1726                     destinationRegion.y;
1727                 int pos = currentLine * lineStride;
1728                 pos += destinationRegion.x >> 1;
1729                 int shift = (1 - (destinationRegion.x & 1)) << 2;
1730                 for (int i = sourceRegion.x;
1731                      i < sourceRegion.x + sourceRegion.width;
1732                      i += scaleX) {
1733                     bdata[pos] |= val[i] << shift;
1734                     shift += 4;
1735                     if (shift == 4) {
1736                         pos++;
1737                     }
1738                     shift &= 7;
1739                 }
1740                 processImageUpdate(bi, 0, currentLine,
1741                                    destinationRegion.width, 1, 1, 1,
1742                                    new int[]{0});
1743                 isSuccess = true;
1744             }
1745             // Ensure to reset the scanline buffer once the copy is complete.
1746             for(int scIndex = 0; scIndex < width; scIndex++) {
1747                 val[scIndex] = 0;
1748             }
1749         }
1750         return isSuccess;
1751     }
1752 
1753     private void decodeRLE4(int imSize,
1754                             int padding,
1755                             byte[] values,
1756                             byte[] bdata) throws IOException {
1757         byte[] val = new byte[width];
1758         int count = 0, l = 0;
1759         int value;
1760         boolean flag = false;
1761         int lineNo = isBottomUp ? height - 1 : 0;
1762         int finished = 0;
1763 
1764         // Ensure the image has sufficient data before proceeding to decode
1765         while ((count + 1) < imSize) {
1766 
1767             value = values[count++] & 0xFF;
1768             if (value == 0) {
1769 
1770                 // Absolute mode
1771                 switch(values[count++] & 0xFF) {
1772 
1773                 case 0:
1774                     // End-of-scanline marker
1775                     // Copy the decoded scanline to destination
1776                     if (copyRLE4ScanlineToDst(lineNo, val, bdata)) {
1777                         finished++;
1778                     }
1779                     processImageProgress(100.0F * finished / destinationRegion.height);
1780                     lineNo += isBottomUp ? -1 : 1;
1781                     l = 0;
1782 
1783                     if (abortRequested()) {
1784                         flag = true;
1785                     }
1786 
1787                     break;
1788 
1789                 case 1:
1790                     // End-of-RLE marker
1791                     flag = true;
1792 
1793                     // Check if the last decoded scanline was copied to
1794                     // destination bitmap
1795                     if (l != 0) {
1796                         // Copy the decoded scanline to destination
1797                         if (copyRLE4ScanlineToDst(lineNo, val, bdata)) {
1798                             finished++;
1799                         }
1800                         processImageProgress(100.0F * finished / destinationRegion.height);
1801                         lineNo += isBottomUp ? -1 : 1;
1802                         l = 0;
1803                     }
1804                     break;
1805 
1806                 case 2:
1807                     // delta or vector marker
1808                     if ((count + 1) < imSize) {
1809                         int xoff = values[count++] & 0xFF;
1810                         int yoff = values[count++] & 0xFF;
1811 
1812                         // Check if the yOffset shifts the decoding to another
1813                         // row. In such cases, the decoded pixels in scanline
1814                         // buffer-val must be copied to the destination image.
1815                         if (yoff != 0) {
1816                             // Copy the decoded scanline to destination
1817                             if (copyRLE4ScanlineToDst(lineNo, val, bdata)) {
1818                                 finished++;
1819                             }
1820                             processImageProgress(100.0F * finished
1821                                                  / destinationRegion.height);
1822                             lineNo += isBottomUp ? -yoff : yoff;
1823                         }
1824 
1825                         // Move to the position (xoff, yoff). Since l-is used
1826                         // to index into the scanline buffer, the accumulated
1827                         // offset is limited to the width of the scanline
1828                         l += xoff + yoff*width;
1829                         l %= width;
1830                     }
1831                     break;
1832 
1833                 default:
1834                     int end = values[count-1] & 0xFF;
1835                     byte readByte = 0;
1836                     // Ensure to check if the source index-count, does not
1837                     // exceed the source image size
1838                     for (int i = 0; (i < end) && (count < imSize); i++) {
1839                         readByte = (byte)(((i & 1) == 0) ?
1840                                         (values[count] & 0xf0) >> 4 :
1841                                         (values[count++] & 0x0f));
1842                         // Ensure to check if scanline index-l, does not
1843                         // exceed the scanline buffer size (width of image)
1844                         if (l < width) {
1845                             val[l++] = readByte;
1846                         }
1847                     }
1848 
1849                     // When end is odd, the above for loop does not
1850                     // increment count, so do it now.
1851                     if ((end & 1) == 1) {
1852                         count++;
1853                     }
1854 
1855                     // Whenever end pixels can fit into odd number of bytes,
1856                     // an extra padding byte will be present, so skip that.
1857                     if ((((end + 1) / 2) & 1) == 1) {
1858                         count++;
1859                     }
1860                     break;
1861                 }
1862             } else {
1863                 // Encoded mode
1864                 // Ensure to check if the source index-count, does not
1865                 // exceed the source image size
1866                 if (count < imSize) {
1867                     int[] alternate = { (values[count] & 0xf0) >> 4,
1868                                         values[count] & 0x0f };
1869                     for (int i=0; (i < value) && (l < width); i++) {
1870                         val[l++] = (byte)alternate[i & 1];
1871                     }
1872                 }
1873 
1874                 count++;
1875             }
1876 
1877             // If End-of-RLE data, then exit the while loop
1878             if (flag) {
1879                 break;
1880             }
1881         }
1882     }
1883 
1884     /** Decodes the jpeg/png image embedded in the bitmap using any jpeg
1885      *  ImageIO-style plugin.
1886      *
1887      * @param bi The destination {@code BufferedImage}.
1888      * @param bmpParam The {@code ImageReadParam} for decoding this
1889      *          BMP image.  The parameters for subregion, band selection and
1890      *          subsampling are used in decoding the jpeg image.
1891      */
1892 
1893     private BufferedImage readEmbedded(int type,
1894                               BufferedImage bi, ImageReadParam bmpParam)
1895       throws IOException {
1896         String format;
1897         switch(type) {
1898           case BI_JPEG:
1899               format = "JPEG";
1900               break;
1901           case BI_PNG:
1902               format = "PNG";
1903               break;
1904           default:
1905               throw new
1906                   IOException("Unexpected compression type: " + type);
1907         }
1908         ImageReader reader =
1909             ImageIO.getImageReadersByFormatName(format).next();
1910         if (reader == null) {
1911             throw new RuntimeException(I18N.getString("BMPImageReader4") +
1912                                        " " + format);
1913         }
1914         // prepare input
1915         byte[] buff = new byte[(int)imageSize];
1916         iis.read(buff);
1917         reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(buff)));
1918         if (bi == null) {
1919             ImageTypeSpecifier embType = reader.getImageTypes(0).next();
1920             bi = embType.createBufferedImage(destinationRegion.x +
1921                                              destinationRegion.width,
1922                                              destinationRegion.y +
1923                                              destinationRegion.height);
1924         }
1925 
1926         reader.addIIOReadProgressListener(new EmbeddedProgressAdapter() {
1927                 public void imageProgress(ImageReader source,
1928                                           float percentageDone)
1929                 {
1930                     processImageProgress(percentageDone);
1931                 }
1932             });
1933 
1934         reader.addIIOReadUpdateListener(new IIOReadUpdateListener() {
1935                 public void imageUpdate(ImageReader source,
1936                                         BufferedImage theImage,
1937                                         int minX, int minY,
1938                                         int width, int height,
1939                                         int periodX, int periodY,
1940                                         int[] bands)
1941                 {
1942                     processImageUpdate(theImage, minX, minY,
1943                                        width, height,
1944                                        periodX, periodY, bands);
1945                 }
1946                 public void passComplete(ImageReader source,
1947                                          BufferedImage theImage)
1948                 {
1949                     processPassComplete(theImage);
1950                 }
1951                 public void passStarted(ImageReader source,
1952                                         BufferedImage theImage,
1953                                         int pass,
1954                                         int minPass, int maxPass,
1955                                         int minX, int minY,
1956                                         int periodX, int periodY,
1957                                         int[] bands)
1958                 {
1959                     processPassStarted(theImage, pass, minPass, maxPass,
1960                                        minX, minY, periodX, periodY,
1961                                        bands);
1962                 }
1963                 public void thumbnailPassComplete(ImageReader source,
1964                                                   BufferedImage thumb) {}
1965                 public void thumbnailPassStarted(ImageReader source,
1966                                                  BufferedImage thumb,
1967                                                  int pass,
1968                                                  int minPass, int maxPass,
1969                                                  int minX, int minY,
1970                                                  int periodX, int periodY,
1971                                                  int[] bands) {}
1972                 public void thumbnailUpdate(ImageReader source,
1973                                             BufferedImage theThumbnail,
1974                                             int minX, int minY,
1975                                             int width, int height,
1976                                             int periodX, int periodY,
1977                                             int[] bands) {}
1978             });
1979 
1980         reader.addIIOReadWarningListener(new IIOReadWarningListener() {
1981                 public void warningOccurred(ImageReader source, String warning)
1982                 {
1983                     processWarningOccurred(warning);
1984                 }
1985             });
1986 
1987         ImageReadParam param = reader.getDefaultReadParam();
1988         param.setDestination(bi);
1989         param.setDestinationBands(bmpParam.getDestinationBands());
1990         param.setDestinationOffset(bmpParam.getDestinationOffset());
1991         param.setSourceBands(bmpParam.getSourceBands());
1992         param.setSourceRegion(bmpParam.getSourceRegion());
1993         param.setSourceSubsampling(bmpParam.getSourceXSubsampling(),
1994                                    bmpParam.getSourceYSubsampling(),
1995                                    bmpParam.getSubsamplingXOffset(),
1996                                    bmpParam.getSubsamplingYOffset());
1997         reader.read(0, param);
1998         return bi;
1999     }
2000 
2001     private class EmbeddedProgressAdapter implements IIOReadProgressListener {
2002         public void imageComplete(ImageReader src) {}
2003         public void imageProgress(ImageReader src, float percentageDone) {}
2004         public void imageStarted(ImageReader src, int imageIndex) {}
2005         public void thumbnailComplete(ImageReader src) {}
2006         public void thumbnailProgress(ImageReader src, float percentageDone) {}
2007         public void thumbnailStarted(ImageReader src, int iIdx, int tIdx) {}
2008         public void sequenceComplete(ImageReader src) {}
2009         public void sequenceStarted(ImageReader src, int minIndex) {}
2010         public void readAborted(ImageReader src) {}
2011     }
2012 
2013     private static Boolean isLinkedProfileDisabled = null;
2014 
2015     private static boolean isLinkedProfileAllowed() {
2016         if (isLinkedProfileDisabled == null) {
2017             PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
2018                 public Boolean run() {
2019                     return Boolean.getBoolean("sun.imageio.plugins.bmp.disableLinkedProfiles");
2020                 }
2021             };
2022             isLinkedProfileDisabled = AccessController.doPrivileged(a);
2023         }
2024         return !isLinkedProfileDisabled;
2025     }
2026 
2027     private static Boolean isWindowsPlatform = null;
2028 
2029     /**
2030      * Verifies whether the byte array contans a unc path.
2031      * Non-UNC path examples:
2032      *  c:\path\to\file  - simple notation
2033      *  \\?\c:\path\to\file - long notation
2034      *
2035      * UNC path examples:
2036      *  \\server\share - a UNC path in simple notation
2037      *  \\?\UNC\server\share - a UNC path in long notation
2038      *  \\.\some\device - a path to device.
2039      */
2040     private static boolean isUncOrDevicePath(byte[] p) {
2041         if (isWindowsPlatform == null) {
2042             PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
2043                 public Boolean run() {
2044                     String osname = System.getProperty("os.name");
2045                     return (osname != null &&
2046                             osname.toLowerCase().startsWith("win"));
2047                 }
2048             };
2049             isWindowsPlatform = AccessController.doPrivileged(a);
2050         }
2051 
2052         if (!isWindowsPlatform) {
2053             /* no need for the check on platforms except windows */
2054             return false;
2055         }
2056 
2057         /* normalize prefix of the path */
2058         if (p[0] == '/') p[0] = '\\';
2059         if (p[1] == '/') p[1] = '\\';
2060         if (p[3] == '/') p[3] = '\\';
2061 
2062 
2063         if ((p[0] == '\\') && (p[1] == '\\')) {
2064             if ((p[2] == '?') && (p[3] == '\\')) {
2065                 // long path: whether unc or local
2066                 return ((p[4] == 'U' || p[4] == 'u') &&
2067                         (p[5] == 'N' || p[5] == 'n') &&
2068                         (p[6] == 'C' || p[6] == 'c'));
2069             } else {
2070                 // device path or short unc notation
2071                 return true;
2072             }
2073         } else {
2074             return false;
2075         }
2076     }
2077 }
2078