1 /*
   2  * Copyright (c) 1997, 2014, 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 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include "awt_parseImage.h"
  29 #include "imageInitIDs.h"
  30 #include "java_awt_Transparency.h"
  31 #include "java_awt_image_BufferedImage.h"
  32 #include "sun_awt_image_IntegerComponentRaster.h"
  33 #include "sun_awt_image_ImagingLib.h"
  34 #include "java_awt_color_ColorSpace.h"
  35 #include "awt_Mlib.h"
  36 #include "safe_alloc.h"
  37 #include "safe_math.h"
  38 
  39 static int setHints(JNIEnv *env, BufImageS_t *imageP);
  40 
  41 
  42 
  43 /* Parse the buffered image.  All of the raster information is returned in the
  44  * imagePP structure.
  45  *
  46  * The handleCustom parameter specifies whether or not the caller
  47  * can use custom channels.  If it is false and a custom channel
  48  * is encountered, the returned value will be 0 and all structures
  49  * will be deallocated.
  50  *
  51  * Return value:
  52  *    -1:     Exception
  53  *     0:     Can't do it.
  54  *     1:     Success
  55  */
  56 int awt_parseImage(JNIEnv *env, jobject jimage, BufImageS_t **imagePP,
  57                    int handleCustom) {
  58     BufImageS_t *imageP;
  59     int status;
  60     jobject jraster;
  61     jobject jcmodel;
  62 
  63     /* Make sure the image exists */
  64     if (JNU_IsNull(env, jimage)) {
  65         JNU_ThrowNullPointerException(env, "null BufferedImage object");
  66         return -1;
  67     }
  68 
  69     if ((imageP = (BufImageS_t *) calloc(1, sizeof(BufImageS_t))) == NULL) {
  70         JNU_ThrowOutOfMemoryError(env, "Out of memory");
  71         return -1;
  72     }
  73     imageP->jimage = jimage;
  74 
  75     /* Retrieve the raster */
  76     if ((jraster = (*env)->GetObjectField(env, jimage,
  77                                           g_BImgRasterID)) == NULL) {
  78         free((void *) imageP);
  79         JNU_ThrowNullPointerException(env, "null Raster object");
  80         return 0;
  81     }
  82 
  83     /* Retrieve the image type */
  84     imageP->imageType = (*env)->GetIntField(env, jimage, g_BImgTypeID);
  85 
  86     /* Parse the raster */
  87     if ((status = awt_parseRaster(env, jraster, &imageP->raster)) <= 0) {
  88         free((void *)imageP);
  89         return status;
  90     }
  91 
  92     /* Retrieve the color model */
  93     if ((jcmodel = (*env)->GetObjectField(env, jimage, g_BImgCMID)) == NULL) {
  94         free((void *) imageP);
  95         JNU_ThrowNullPointerException(env, "null Raster object");
  96         return 0;
  97     }
  98 
  99     /* Parse the color model */
 100     if ((status = awt_parseColorModel(env, jcmodel, imageP->imageType,
 101                                       &imageP->cmodel)) <= 0) {
 102         awt_freeParsedRaster(&imageP->raster, FALSE);
 103         free((void *)imageP);
 104         return 0;
 105     }
 106 
 107     /* Set hints  */
 108     if ((status = setHints(env, imageP)) <= 0) {
 109         awt_freeParsedImage(imageP, TRUE);
 110         return 0;
 111     }
 112 
 113     *imagePP = imageP;
 114 
 115     return status;
 116 }
 117 
 118 /* Verifies whether the channel offsets are sane and correspond to the type of
 119  * the raster.
 120  *
 121  * Return value:
 122  *     0: Failure: channel offsets are invalid
 123  *     1: Success
 124  */
 125 static int checkChannelOffsets(RasterS_t *rasterP, int dataArrayLength) {
 126     int i, lastPixelOffset, lastScanOffset;
 127     switch (rasterP->rasterType) {
 128     case COMPONENT_RASTER_TYPE:
 129         if (!SAFE_TO_MULT(rasterP->height, rasterP->scanlineStride)) {
 130             return 0;
 131         }
 132         if (!SAFE_TO_MULT(rasterP->width, rasterP->pixelStride)) {
 133             return 0;
 134         }
 135 
 136         lastScanOffset = (rasterP->height - 1) * rasterP->scanlineStride;
 137         lastPixelOffset = (rasterP->width - 1) * rasterP->pixelStride;
 138 
 139 
 140         if (!SAFE_TO_ADD(lastPixelOffset, lastScanOffset)) {
 141             return 0;
 142         }
 143 
 144         lastPixelOffset += lastScanOffset;
 145 
 146         for (i = 0; i < rasterP->numDataElements; i++) {
 147             int off = rasterP->chanOffsets[i];
 148             int size = lastPixelOffset + off;
 149 
 150             if (off < 0 || !SAFE_TO_ADD(lastPixelOffset, off)) {
 151                 return 0;
 152             }
 153 
 154             if (size < lastPixelOffset || size >= dataArrayLength) {
 155                 // an overflow, or insufficient buffer capacity
 156                 return 0;
 157             }
 158         }
 159         return 1;
 160     case BANDED_RASTER_TYPE:
 161         // NB:caller does not support the banded rasters yet,
 162         // so this branch of the code must be re-defined in
 163         // order to provide valid criteria for the data offsets
 164         // verification, when/if banded rasters will be supported.
 165         // At the moment, we prohibit banded rasters as well.
 166         return 0;
 167     default:
 168         // PACKED_RASTER_TYPE: does not support channel offsets
 169         // UNKNOWN_RASTER_TYPE: should not be used, likely indicates an error
 170         return 0;
 171     }
 172 }
 173 
 174 /* Parse the raster.  All of the raster information is returned in the
 175  * rasterP structure.
 176  *
 177  * Return value:
 178  *    -1:     Exception
 179  *     0:     Can't do it (Custom channel)
 180  *     1:     Success
 181  */
 182 int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) {
 183     jobject joffs = NULL;
 184     /* int status;*/
 185     jclass singlePixelPackedSampleModelClass = NULL;
 186     jclass integerComponentRasterClass = NULL;
 187     jclass byteComponentRasterClass = NULL;
 188     jclass shortComponentRasterClass = NULL;
 189     jclass bytePackedRasterClass = NULL;
 190 
 191     if (JNU_IsNull(env, jraster)) {
 192         JNU_ThrowNullPointerException(env, "null Raster object");
 193         return -1;
 194     }
 195 
 196     rasterP->jraster = jraster;
 197     rasterP->width   = (*env)->GetIntField(env, jraster, g_RasterWidthID);
 198     rasterP->height  = (*env)->GetIntField(env, jraster, g_RasterHeightID);
 199     rasterP->numDataElements = (*env)->GetIntField(env, jraster,
 200                                                    g_RasterNumDataElementsID);
 201     rasterP->numBands = (*env)->GetIntField(env, jraster,
 202                                             g_RasterNumBandsID);
 203 
 204     rasterP->baseOriginX = (*env)->GetIntField(env, jraster,
 205                                                g_RasterBaseOriginXID);
 206     rasterP->baseOriginY = (*env)->GetIntField(env, jraster,
 207                                                g_RasterBaseOriginYID);
 208     rasterP->minX = (*env)->GetIntField(env, jraster, g_RasterMinXID);
 209     rasterP->minY = (*env)->GetIntField(env, jraster, g_RasterMinYID);
 210 
 211     rasterP->jsampleModel = (*env)->GetObjectField(env, jraster,
 212                                                    g_RasterSampleModelID);
 213 
 214     if (JNU_IsNull(env, rasterP->jsampleModel)) {
 215         JNU_ThrowNullPointerException(env, "null Raster object");
 216         return -1;
 217     }
 218 
 219     // make sure that the raster type is initialized
 220     rasterP->rasterType = UNKNOWN_RASTER_TYPE;
 221 
 222     if (rasterP->numBands <= 0 ||
 223         rasterP->numBands > MAX_NUMBANDS)
 224     {
 225         /*
 226          * we can't handle such kind of rasters due to limitations
 227          * of SPPSampleModelS_t structure and expand/set methods.
 228          */
 229         return 0;
 230     }
 231 
 232     rasterP->sppsm.isUsed = 0;
 233 
 234     singlePixelPackedSampleModelClass = (*env)->FindClass(env,
 235                             "java/awt/image/SinglePixelPackedSampleModel");
 236     CHECK_NULL_RETURN(singlePixelPackedSampleModelClass, -1);
 237     if ((*env)->IsInstanceOf(env, rasterP->jsampleModel,
 238                              singlePixelPackedSampleModelClass)) {
 239         jobject jmask, joffs, jnbits;
 240 
 241         rasterP->sppsm.isUsed = 1;
 242 
 243         rasterP->sppsm.maxBitSize = (*env)->GetIntField(env,
 244                                                         rasterP->jsampleModel,
 245                                                         g_SPPSMmaxBitID);
 246         jmask = (*env)->GetObjectField(env, rasterP->jsampleModel,
 247                                        g_SPPSMmaskArrID);
 248         joffs = (*env)->GetObjectField(env, rasterP->jsampleModel,
 249                                        g_SPPSMmaskOffID);
 250         jnbits = (*env)->GetObjectField(env, rasterP->jsampleModel,
 251                                         g_SPPSMnBitsID);
 252         if (jmask == NULL || joffs == NULL || jnbits == NULL ||
 253             rasterP->sppsm.maxBitSize < 0)
 254         {
 255             JNU_ThrowInternalError(env, "Can't grab SPPSM fields");
 256             return -1;
 257         }
 258         (*env)->GetIntArrayRegion(env, jmask, 0,
 259                                   rasterP->numBands, rasterP->sppsm.maskArray);
 260         (*env)->GetIntArrayRegion(env, joffs, 0,
 261                                   rasterP->numBands, rasterP->sppsm.offsets);
 262         (*env)->GetIntArrayRegion(env, jnbits, 0,
 263                                   rasterP->numBands, rasterP->sppsm.nBits);
 264 
 265     }
 266     rasterP->baseRasterWidth = (*env)->GetIntField(env, rasterP->jsampleModel,
 267                                                    g_SMWidthID);
 268     rasterP->baseRasterHeight = (*env)->GetIntField(env,
 269                                                     rasterP->jsampleModel,
 270                                                     g_SMHeightID);
 271 
 272     integerComponentRasterClass = (*env)->FindClass(env, "sun/awt/image/IntegerComponentRaster");
 273     CHECK_NULL_RETURN(integerComponentRasterClass, -1);
 274     byteComponentRasterClass = (*env)->FindClass(env, "sun/awt/image/ByteComponentRaster");
 275     CHECK_NULL_RETURN(byteComponentRasterClass, -1);
 276     shortComponentRasterClass = (*env)->FindClass(env,"sun/awt/image/ShortComponentRaster");
 277     CHECK_NULL_RETURN(shortComponentRasterClass, -1);
 278     bytePackedRasterClass = (*env)->FindClass(env, "sun/awt/image/BytePackedRaster");
 279     CHECK_NULL_RETURN(bytePackedRasterClass, -1);
 280     if ((*env)->IsInstanceOf(env, jraster, integerComponentRasterClass)){
 281         rasterP->jdata = (*env)->GetObjectField(env, jraster, g_ICRdataID);
 282         rasterP->dataType = INT_DATA_TYPE;
 283         rasterP->dataSize = 4;
 284         rasterP->dataIsShared = TRUE;
 285         rasterP->rasterType = COMPONENT_RASTER_TYPE;
 286         rasterP->type = (*env)->GetIntField(env, jraster, g_ICRtypeID);
 287         rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_ICRscanstrID);
 288         rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_ICRpixstrID);
 289         joffs = (*env)->GetObjectField(env, jraster, g_ICRdataOffsetsID);
 290     }
 291     else if ((*env)->IsInstanceOf(env, jraster, byteComponentRasterClass)){
 292         rasterP->jdata = (*env)->GetObjectField(env, jraster, g_BCRdataID);
 293         rasterP->dataType = BYTE_DATA_TYPE;
 294         rasterP->dataSize = 1;
 295         rasterP->dataIsShared = TRUE;
 296         rasterP->rasterType = COMPONENT_RASTER_TYPE;
 297         rasterP->type = (*env)->GetIntField(env, jraster, g_BCRtypeID);
 298         rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_BCRscanstrID);
 299         rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_BCRpixstrID);
 300         joffs = (*env)->GetObjectField(env, jraster, g_BCRdataOffsetsID);
 301     }
 302     else if ((*env)->IsInstanceOf(env, jraster, shortComponentRasterClass)){
 303         rasterP->jdata = (*env)->GetObjectField(env, jraster, g_SCRdataID);
 304         rasterP->dataType = SHORT_DATA_TYPE;
 305         rasterP->dataSize = 2;
 306         rasterP->dataIsShared = TRUE;
 307         rasterP->rasterType = COMPONENT_RASTER_TYPE;
 308         rasterP->type = (*env)->GetIntField(env, jraster, g_SCRtypeID);
 309         rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_SCRscanstrID);
 310         rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_SCRpixstrID);
 311         joffs = (*env)->GetObjectField(env, jraster, g_SCRdataOffsetsID);
 312     }
 313     else if ((*env)->IsInstanceOf(env, jraster, bytePackedRasterClass)){
 314         rasterP->rasterType = PACKED_RASTER_TYPE;
 315         rasterP->dataType = BYTE_DATA_TYPE;
 316         rasterP->dataSize = 1;
 317         rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_BPRscanstrID);
 318         rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_BPRpixstrID);
 319         rasterP->jdata = (*env)->GetObjectField(env, jraster, g_BPRdataID);
 320         rasterP->type = (*env)->GetIntField(env, jraster, g_BPRtypeID);
 321         rasterP->chanOffsets = NULL;
 322         if (SAFE_TO_ALLOC_2(rasterP->numDataElements, sizeof(jint))) {
 323             rasterP->chanOffsets =
 324                 (jint *)malloc(rasterP->numDataElements * sizeof(jint));
 325         }
 326         if (rasterP->chanOffsets == NULL) {
 327             /* Out of memory */
 328             JNU_ThrowOutOfMemoryError(env, "Out of memory");
 329             return -1;
 330         }
 331         rasterP->chanOffsets[0] = (*env)->GetIntField(env, jraster, g_BPRdataBitOffsetID);
 332         rasterP->dataType = BYTE_DATA_TYPE;
 333     }
 334     else {
 335         rasterP->type = sun_awt_image_IntegerComponentRaster_TYPE_CUSTOM;
 336         rasterP->dataType = UNKNOWN_DATA_TYPE;
 337         rasterP->rasterType = UNKNOWN_RASTER_TYPE;
 338         rasterP->chanOffsets = NULL;
 339         /* Custom raster */
 340         return 0;
 341     }
 342 
 343     // do basic validation of the raster structure
 344     if (rasterP->width <= 0 || rasterP->height <= 0 ||
 345         rasterP->pixelStride <= 0 || rasterP->scanlineStride <= 0)
 346     {
 347         // invalid raster
 348         return -1;
 349     }
 350 
 351     // channel (data) offsets
 352     switch (rasterP->rasterType) {
 353     case COMPONENT_RASTER_TYPE:
 354     case BANDED_RASTER_TYPE: // note that this routine does not support banded rasters at the moment
 355         // get channel (data) offsets
 356         rasterP->chanOffsets = NULL;
 357         if (SAFE_TO_ALLOC_2(rasterP->numDataElements, sizeof(jint))) {
 358             rasterP->chanOffsets =
 359                 (jint *)malloc(rasterP->numDataElements * sizeof(jint));
 360         }
 361         if (rasterP->chanOffsets == NULL) {
 362             /* Out of memory */
 363             JNU_ThrowOutOfMemoryError(env, "Out of memory");
 364             return -1;
 365         }
 366         (*env)->GetIntArrayRegion(env, joffs, 0, rasterP->numDataElements,
 367                                   rasterP->chanOffsets);
 368         if (rasterP->jdata == NULL) {
 369             // unable to verify the raster
 370             return -1;
 371         }
 372         // verify whether channel offsets look sane
 373         if (!checkChannelOffsets(rasterP, (*env)->GetArrayLength(env, rasterP->jdata))) {
 374             return -1;
 375         }
 376         break;
 377     default:
 378         ; // PACKED_RASTER_TYPE does not use the channel offsets.
 379     }
 380 
 381     /* additional check for sppsm fields validity: make sure that
 382      * size of raster samples doesn't exceed the data type capacity.
 383      */
 384     if (rasterP->dataType > UNKNOWN_DATA_TYPE && /* data type has been recognized */
 385         rasterP->sppsm.maxBitSize > 0 && /* raster has SPP sample model */
 386         rasterP->sppsm.maxBitSize > (rasterP->dataSize * 8))
 387     {
 388         JNU_ThrowInternalError(env, "Raster samples are too big");
 389         return -1;
 390     }
 391 
 392 #if 0
 393     fprintf(stderr,"---------------------\n");
 394     fprintf(stderr,"Width  : %d\n",rasterP->width);
 395     fprintf(stderr,"Height : %d\n",rasterP->height);
 396     fprintf(stderr,"X      : %d\n",rasterP->x);
 397     fprintf(stderr,"Y      : %d\n",rasterP->y);
 398     fprintf(stderr,"numC   : %d\n",rasterP->numDataElements);
 399     fprintf(stderr,"SS     : %d\n",rasterP->scanlineStride);
 400     fprintf(stderr,"PS     : %d\n",rasterP->pixelStride);
 401     fprintf(stderr,"CO     : %d\n",rasterP->chanOffsets);
 402     fprintf(stderr,"shared?: %d\n",rasterP->dataIsShared);
 403     fprintf(stderr,"RasterT: %d\n",rasterP->rasterType);
 404     fprintf(stderr,"DataT  : %d\n",rasterP->dataType);
 405     fprintf(stderr,"---------------------\n");
 406 #endif
 407 
 408     return 1;
 409 }
 410 
 411 static int getColorModelType(JNIEnv *env, jobject jcmodel) {
 412     jclass colorModelClass;
 413 
 414     colorModelClass = (*env)->FindClass(env,
 415                                         "java/awt/image/IndexColorModel");
 416     CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE);
 417 
 418     if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass))
 419     {
 420         return INDEX_CM_TYPE;
 421     }
 422 
 423     colorModelClass = (*env)->FindClass(env,
 424                                         "java/awt/image/PackedColorModel");
 425     CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE);
 426     if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass))
 427     {
 428         colorModelClass = (*env)->FindClass(env,
 429                                             "java/awt/image/DirectColorModel");
 430         CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE);
 431         if  ((*env)->IsInstanceOf(env, jcmodel, colorModelClass)) {
 432             return DIRECT_CM_TYPE;
 433         }
 434         else {
 435             return PACKED_CM_TYPE;
 436         }
 437     }
 438     colorModelClass = (*env)->FindClass(env,
 439                                         "java/awt/image/ComponentColorModel");
 440     CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE);
 441     if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass))
 442     {
 443         return COMPONENT_CM_TYPE;
 444     }
 445 
 446     return UNKNOWN_CM_TYPE;
 447 }
 448 
 449 int awt_parseColorModel (JNIEnv *env, jobject jcmodel, int imageType,
 450                          ColorModelS_t *cmP) {
 451     /*jmethodID jID;   */
 452     jobject jnBits;
 453     jsize   nBitsLength;
 454 
 455     int i;
 456     static jobject s_jdefCM = NULL;
 457 
 458     if (JNU_IsNull(env, jcmodel)) {
 459         JNU_ThrowNullPointerException(env, "null ColorModel object");
 460         return -1;
 461     }
 462 
 463     cmP->jcmodel = jcmodel;
 464 
 465     cmP->jcspace = (*env)->GetObjectField(env, jcmodel, g_CMcspaceID);
 466 
 467     cmP->numComponents = (*env)->GetIntField(env, jcmodel,
 468                                              g_CMnumComponentsID);
 469     cmP->supportsAlpha = (*env)->GetBooleanField(env, jcmodel,
 470                                                  g_CMsuppAlphaID);
 471     cmP->isAlphaPre = (*env)->GetBooleanField(env,jcmodel,
 472                                               g_CMisAlphaPreID);
 473     cmP->transparency = (*env)->GetIntField(env, jcmodel,
 474                                             g_CMtransparencyID);
 475 
 476     jnBits = (*env)->GetObjectField(env, jcmodel, g_CMnBitsID);
 477     if (jnBits == NULL) {
 478         JNU_ThrowNullPointerException(env, "null nBits structure in CModel");
 479         return -1;
 480     }
 481 
 482     nBitsLength = (*env)->GetArrayLength(env, jnBits);
 483     if (nBitsLength != cmP->numComponents) {
 484         // invalid number of components?
 485         return -1;
 486     }
 487 
 488     cmP->nBits = NULL;
 489     if (SAFE_TO_ALLOC_2(cmP->numComponents, sizeof(jint))) {
 490         cmP->nBits = (jint *)malloc(cmP->numComponents * sizeof(jint));
 491     }
 492 
 493     if (cmP->nBits == NULL){
 494         JNU_ThrowOutOfMemoryError(env, "Out of memory");
 495         return -1;
 496     }
 497     (*env)->GetIntArrayRegion(env, jnBits, 0, cmP->numComponents,
 498                               cmP->nBits);
 499     cmP->maxNbits = 0;
 500     for (i=0; i < cmP->numComponents; i++) {
 501         if (cmP->maxNbits < cmP->nBits[i]) {
 502             cmP->maxNbits = cmP->nBits[i];
 503         }
 504     }
 505 
 506     cmP->is_sRGB = (*env)->GetBooleanField(env, cmP->jcmodel, g_CMis_sRGBID);
 507 
 508     cmP->csType = (*env)->GetIntField(env, cmP->jcmodel, g_CMcsTypeID);
 509 
 510     cmP->cmType = getColorModelType(env, jcmodel);
 511     JNU_CHECK_EXCEPTION_RETURN(env, -1);
 512 
 513     cmP->isDefaultCM = FALSE;
 514     cmP->isDefaultCompatCM = FALSE;
 515 
 516     /* look for standard cases */
 517     if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB) {
 518         cmP->isDefaultCM = TRUE;
 519         cmP->isDefaultCompatCM = TRUE;
 520     } else if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE ||
 521                imageType == java_awt_image_BufferedImage_TYPE_INT_RGB ||
 522                imageType == java_awt_image_BufferedImage_TYPE_INT_BGR ||
 523                imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR ||
 524                imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE)
 525     {
 526         cmP->isDefaultCompatCM = TRUE;
 527     }
 528     else {
 529         /* Figure out if this is the default CM */
 530         if (s_jdefCM == NULL) {
 531             jobject defCM;
 532             jclass jcm = (*env)->FindClass(env, "java/awt/image/ColorModel");
 533             CHECK_NULL_RETURN(jcm, -1);
 534             defCM = (*env)->CallStaticObjectMethod(env, jcm,
 535                                                    g_CMgetRGBdefaultMID, NULL);
 536             s_jdefCM = (*env)->NewGlobalRef(env, defCM);
 537             if (defCM == NULL || s_jdefCM == NULL) {
 538                 (*env)->ExceptionClear(env);
 539                 JNU_ThrowNullPointerException(env, "Unable to find default CM");
 540                 return -1;
 541             }
 542         }
 543         cmP->isDefaultCM = ((*env)->IsSameObject(env, s_jdefCM, jcmodel));
 544         cmP->isDefaultCompatCM = cmP->isDefaultCM;
 545     }
 546 
 547     /* check whether image attributes correspond to default cm */
 548     if (cmP->isDefaultCompatCM) {
 549         if (cmP->csType != java_awt_color_ColorSpace_TYPE_RGB ||
 550             !cmP->is_sRGB)
 551         {
 552             return -1;
 553         }
 554 
 555         for (i = 0; i < cmP->numComponents; i++) {
 556             if (cmP->nBits[i] != 8) {
 557                 return -1;
 558             }
 559         }
 560     }
 561 
 562     /* Get index color model attributes */
 563     if (imageType == java_awt_image_BufferedImage_TYPE_BYTE_INDEXED ||
 564         cmP->cmType == INDEX_CM_TYPE)
 565     {
 566         cmP->transIdx = (*env)->GetIntField(env, jcmodel, g_ICMtransIdxID);
 567         cmP->mapSize = (*env)->GetIntField(env, jcmodel, g_ICMmapSizeID);
 568         cmP->jrgb    = (*env)->GetObjectField(env, jcmodel, g_ICMrgbID);
 569         if (cmP->transIdx == -1) {
 570             /* Need to find the transparent index */
 571             int *rgb = (int *) (*env)->GetPrimitiveArrayCritical(env,
 572                                                                  cmP->jrgb,
 573                                                                  NULL);
 574             if (rgb == NULL) {
 575                 return -1;
 576             }
 577             for (i=0; i < cmP->mapSize; i++) {
 578                 if ((rgb[i]&0xff000000) == 0) {
 579                     cmP->transIdx = i;
 580                     break;
 581                 }
 582             }
 583             (*env)->ReleasePrimitiveArrayCritical(env, cmP->jrgb, rgb,
 584                                                   JNI_ABORT);
 585             if (cmP->transIdx == -1) {
 586                 /* Now what? No transparent pixel... */
 587                 cmP->transIdx = 0;
 588             }
 589         }
 590     }
 591 
 592     return 1;
 593 }
 594 
 595 void awt_freeParsedRaster(RasterS_t *rasterP, int freeRasterP) {
 596     if (rasterP->chanOffsets) {
 597         free((void *) rasterP->chanOffsets);
 598     }
 599 
 600     if (freeRasterP) {
 601         free((void *) rasterP);
 602     }
 603 }
 604 
 605 void awt_freeParsedImage(BufImageS_t *imageP, int freeImageP) {
 606     if (imageP->hints.colorOrder) {
 607         free ((void *) imageP->hints.colorOrder);
 608     }
 609 
 610     if (imageP->cmodel.nBits) {
 611         free ((void *) imageP->cmodel.nBits);
 612     }
 613 
 614     /* Free the raster */
 615     awt_freeParsedRaster(&imageP->raster, FALSE);
 616 
 617     if (freeImageP) {
 618         free((void *) imageP);
 619     }
 620 }
 621 
 622 static void
 623 awt_getBIColorOrder(int type, int *colorOrder) {
 624     switch(type) {
 625         case java_awt_image_BufferedImage_TYPE_INT_ARGB:
 626         case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE:
 627 #ifdef _LITTLE_ENDIAN
 628             colorOrder[0] = 2;
 629             colorOrder[1] = 1;
 630             colorOrder[2] = 0;
 631             colorOrder[3] = 3;
 632 #else
 633             colorOrder[0] = 1;
 634             colorOrder[1] = 2;
 635             colorOrder[2] = 3;
 636             colorOrder[3] = 0;
 637 #endif
 638             break;
 639         case java_awt_image_BufferedImage_TYPE_INT_BGR:
 640 #ifdef _LITTLE_ENDIAN
 641             colorOrder[0] = 0;
 642             colorOrder[1] = 1;
 643             colorOrder[2] = 2;
 644 #else
 645             colorOrder[0] = 3;
 646             colorOrder[1] = 2;
 647             colorOrder[2] = 1;
 648 #endif
 649             break;
 650         case java_awt_image_BufferedImage_TYPE_INT_RGB:
 651 #ifdef _LITTLE_ENDIAN
 652             colorOrder[0] = 2;
 653             colorOrder[1] = 1;
 654             colorOrder[2] = 0;
 655 #else
 656             colorOrder[0] = 1;
 657             colorOrder[1] = 2;
 658             colorOrder[2] = 3;
 659 #endif
 660             break;
 661         case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR:
 662         case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE:
 663             colorOrder[0] = 3;
 664             colorOrder[1] = 2;
 665             colorOrder[2] = 1;
 666             colorOrder[3] = 0;
 667             break;
 668         case java_awt_image_BufferedImage_TYPE_3BYTE_BGR:
 669             colorOrder[0] = 2;
 670             colorOrder[1] = 1;
 671             colorOrder[2] = 0;
 672             break;
 673         case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB:
 674         case java_awt_image_BufferedImage_TYPE_USHORT_555_RGB:
 675             colorOrder[0] = 0;
 676             colorOrder[1] = 1;
 677             colorOrder[2] = 2;
 678             break;
 679         case java_awt_image_BufferedImage_TYPE_BYTE_GRAY:
 680         case java_awt_image_BufferedImage_TYPE_USHORT_GRAY:
 681         case java_awt_image_BufferedImage_TYPE_BYTE_BINARY:
 682         case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED:
 683             colorOrder[0] = 0;
 684             break;
 685     }
 686 }
 687 
 688 static int
 689 setHints(JNIEnv *env, BufImageS_t *imageP) {
 690     HintS_t *hintP = &imageP->hints;
 691     RasterS_t *rasterP = &imageP->raster;
 692     ColorModelS_t *cmodelP = &imageP->cmodel;
 693     int imageType = imageP->imageType;
 694 
 695     // check whether raster and color model are compatible
 696     if (cmodelP->numComponents != rasterP->numBands) {
 697         if (cmodelP->cmType != INDEX_CM_TYPE) {
 698             return -1;
 699         }
 700     }
 701 
 702     hintP->numChans = imageP->cmodel.numComponents;
 703     hintP->colorOrder = NULL;
 704     if (SAFE_TO_ALLOC_2(hintP->numChans, sizeof(int))) {
 705         hintP->colorOrder = (int *)malloc(hintP->numChans * sizeof(int));
 706     }
 707     if (hintP->colorOrder == NULL) {
 708         JNU_ThrowOutOfMemoryError(env, "Out of memory");
 709         return -1;
 710     }
 711     if (imageType != java_awt_image_BufferedImage_TYPE_CUSTOM) {
 712         awt_getBIColorOrder(imageType, hintP->colorOrder);
 713     }
 714     if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB ||
 715         imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE ||
 716         imageType == java_awt_image_BufferedImage_TYPE_INT_RGB)
 717     {
 718         hintP->channelOffset = rasterP->chanOffsets[0];
 719         /* These hints are #bytes  */
 720         hintP->dataOffset    = hintP->channelOffset*rasterP->dataSize;
 721         hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
 722         hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
 723         hintP->packing = BYTE_INTERLEAVED;
 724     } else if (imageType ==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR ||
 725                imageType==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE||
 726                imageType == java_awt_image_BufferedImage_TYPE_3BYTE_BGR ||
 727                imageType == java_awt_image_BufferedImage_TYPE_INT_BGR)
 728     {
 729         if (imageType == java_awt_image_BufferedImage_TYPE_INT_BGR) {
 730             hintP->channelOffset = rasterP->chanOffsets[0];
 731         }
 732         else {
 733             hintP->channelOffset = rasterP->chanOffsets[hintP->numChans-1];
 734         }
 735         hintP->dataOffset    = hintP->channelOffset*rasterP->dataSize;
 736         hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
 737         hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
 738         hintP->packing = BYTE_INTERLEAVED;
 739     } else if (imageType==java_awt_image_BufferedImage_TYPE_USHORT_565_RGB ||
 740                imageType==java_awt_image_BufferedImage_TYPE_USHORT_555_RGB) {
 741         hintP->needToExpand  = TRUE;
 742         hintP->expandToNbits = 8;
 743         hintP->packing = PACKED_SHORT_INTER;
 744     } else if (cmodelP->cmType == INDEX_CM_TYPE) {
 745         int i;
 746         hintP->numChans = 1;
 747         hintP->channelOffset = rasterP->chanOffsets[0];
 748         hintP->dataOffset    = hintP->channelOffset*rasterP->dataSize;
 749         hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
 750         hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
 751         switch(rasterP->dataType ) {
 752         case BYTE_DATA_TYPE:
 753             if (rasterP->rasterType == PACKED_RASTER_TYPE) {
 754                 hintP->needToExpand = TRUE;
 755                 hintP->expandToNbits = 8;
 756                 hintP->packing = BYTE_PACKED_BAND;
 757             }
 758             else {
 759                 hintP->packing = BYTE_SINGLE_BAND;
 760             }
 761             break;
 762         case SHORT_DATA_TYPE:
 763             hintP->packing = SHORT_SINGLE_BAND;
 764             break;
 765         case INT_DATA_TYPE:
 766         default:
 767             hintP->packing = UNKNOWN_PACKING;
 768             break;
 769         }
 770         for (i=0; i < hintP->numChans; i++) {
 771             hintP->colorOrder[i] = i;
 772         }
 773     }
 774     else if (cmodelP->cmType == COMPONENT_CM_TYPE) {
 775         /* Figure out if it is interleaved */
 776         int bits=1;
 777         int i;
 778         int low = rasterP->chanOffsets[0];
 779         int diff;
 780         int banded = 0;
 781         for (i=1; i < hintP->numChans; i++) {
 782             if (rasterP->chanOffsets[i] < low) {
 783                 low = rasterP->chanOffsets[i];
 784             }
 785         }
 786         for (i=1; i < hintP->numChans; i++) {
 787             diff = rasterP->chanOffsets[i]-low;
 788             if (diff < hintP->numChans) {
 789                 if (bits & (1<<diff)) {
 790                     /* Overlapping samples */
 791                     /* Could just copy */
 792                     return -1;
 793                 }
 794                 bits |= (1<<diff);
 795             }
 796             else if (diff >= rasterP->width) {
 797                 banded = 1;
 798             }
 799             /* Ignore the case if bands are overlapping */
 800         }
 801         hintP->channelOffset = low;
 802         hintP->dataOffset    = low*rasterP->dataSize;
 803         hintP->sStride       = rasterP->scanlineStride*rasterP->dataSize;
 804         hintP->pStride       = rasterP->pixelStride*rasterP->dataSize;
 805         switch(rasterP->dataType) {
 806         case BYTE_DATA_TYPE:
 807             hintP->packing = BYTE_COMPONENTS;
 808             break;
 809         case SHORT_DATA_TYPE:
 810             hintP->packing = SHORT_COMPONENTS;
 811             break;
 812         default:
 813             /* Don't handle any other case */
 814             return -1;
 815         }
 816         if (bits == ((1<<hintP->numChans)-1)) {
 817             hintP->packing |= INTERLEAVED;
 818             for (i=0; i < hintP->numChans; i++) {
 819                 hintP->colorOrder[rasterP->chanOffsets[i]-low] = i;
 820             }
 821         }
 822         else if (banded == 1) {
 823             int bandSize = rasterP->width*rasterP->height;
 824             hintP->packing |= BANDED;
 825             for (i=0; i < hintP->numChans; i++) {
 826                 /* REMIND: Not necessarily correct */
 827                 hintP->colorOrder[(rasterP->chanOffsets[i]-low)%bandSize] = i;
 828             }
 829         }
 830         else {
 831             return -1;
 832         }
 833     }
 834     else if (cmodelP->cmType == DIRECT_CM_TYPE || cmodelP->cmType == PACKED_CM_TYPE) {
 835         int i;
 836 
 837         /* do some sanity check first: make sure that
 838          * - sample model is SinglePixelPackedSampleModel
 839          * - number of bands in the raster corresponds to the number
 840          *   of color components in the color model
 841          */
 842         if (!rasterP->sppsm.isUsed ||
 843             rasterP->numBands != cmodelP->numComponents)
 844         {
 845             /* given raster is not compatible with the color model,
 846              * so the operation has to be aborted.
 847              */
 848             return -1;
 849         }
 850 
 851         if (cmodelP->maxNbits > 8) {
 852             hintP->needToExpand = TRUE;
 853             hintP->expandToNbits = cmodelP->maxNbits;
 854         }
 855         else if (rasterP->sppsm.offsets != NULL) {
 856             for (i=0; i < rasterP->numBands; i++) {
 857                 if (!(rasterP->sppsm.offsets[i] % 8)) {
 858                     hintP->needToExpand  = TRUE;
 859                     hintP->expandToNbits = 8;
 860                     break;
 861                 }
 862                 else {
 863                     hintP->colorOrder[i] = rasterP->sppsm.offsets[i]>>3;
 864                 }
 865             }
 866         }
 867 
 868         hintP->channelOffset = rasterP->chanOffsets[0];
 869         hintP->dataOffset    = hintP->channelOffset*rasterP->dataSize;
 870         hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
 871         hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
 872         if (hintP->needToExpand) {
 873             switch(rasterP->dataType) {
 874             case BYTE_DATA_TYPE:
 875                 hintP->packing = PACKED_BYTE_INTER;
 876                 break;
 877             case SHORT_DATA_TYPE:
 878                 hintP->packing = PACKED_SHORT_INTER;
 879                 break;
 880             case INT_DATA_TYPE:
 881                 hintP->packing = PACKED_INT_INTER;
 882                 break;
 883             default:
 884                 /* Don't know what it is */
 885                 return -1;
 886             }
 887         }
 888         else {
 889             hintP->packing = BYTE_INTERLEAVED;
 890 
 891         }
 892     }
 893     else {
 894         /* REMIND: Need to handle more cases */
 895         return -1;
 896     }
 897 
 898     return 1;
 899 }
 900 
 901 #define MAX_TO_GRAB (10240)
 902 
 903 typedef union {
 904     void *pv;
 905     unsigned char *pb;
 906     unsigned short *ps;
 907 } PixelData_t;
 908 
 909 
 910 int awt_getPixels(JNIEnv *env, RasterS_t *rasterP, void *bufferP) {
 911     const int w = rasterP->width;
 912     const int h = rasterP->height;
 913     const int numBands = rasterP->numBands;
 914     int y;
 915     int i;
 916     int maxLines;
 917     jobject jsm;
 918     int off = 0;
 919     jarray jdata = NULL;
 920     jobject jdatabuffer;
 921     int *dataP;
 922     int maxSamples;
 923     PixelData_t p;
 924 
 925     if (bufferP == NULL) {
 926         return -1;
 927     }
 928 
 929     if (rasterP->dataType != BYTE_DATA_TYPE &&
 930         rasterP->dataType != SHORT_DATA_TYPE)
 931     {
 932         return -1;
 933     }
 934 
 935     p.pv = bufferP;
 936 
 937     if (!SAFE_TO_MULT(w, numBands)) {
 938         return -1;
 939     }
 940     maxSamples = w * numBands;
 941 
 942     maxLines = maxSamples > MAX_TO_GRAB ? 1 : (MAX_TO_GRAB / maxSamples);
 943     if (maxLines > h) {
 944         maxLines = h;
 945     }
 946 
 947     if (!SAFE_TO_MULT(maxSamples, maxLines)) {
 948         return -1;
 949     }
 950 
 951     maxSamples *= maxLines;
 952 
 953     jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID);
 954     jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster,
 955                                          g_RasterDataBufferID);
 956 
 957     jdata = (*env)->NewIntArray(env, maxSamples);
 958     if (JNU_IsNull(env, jdata)) {
 959         (*env)->ExceptionClear(env);
 960         JNU_ThrowOutOfMemoryError(env, "Out of Memory");
 961         return -1;
 962     }
 963 
 964     for (y = 0; y < h; y += maxLines) {
 965         if (y + maxLines > h) {
 966             maxLines = h - y;
 967             maxSamples = w * numBands * maxLines;
 968         }
 969 
 970         (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID,
 971                                  0, y, w,
 972                                  maxLines, jdata, jdatabuffer);
 973 
 974         if ((*env)->ExceptionOccurred(env)) {
 975             (*env)->DeleteLocalRef(env, jdata);
 976             return -1;
 977         }
 978 
 979         dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
 980                                                           NULL);
 981         if (dataP == NULL) {
 982             (*env)->DeleteLocalRef(env, jdata);
 983             return -1;
 984         }
 985 
 986         switch (rasterP->dataType) {
 987         case BYTE_DATA_TYPE:
 988             for (i = 0; i < maxSamples; i ++) {
 989                 p.pb[off++] = (unsigned char) dataP[i];
 990             }
 991             break;
 992         case SHORT_DATA_TYPE:
 993             for (i = 0; i < maxSamples; i ++) {
 994                 p.ps[off++] = (unsigned short) dataP[i];
 995             }
 996             break;
 997         }
 998 
 999         (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
1000                                               JNI_ABORT);
1001     }
1002     (*env)->DeleteLocalRef(env, jdata);
1003 
1004     return 1;
1005 }
1006 
1007 int awt_setPixels(JNIEnv *env, RasterS_t *rasterP, void *bufferP) {
1008     const int w = rasterP->width;
1009     const int h = rasterP->height;
1010     const int numBands = rasterP->numBands;
1011 
1012     int y;
1013     int i;
1014     int maxLines;
1015     jobject jsm;
1016     int off = 0;
1017     jarray jdata = NULL;
1018     jobject jdatabuffer;
1019     int *dataP;
1020     int maxSamples;
1021     PixelData_t p;
1022 
1023     if (bufferP == NULL) {
1024         return -1;
1025     }
1026 
1027     if (rasterP->dataType != BYTE_DATA_TYPE &&
1028         rasterP->dataType != SHORT_DATA_TYPE)
1029     {
1030         return -1;
1031     }
1032 
1033     p.pv = bufferP;
1034 
1035     if (!SAFE_TO_MULT(w, numBands)) {
1036         return -1;
1037     }
1038     maxSamples = w * numBands;
1039 
1040     maxLines = maxSamples > MAX_TO_GRAB ? 1 : (MAX_TO_GRAB / maxSamples);
1041     if (maxLines > h) {
1042         maxLines = h;
1043     }
1044 
1045     if (!SAFE_TO_MULT(maxSamples, maxLines)) {
1046         return -1;
1047     }
1048 
1049     maxSamples *= maxLines;
1050 
1051     jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID);
1052     jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster,
1053                                          g_RasterDataBufferID);
1054 
1055     jdata = (*env)->NewIntArray(env, maxSamples);
1056     if (JNU_IsNull(env, jdata)) {
1057         (*env)->ExceptionClear(env);
1058         JNU_ThrowOutOfMemoryError(env, "Out of Memory");
1059         return -1;
1060     }
1061 
1062     for (y = 0; y < h; y += maxLines) {
1063         if (y + maxLines > h) {
1064             maxLines = h - y;
1065             maxSamples = w * numBands * maxLines;
1066         }
1067         dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
1068                                                           NULL);
1069         if (dataP == NULL) {
1070             (*env)->DeleteLocalRef(env, jdata);
1071             return -1;
1072         }
1073 
1074         switch (rasterP->dataType) {
1075         case BYTE_DATA_TYPE:
1076             for (i = 0; i < maxSamples; i ++) {
1077                 dataP[i] = p.pb[off++];
1078             }
1079             break;
1080         case SHORT_DATA_TYPE:
1081             for (i = 0; i < maxSamples; i ++) {
1082                 dataP[i] = p.ps[off++];
1083             }
1084             break;
1085         }
1086 
1087         (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
1088                                               JNI_ABORT);
1089 
1090         (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID,
1091                                0, y, w,
1092                                maxLines, jdata, jdatabuffer);
1093 
1094         if ((*env)->ExceptionOccurred(env)) {
1095             (*env)->DeleteLocalRef(env, jdata);
1096             return -1;
1097         }
1098     }
1099 
1100     (*env)->DeleteLocalRef(env, jdata);
1101 
1102     return 1;
1103 }