Android NDK: read JPG from assets and sdcard

Some parts of the code are borrowed from Independent JPEG Group and
Android NDKでlibjpegをビルドして利用する(UsefullCode.net)

Resulted texture will have dummy alpha components (0xff) for compatibility with PNG.

static uint32_t  make8888(int red, int green, int blue, int alpha){
    return (uint32_t)( ((alpha   << 24) & 0xff000000) |
                       ((blue << 16) & 0x00ff0000) |
                       ((green << 8) & 0x0000ff00) |
                       ( red & 0x000000ff) );
}

static void _JpegError(j_common_ptr cInfo){
    char pszMessage[JMSG_LENGTH_MAX];

    (*cInfo->err->format_message)(cInfo, pszMessage);

    LOGE("Jpeg Lib","error!  %s", pszMessage);
}

// media: 0=asset, 1=sdcard
unsigned char* loadJPG(int medium, AAssetManager* mgr, const char* pImgFileName){ 
    AAsset* pAsset = NULL;
    FILE* fp = NULL;
    if (isJpgRead) return NULL; // already read.

    struct jpeg_decompress_struct cInfo;    
    struct jpeg_error_mgr jError;
    cInfo.err = jpeg_std_error(&jError); // register error handler 1
    jError.error_exit = _JpegError; // register error handler 2
    jpeg_create_decompress(&cInfo); // create a decompresser

    // init the ptr to the source medium //////////////////////////
    if (medium == 0){
        /// load from asset ////////////////////////////////////////

        pAsset = AAssetManager_open(mgr, pImgFileName, AASSET_MODE_UNKNOWN);
        if (!pAsset) return NULL;

        unsigned char* ucharRawData = (unsigned char*)AAsset_getBuffer(pAsset);
        long myAssetLength = (long)AAsset_getLength(pAsset);

        // the jpeg_stdio_src alternative func, which is also included in IJG's lib.
        jpeg_mem_src(&cInfo, ucharRawData, myAssetLength); 

    }else if(medium == 1){
        /// load from FILE /////////////////////////////////////////

        fp = fopen(pImgFileName,"r+");
        if(fp == NULL) return  NULL;
        jpeg_stdio_src(&cInfo, fp); // notify the decomp the ptr to src

    }else {

        LOGE("The medium is not supported.");
        return NULL;

    }

    ///////////////////////////////////////////////
    uint32_t* pTexUint;
    int yy;
    int width, height, pixelSize, lineSize;    
    char* lpbtBits;
    JSAMPLE tmp;
    int rectHeight, rectWidth;

    ///////////////////////////////////////////////
    jpeg_read_header(&cInfo, TRUE); // read header
    jpeg_start_decompress(&cInfo); // start decompression

    width = cInfo.output_width;
    height = height = cInfo.output_height;
    pixelSize = cInfo.output_components;
    lineSize = width * pixelSize;
       
    pTexUint = (uint32_t*)calloc(sizeof(uint32_t), width * height);
    if (pTexUint == NULL){
        switch (medium){
        case 0:
            AAsset_close(pAsset);
            break;
        case 1:
            fclose(fp);
            break;
        }
        return NULL;
    }

    JSAMPLE* pSample = (JSAMPLE*)calloc(sizeof(JSAMPLE), lineSize + 10);
    if (!pSample){
        __android_log_print(ANDROID_LOG_ERROR,"Jpeg Lib","cannot alloc pSample");
        if (pTexUint) free(pTexUint);
        switch (medium){
        case 0:
            AAsset_close(pAsset);
            break;
        case 1:
            fclose(fp);
            break;
        }
        return NULL; //error
    }

    JSAMPROW buffer[1];
    buffer[0] = pSample;
    
    uint32_t* pPixelsUint = pTexUint;
    yy = 0;
    while(cInfo.output_scanline < cInfo.output_height){
        if(yy >= cInfo.output_height)
            break;

        jpeg_read_scanlines(&cInfo, buffer, 1);

        int xx;
        int x3;
        for(xx = 0, x3 = 0; xx < width; xx++, x3 += 3)
            pPixelsUint[xx] = make8888(buffer[0][x3], buffer[0][x3 + 1], buffer[0][x3 + 2], 0xff);

        pPixelsUint = (uint32_t*)pPixelsUint + width;
        yy++;
    }

    jpeg_finish_decompress(&cInfo);
    jpeg_destroy_decompress(&cInfo);

    if (pSample) free(pSample);
    switch (medium){
    case 0:
        AAsset_close(pAsset);
        break;
    case 1:
        fclose(fp);
        break;
    }
    return (unsigned char*)pTexUint;
}