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