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