Commit message: fixed error handling for broken full-color images
CVE: CVE-2013-2126
CWE: CWE-399
Vulnerability description: Multiple double free vulnerabilities in the LibRaw::unpack function in libraw_cxx.cpp in LibRaw before 0.15.2 allow context-dependent attackers to cause a denial of service (application crash) and possibly execute arbitrary code via a malformed full-color (1) Foveon or (2) sRAW image file.

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw::get_decoder_info(libraw_decoder_info_t* d_info)
{
    if(!d_info)   return LIBRAW_UNSPECIFIED_ERROR;
    if(!load_raw) return LIBRAW_OUT_OF_ORDER_CALL;
    
    d_info->decoder_flags = LIBRAW_DECODER_NOTSET;

    // sorted names order
    if (load_raw == &LibRaw::adobe_dng_load_raw_lj) 
        {
            // Check rbayer
            d_info->decoder_name = "adobe_dng_load_raw_lj()"; 
            d_info->decoder_flags = imgdata.idata.filters ? LIBRAW_DECODER_FLATFIELD : LIBRAW_DECODER_4COMPONENT ;
            d_info->decoder_flags |= LIBRAW_DECODER_HASCURVE;
        }
    else if (load_raw == &LibRaw::adobe_dng_load_raw_nc)
        {
            // Check rbayer
            d_info->decoder_name = "adobe_dng_load_raw_nc()"; 
            d_info->decoder_flags = imgdata.idata.filters ? LIBRAW_DECODER_FLATFIELD : LIBRAW_DECODER_4COMPONENT;
            d_info->decoder_flags |= LIBRAW_DECODER_HASCURVE;
        }
    else if (load_raw == &LibRaw::canon_600_load_raw) 
        {
            d_info->decoder_name = "canon_600_load_raw()";   
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD; // WB set within decoder, no need to load raw
        }
    else if (load_raw == &LibRaw::canon_compressed_load_raw)
        {
            d_info->decoder_name = "canon_compressed_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::canon_sraw_load_raw) 
        {
            d_info->decoder_name = "canon_sraw_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_LEGACY; 
        }
    else if (load_raw == &LibRaw::eight_bit_load_raw )
        {
            d_info->decoder_name = "eight_bit_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
            d_info->decoder_flags |= LIBRAW_DECODER_HASCURVE;
        }
    else if (load_raw == &LibRaw::foveon_load_raw )
        {
            d_info->decoder_name = "foveon_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_LEGACY; 
        }
    else if (load_raw == &LibRaw::fuji_load_raw ) 
        { 
            d_info->decoder_name = "fuji_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::hasselblad_load_raw )
        {
            d_info->decoder_name = "hasselblad_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::imacon_full_load_raw )
        {
            d_info->decoder_name = "imacon_full_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_4COMPONENT; 
        }
    else if (load_raw == &LibRaw::kodak_262_load_raw )
        {
            d_info->decoder_name = "kodak_262_load_raw()"; // UNTESTED!
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
            d_info->decoder_flags |= LIBRAW_DECODER_HASCURVE;
        }
    else if (load_raw == &LibRaw::kodak_65000_load_raw )
        {
            d_info->decoder_name = "kodak_65000_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
            d_info->decoder_flags |= LIBRAW_DECODER_HASCURVE;
        }
    else if (load_raw == &LibRaw::kodak_dc120_load_raw )
        {
            d_info->decoder_name = "kodak_dc120_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::kodak_jpeg_load_raw )
        {
            // UNTESTED + RBAYER
            d_info->decoder_name = "kodak_jpeg_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::kodak_radc_load_raw )
        {
            d_info->decoder_name = "kodak_radc_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_4COMPONENT;
        }
    else if (load_raw == &LibRaw::kodak_rgb_load_raw ) 
        {
            // UNTESTED
            d_info->decoder_name = "kodak_rgb_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_4COMPONENT;
        }
    else if (load_raw == &LibRaw::kodak_yrgb_load_raw )    
        {
            d_info->decoder_name = "kodak_yrgb_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_4COMPONENT;
            d_info->decoder_flags |= LIBRAW_DECODER_HASCURVE;
        }
    else if (load_raw == &LibRaw::kodak_ycbcr_load_raw )
        {
            // UNTESTED
            d_info->decoder_name = "kodak_ycbcr_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_4COMPONENT;
            d_info->decoder_flags |= LIBRAW_DECODER_HASCURVE;
        }
    else if (load_raw == &LibRaw::leaf_hdr_load_raw )
        {
            d_info->decoder_name = "leaf_hdr_load_raw()"; 
            d_info->decoder_flags = imgdata.idata.filters ? LIBRAW_DECODER_FLATFIELD : LIBRAW_DECODER_4COMPONENT;
        }
    else if (load_raw == &LibRaw::lossless_jpeg_load_raw)
        {
            // Check rbayer
            d_info->decoder_name = "lossless_jpeg_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD | LIBRAW_DECODER_HASCURVE;
        }
    else if (load_raw == &LibRaw::minolta_rd175_load_raw ) 
        {  
            // UNTESTED
            d_info->decoder_name = "minolta_rd175_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::nikon_compressed_load_raw)
        {
            // Check rbayer
            d_info->decoder_name = "nikon_compressed_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::nokia_load_raw )
        {
            // UNTESTED
            d_info->decoder_name = "nokia_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::olympus_load_raw )
        {
            d_info->decoder_name = "olympus_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::packed_load_raw )
        {
            d_info->decoder_name = "packed_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::panasonic_load_raw )
        {
            d_info->decoder_name = "panasonic_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::pentax_load_raw )
        {
            d_info->decoder_name = "pentax_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::phase_one_load_raw )
        {
            d_info->decoder_name = "phase_one_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::phase_one_load_raw_c )
        {
            d_info->decoder_name = "phase_one_load_raw_c()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::quicktake_100_load_raw )
        {
            // UNTESTED
            d_info->decoder_name = "quicktake_100_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::rollei_load_raw )
        {
            // UNTESTED
            d_info->decoder_name = "rollei_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::sinar_4shot_load_raw )
        {
            // UNTESTED
            d_info->decoder_name = "sinar_4shot_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_4COMPONENT;
        }
    else if (load_raw == &LibRaw::smal_v6_load_raw )
        {
            // UNTESTED
            d_info->decoder_name = "smal_v6_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::smal_v9_load_raw )
        {
            // UNTESTED
            d_info->decoder_name = "smal_v9_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::sony_load_raw )
        {
            d_info->decoder_name = "sony_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::sony_arw_load_raw )
        {
            d_info->decoder_name = "sony_arw_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
        }
    else if (load_raw == &LibRaw::sony_arw2_load_raw )
        {
            d_info->decoder_name = "sony_arw2_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD;
            d_info->decoder_flags |= LIBRAW_DECODER_HASCURVE;
        }
    else if (load_raw == &LibRaw::unpacked_load_raw )
        {
            d_info->decoder_name = "unpacked_load_raw()"; 
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD | LIBRAW_DECODER_USEBAYER2;
        }
    else  if (load_raw == &LibRaw::redcine_load_raw)
        {
            d_info->decoder_name = "redcine_load_raw()";
            d_info->decoder_flags = LIBRAW_DECODER_FLATFIELD; 
            d_info->decoder_flags |= LIBRAW_DECODER_HASCURVE;
        }
    else
        {
            d_info->decoder_name = "Unknown unpack function";
            d_info->decoder_flags = LIBRAW_DECODER_NOTSET;
        }
    return LIBRAW_SUCCESS;
}

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw::dcraw_process(void)
{
    int quality,i;

    int iterations=-1, dcb_enhance=1, noiserd=0;
    int eeci_refine_fl=0, es_med_passes_fl=0;
    float cared=0,cablue=0;
    float linenoise=0; 
    float lclean=0,cclean=0;
    float thresh=0;
    float preser=0;
    float expos=1.0;


    CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);
//    CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE);

    try {

        int no_crop = 1;

        if (~O.cropbox[2] && ~O.cropbox[3])
            no_crop=0;

        raw2image_ex(); // raw2image+crop+rotate_fuji_raw + subtract_black for fuji

        int save_4color = O.four_color_rgb;

        if (IO.zero_is_bad) 
            {
                remove_zeroes();
                SET_PROC_FLAG(LIBRAW_PROGRESS_REMOVE_ZEROES);
            }

        if(!IO.fuji_width) // PhaseOne only, all other cases handled at raw2image_ex()
            subtract_black();

        if(O.half_size) 
            O.four_color_rgb = 1;

        if(O.bad_pixels && no_crop) 
            {
                bad_pixels(O.bad_pixels);
                SET_PROC_FLAG(LIBRAW_PROGRESS_BAD_PIXELS);
            }

        if (O.dark_frame && no_crop)
            {
                subtract (O.dark_frame);
                SET_PROC_FLAG(LIBRAW_PROGRESS_DARK_FRAME);
            }


        quality = 2 + !IO.fuji_width;

        if (O.user_qual >= 0) quality = O.user_qual;

        adjust_maximum();

        if (O.user_sat > 0) C.maximum = O.user_sat;

        if (P1.is_foveon && !O.document_mode) 
            {
                foveon_interpolate();
                SET_PROC_FLAG(LIBRAW_PROGRESS_FOVEON_INTERPOLATE);
            }

        if (O.green_matching && !O.half_size)
            {
                green_matching();
            }

        if (!P1.is_foveon &&  O.document_mode < 2)
            {
                scale_colors();
                SET_PROC_FLAG(LIBRAW_PROGRESS_SCALE_COLORS);
            }

        pre_interpolate();

        SET_PROC_FLAG(LIBRAW_PROGRESS_PRE_INTERPOLATE);

        if (O.dcb_iterations >= 0) iterations = O.dcb_iterations;
        if (O.dcb_enhance_fl >=0 ) dcb_enhance = O.dcb_enhance_fl;
        if (O.fbdd_noiserd >=0 ) noiserd = O.fbdd_noiserd;
        if (O.eeci_refine >=0 ) eeci_refine_fl = O.eeci_refine;
        if (O.es_med_passes >0 ) es_med_passes_fl = O.es_med_passes;

// LIBRAW_DEMOSAIC_PACK_GPL3

        if (!O.half_size && O.cfa_green >0) {thresh=O.green_thresh ;green_equilibrate(thresh);} 
        if (O.exp_correc >0) {expos=O.exp_shift ; preser=O.exp_preser; exp_bef(expos,preser);} 
        if (O.ca_correc >0 ) {cablue=O.cablue; cared=O.cared; CA_correct_RT(cablue, cared);}
        if (O.cfaline >0 ) {linenoise=O.linenoise; cfa_linedn(linenoise);}
        if (O.cfa_clean >0 ) {lclean=O.lclean; cclean=O.cclean; cfa_impulse_gauss(lclean,cclean);}

        if (P1.filters && !O.document_mode) 
            {
                if (noiserd>0 && P1.colors==3 && P1.filters) fbdd(noiserd);

                if (quality == 0)
                    lin_interpolate();
                else if (quality == 1 || P1.colors > 3)
                    vng_interpolate();
                else if (quality == 2)
                    ppg_interpolate();

                else if (quality == 3) 
                    ahd_interpolate(); // really don't need it here due to fallback op

                else if (quality == 4)
                    dcb(iterations, dcb_enhance);

//  LIBRAW_DEMOSAIC_PACK_GPL2                
                else if (quality == 5)
                    ahd_interpolate_mod();
                else if (quality == 6)
                    afd_interpolate_pl(2,1);
                else if (quality == 7)
                    vcd_interpolate(0);
                else if (quality == 8)
                    vcd_interpolate(12);
                else if (quality == 9)
                    lmmse_interpolate(1);

// LIBRAW_DEMOSAIC_PACK_GPL3
                else if (quality == 10)
                    amaze_demosaic_RT();
 // fallback to AHD
                else
                    ahd_interpolate();
                
                SET_PROC_FLAG(LIBRAW_PROGRESS_INTERPOLATE);
            }
        if (IO.mix_green)
            {
                for (P1.colors=3, i=0; i < S.height * S.width; i++)
                    imgdata.image[i][1] = (imgdata.image[i][1] + imgdata.image[i][3]) >> 1;
                SET_PROC_FLAG(LIBRAW_PROGRESS_MIX_GREEN);
            }

        if(!P1.is_foveon)
            {
                if (P1.colors == 3) 
                    {
                        
                        if (quality == 8) 
                            {
                                if (eeci_refine_fl == 1) refinement();
                                if (O.med_passes > 0)    median_filter_new();
                                if (es_med_passes_fl > 0) es_median_filter();
                            } 
                        else {
                            median_filter();
                        }
                        SET_PROC_FLAG(LIBRAW_PROGRESS_MEDIAN_FILTER);
                    }
            }
        
        if (O.highlight == 2) 
            {
                blend_highlights();
                SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS);
            }
        
        if (O.highlight > 2) 
            {
                recover_highlights();
                SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS);
            }
        
        if (O.use_fuji_rotate) 
            {
                fuji_rotate();
                SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE);
            }
    
        if(!libraw_internal_data.output_data.histogram)
            {
                libraw_internal_data.output_data.histogram = (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4);
                merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_process()");
            }
#ifndef NO_LCMS
	if(O.camera_profile)
            {
                apply_profile(O.camera_profile,O.output_profile);
                SET_PROC_FLAG(LIBRAW_PROGRESS_APPLY_PROFILE);
            }
#endif

        convert_to_rgb();
        SET_PROC_FLAG(LIBRAW_PROGRESS_CONVERT_RGB);

        if (O.use_fuji_rotate) 
            {
                stretch();
                SET_PROC_FLAG(LIBRAW_PROGRESS_STRETCH);
            }
        O.four_color_rgb = save_4color; // also, restore

        return 0;
    }
    catch ( LibRaw_exceptions err) {
        EXCEPTION_HANDLER(err);
    }
}

Project: LibRaw
File: libraw_cxx.cpp

void* LibRaw::       calloc(size_t n,size_t t)
{
    void *p = memmgr.calloc(n,t);
    return p;
}

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw::raw2image(void)
{

    CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);

    try {
        raw2image_start();

        // free and re-allocate image bitmap
        if(imgdata.image)
            {
                imgdata.image = (ushort (*)[4]) realloc (imgdata.image,S.iheight*S.iwidth *sizeof (*imgdata.image));
                memset(imgdata.image,0,S.iheight*S.iwidth *sizeof (*imgdata.image));
            }
        else
            imgdata.image = (ushort (*)[4]) calloc (S.iheight*S.iwidth, sizeof (*imgdata.image));

        merror (imgdata.image, "raw2image()");

        libraw_decoder_info_t decoder_info;
        get_decoder_info(&decoder_info);
        
        // Move saved bitmap to imgdata.image
        if(decoder_info.decoder_flags & LIBRAW_DECODER_FLATFIELD)
            {
                if(decoder_info.decoder_flags & LIBRAW_DECODER_USEBAYER2)
                    {
                        for(int row = 0; row < S.height; row++)
                            for(int col = 0; col < S.width; col++)
                                imgdata.image[(row >> IO.shrink)*S.iwidth + (col>>IO.shrink)][fc(row,col)]
                                = imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_width
                                                                           +(col+S.left_margin)];
                    }
                else
                    {
                        for(int row = 0; row < S.height; row++)
                            {
                                int colors[4];
                                for (int xx=0;xx<4;xx++)
                                    colors[xx] = COLOR(row,xx);
                                for(int col = 0; col < S.width; col++)
                                    {
                                        int cc = colors[col&3];
                                        imgdata.image[(row >> IO.shrink)*S.iwidth + (col>>IO.shrink)][cc] =
                                            imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_width+(col
                                                                                                      +S.left_margin)];
                                    }
                            }
                    }
            }
        else if (decoder_info.decoder_flags & LIBRAW_DECODER_4COMPONENT)
            {
                if(IO.shrink)
                    {
                        for(int row = 0; row < S.height; row++)
                            for(int col = 0; col < S.width; col++)
                                {
                                    int cc = FC(row,col);
                                    imgdata.image[(row >> IO.shrink)*S.iwidth + (col>>IO.shrink)][cc] 
                                        = imgdata.rawdata.color_image[(row+S.top_margin)*S.raw_width
                                                                      +S.left_margin+col][cc];
                                }
                    }
                else
                    for(int row = 0; row < S.height; row++)
                        memmove(&imgdata.image[row*S.width],
                                &imgdata.rawdata.color_image[(row+S.top_margin)*S.raw_width+S.left_margin],
                                S.width*sizeof(*imgdata.image));
            }
        else if(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY)
            {
                // legacy is always 4channel and not shrinked!
                memmove(imgdata.image,imgdata.rawdata.color_image,S.width*S.height*sizeof(*imgdata.image));
            }

        if(imgdata.rawdata.use_ph1_correct) // Phase one unpacked!
            phase_one_correct();

        // hack - clear later flags!
        imgdata.progress_flags 
            = LIBRAW_PROGRESS_START|LIBRAW_PROGRESS_OPEN
            |LIBRAW_PROGRESS_IDENTIFY|LIBRAW_PROGRESS_SIZE_ADJUST|LIBRAW_PROGRESS_LOAD_RAW;
        return 0;
    }
    catch ( LibRaw_exceptions err) {
        EXCEPTION_HANDLER(err);
    }
}

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw::raw2image_ex(void)
{
    CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);

    raw2image_start();

    // process cropping
    int do_crop = 0;
    unsigned save_filters = imgdata.idata.filters;
    unsigned save_width = S.width;
    if (~O.cropbox[2] && ~O.cropbox[3])
        {
            int crop[4],c,filt;
            for(int c=0;c<4;c++) 
                {
                    crop[c] = O.cropbox[c];
                    if(crop[c]<0)
                        crop[c]=0;
                }
            if(IO.fwidth) 
                {
                    crop[0] = (crop[0]/4)*4;
                    crop[1] = (crop[1]/4)*4;
                }
            do_crop = 1;
            crop[2] = MIN (crop[2], (signed) S.width-crop[0]);
            crop[3] = MIN (crop[3], (signed) S.height-crop[1]);
            if (crop[2] <= 0 || crop[3] <= 0)
                throw LIBRAW_EXCEPTION_BAD_CROP;
            
            // adjust sizes!
            S.left_margin+=crop[0];
            S.top_margin+=crop[1];
            S.width=crop[2];
            S.height=crop[3];
            
            S.iheight = (S.height + IO.shrink) >> IO.shrink;
            S.iwidth  = (S.width  + IO.shrink) >> IO.shrink;
            if(!IO.fwidth && imgdata.idata.filters)
                {
                    for (filt=c=0; c < 16; c++)
                        filt |= FC((c >> 1)+(crop[1]),
                                   (c &  1)+(crop[0])) << c*2;
                    imgdata.idata.filters = filt;
                }
        }

    if(IO.fwidth) 
        {
            ushort fiwidth,fiheight;
            if(do_crop)
                {
                    IO.fuji_width = S.width >> !libraw_internal_data.unpacker_data.fuji_layout;
                    IO.fwidth = (S.height >> libraw_internal_data.unpacker_data.fuji_layout) + IO.fuji_width;
                    IO.fheight = IO.fwidth - 1;
                }

            fiheight = (IO.fheight + IO.shrink) >> IO.shrink;
            fiwidth = (IO.fwidth + IO.shrink) >> IO.shrink;
            if(imgdata.image)
                    {
                        imgdata.image = (ushort (*)[4])realloc(imgdata.image,fiheight*fiwidth*sizeof (*imgdata.image));
                        memset(imgdata.image,0,fiheight*fiwidth *sizeof (*imgdata.image));
                    }
                else
                    imgdata.image = (ushort (*)[4]) calloc (fiheight*fiwidth, sizeof (*imgdata.image));
            merror (imgdata.image, "raw2image_ex()");

            int cblk[4],i;
            for(i=0;i<4;i++)
                cblk[i] = C.cblack[i]+C.black;
            ZERO(C.channel_maximum);

            int row,col;
            for(row=0;row<S.height;row++)
                {
                    for(col=0;col<S.width;col++)
                        {
                            int r,c;
                            if (libraw_internal_data.unpacker_data.fuji_layout) {
                                r = IO.fuji_width - 1 - col + (row >> 1);
                                c = col + ((row+1) >> 1);
                            } else {
                                r = IO.fuji_width - 1 + row - (col >> 1);
                                c = row + ((col+1) >> 1);
                            }
                            
                            int val = imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_width
                                                            +(col+S.left_margin)];
                            int cc = FCF(row,col);
                            if(val > cblk[cc])
                                val -= cblk[cc];
                            else
                                val = 0;
                            imgdata.image[((r) >> IO.shrink)*fiwidth + ((c) >> IO.shrink)][cc] = val;
                            if(C.channel_maximum[cc] < val) C.channel_maximum[cc] = val;
                        }
                }
            C.maximum -= C.black;
            ZERO(C.cblack);
            C.black = 0;

            // restore fuji sizes!
            S.height = IO.fheight;
            S.width = IO.fwidth;
            S.iheight = (S.height + IO.shrink) >> IO.shrink;
            S.iwidth  = (S.width  + IO.shrink) >> IO.shrink;
            S.raw_height -= 2*S.top_margin;
        }
    else
        {

                if(imgdata.image)
                    {
                        imgdata.image = (ushort (*)[4]) realloc (imgdata.image,S.iheight*S.iwidth 
                                                                 *sizeof (*imgdata.image));
                        memset(imgdata.image,0,S.iheight*S.iwidth *sizeof (*imgdata.image));
                    }
                else
                    imgdata.image = (ushort (*)[4]) calloc (S.iheight*S.iwidth, sizeof (*imgdata.image));

                merror (imgdata.image, "raw2image_ex()");
                
                libraw_decoder_info_t decoder_info;
                get_decoder_info(&decoder_info);


                if(decoder_info.decoder_flags & LIBRAW_DECODER_FLATFIELD)
                    {
                        if(decoder_info.decoder_flags & LIBRAW_DECODER_USEBAYER2)
#if defined(LIBRAW_USE_OPENMP)
#pragma omp parallel for default(shared)
#endif
                            for(int row = 0; row < S.height; row++)
                                for(int col = 0; col < S.width; col++)
                                    imgdata.image[(row >> IO.shrink)*S.iwidth + (col>>IO.shrink)][fc(row,col)]
                                        = imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_width
                                                                    +(col+S.left_margin)];
                        else
#if defined(LIBRAW_USE_OPENMP)
#pragma omp parallel for default(shared)
#endif
                            for(int row = 0; row < S.height; row++)
                                {
                                    int colors[2];
                                    for (int xx=0;xx<2;xx++)
                                        colors[xx] = COLOR(row,xx);
                                    for(int col = 0; col < S.width; col++)
                                        {
                                            int cc = colors[col&1];
                                            imgdata.image[(row >> IO.shrink)*S.iwidth + (col>>IO.shrink)][cc] =
                                                imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_width
                                                                          +(col+S.left_margin)];
                                        }
                                }
                    }
                else if (decoder_info.decoder_flags & LIBRAW_DECODER_4COMPONENT)
                    {
#define FC0(row,col) (save_filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)
                        if(IO.shrink)
#if defined(LIBRAW_USE_OPENMP)
#pragma omp parallel for default(shared)
#endif
                            for(int row = 0; row < S.height; row++)
                                for(int col = 0; col < S.width; col++)
                                    imgdata.image[(row >> IO.shrink)*S.iwidth + (col>>IO.shrink)][FC(row,col)] 
                                        = imgdata.rawdata.color_image[(row+S.top_margin)*S.raw_width
                                                                      +S.left_margin+col]
                                        [FC0(row+S.top_margin,col+S.left_margin)];
#undef FC0
                        else
#if defined(LIBRAW_USE_OPENMP)
#pragma omp parallel for default(shared)
#endif
                            for(int row = 0; row < S.height; row++)
                                memmove(&imgdata.image[row*S.width],
                                        &imgdata.rawdata.color_image[(row+S.top_margin)*S.raw_width+S.left_margin],
                                        S.width*sizeof(*imgdata.image));
                    }
                else if(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY)
                    {
                        if(do_crop)
#if defined(LIBRAW_USE_OPENMP)
#pragma omp parallel for default(shared)
#endif
                            for(int row = 0; row < S.height; row++)
                                memmove(&imgdata.image[row*S.width],
                                        &imgdata.rawdata.color_image[(row+S.top_margin)*save_width+S.left_margin],
                                        S.width*sizeof(*imgdata.image));
                                
                        else 
                            memmove(imgdata.image,imgdata.rawdata.color_image,
                                    S.width*S.height*sizeof(*imgdata.image));
                    }

                if(imgdata.rawdata.use_ph1_correct) // Phase one unpacked!
                        phase_one_correct();
            }
    return LIBRAW_SUCCESS;
}

Project: LibRaw
File: libraw_cxx.cpp

void LibRaw::subtract_black()
{

#define BAYERC(row,col,c) imgdata.image[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][c] 

    if(C.ph1_black)
        {
            // Phase One compressed format
            int row,col,val,cc;
            for(row=0;row<S.height;row++)
                for(col=0;col<S.width;col++)
                    {
                        cc=FC(row,col);
                        val = BAYERC(row,col,cc) 
                            - C.phase_one_data.t_black 
                            + C.ph1_black[row+S.top_margin][(col + S.left_margin) 
                                                                                >=C.phase_one_data.split_col];
                        if(val<0) val = 0;
                        BAYERC(row,col,cc) = val;
                    }
            C.maximum -= C.black;
            phase_one_correct();
            // recalculate channel maximum
            ZERO(C.channel_maximum);
            for(row=0;row<S.height;row++)
                for(col=0;col<S.width;col++)
                    {
                        cc=FC(row,col);
                        val = BAYERC(row,col,cc);
                        if(C.channel_maximum[cc] > val) C.channel_maximum[cc] = val;
                    }
            // clear P1 black level data
            imgdata.color.phase_one_data.t_black = 0;
            C.ph1_black = 0;
            ZERO(C.cblack);
            C.black = 0;
        }
    else if((C.black || C.cblack[0] || C.cblack[1] || C.cblack[2] || C.cblack[3]))
        {
            int cblk[4],i,row,col,val,cc;
            for(i=0;i<4;i++)
                cblk[i] = C.cblack[i]+C.black;
            ZERO(C.channel_maximum);

            for(row=0;row<S.height;row++)
                for(col=0;col<S.width;col++)
                    {
                        cc=COLOR(row,col);
                        val = BAYERC(row,col,cc);
                        if(val > cblk[cc])
                            val -= cblk[cc];
                        else
                            val = 0;
                        if(C.channel_maximum[cc] < val) C.channel_maximum[cc] = val;
                        BAYERC(row,col,cc) = val;
                    }
            C.maximum -= C.black;
            ZERO(C.cblack);
            C.black = 0;
        }
    else
        {
            // only calculate channel maximum;
            int row,col,cc,val;
            ZERO(C.channel_maximum);
            for(row=0;row<S.height;row++)
                for(col=0;col<S.width;col++)
                    for(cc = 0; cc< 4; cc++)
                        {
                            int val = BAYERC(row,col,cc);
                            if(C.channel_maximum[cc] < val) C.channel_maximum[cc] = val;
                        }
            
        }
}

Project: LibRaw
File: libraw_cxx.cpp

void LibRaw::kodak_thumb_loader()
{
    // some kodak cameras
    ushort s_height = S.height, s_width = S.width,s_iwidth = S.iwidth,s_iheight=S.iheight;
    int s_colors = P1.colors;
    unsigned s_filters = P1.filters;
    ushort (*s_image)[4] = imgdata.image;

    
    S.height = T.theight;
    S.width  = T.twidth;
    P1.filters = 0;

    if (thumb_load_raw == &CLASS kodak_ycbcr_load_thumb) 
        {
            S.height += S.height & 1;
            S.width  += S.width  & 1;
        }
    
    imgdata.image = (ushort (*)[4]) calloc (S.iheight*S.iwidth, sizeof (*imgdata.image));
    merror (imgdata.image, "LibRaw::kodak_thumb_loader()");

    ID.input->seek(ID.toffset, SEEK_SET);
    // read kodak thumbnail into T.image[]
    (this->*thumb_load_raw)();

    // copy-n-paste from image pipe
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define LIM(x,min,max) MAX(min,MIN(x,max))
#define CLIP(x) LIM(x,0,65535)
#define SWAP(a,b) { a ^= b; a ^= (b ^= a); }

    // from scale_colors
    {
        double   dmax;
        float scale_mul[4];
        int c,val;
        for (dmax=DBL_MAX, c=0; c < 3; c++) 
                if (dmax > C.pre_mul[c])
                    dmax = C.pre_mul[c];

        for( c=0; c< 3; c++)
                scale_mul[c] = (C.pre_mul[c] / dmax) * 65535.0 / C.maximum;
        scale_mul[3] = scale_mul[1];

        size_t size = S.height * S.width;
        for (unsigned i=0; i < size*4 ; i++) 
            {
                val = imgdata.image[0][i];
                if(!val) continue;
                val *= scale_mul[i & 3];
                imgdata.image[0][i] = CLIP(val);
            }
    }

    // from convert_to_rgb
    ushort *img;
    int row,col;
    
    int  (*t_hist)[LIBRAW_HISTOGRAM_SIZE] =  (int (*)[LIBRAW_HISTOGRAM_SIZE]) calloc(sizeof(*t_hist),4);
    merror (t_hist, "LibRaw::kodak_thumb_loader()");
    
    float out[3], 
        out_cam[3][4] = 
        {
            {2.81761312, -1.98369181, 0.166078627, 0}, 
            {-0.111855984, 1.73688626, -0.625030339, 0}, 
            {-0.0379119813, -0.891268849, 1.92918086, 0}
        };

    for (img=imgdata.image[0], row=0; row < S.height; row++)
        for (col=0; col < S.width; col++, img+=4)
            {
                out[0] = out[1] = out[2] = 0;
                int c;
                for(c=0;c<3;c++) 
                    {
                        out[0] += out_cam[0][c] * img[c];
                        out[1] += out_cam[1][c] * img[c];
                        out[2] += out_cam[2][c] * img[c];
                    }
                for(c=0; c<3; c++)
                    img[c] = CLIP((int) out[c]);
                for(c=0; c<P1.colors;c++)
                    t_hist[c][img[c] >> 3]++;
                    
            }

    // from gamma_lut
    int  (*save_hist)[LIBRAW_HISTOGRAM_SIZE] = libraw_internal_data.output_data.histogram;
    libraw_internal_data.output_data.histogram = t_hist;

    // make curve output curve!
    ushort (*t_curve) = (ushort*) calloc(sizeof(C.curve),1);
    merror (t_curve, "LibRaw::kodak_thumb_loader()");
    memmove(t_curve,C.curve,sizeof(C.curve));
    memset(C.curve,0,sizeof(C.curve));
        {
            int perc, val, total, t_white=0x2000,c;

            perc = S.width * S.height * 0.01;		/* 99th percentile white level */
            if (IO.fuji_width) perc /= 2;
            if (!((O.highlight & ~2) || O.no_auto_bright))
                for (t_white=c=0; c < P1.colors; c++) {
                    for (val=0x2000, total=0; --val > 32; )
                        if ((total += libraw_internal_data.output_data.histogram[c][val]) > perc) break;
                    if (t_white < val) t_white = val;
                }
            gamma_curve (O.gamm[0], O.gamm[1], 2, (t_white << 3)/O.bright);
        }
    
    libraw_internal_data.output_data.histogram = save_hist;
    free(t_hist);
    
    // from write_ppm_tiff - copy pixels into bitmap
    
    S.iheight = S.height;
    S.iwidth  = S.width;
    if (S.flip & 4) SWAP(S.height,S.width);

    if(T.thumb) free(T.thumb);
    T.thumb = (char*) calloc (S.width * S.height, P1.colors);
    merror (T.thumb, "LibRaw::kodak_thumb_loader()");
    T.tlength = S.width * S.height * P1.colors;

    // from write_tiff_ppm
    {
        int soff  = flip_index (0, 0);
        int cstep = flip_index (0, 1) - soff;
        int rstep = flip_index (1, 0) - flip_index (0, S.width);
        
        for (int row=0; row < S.height; row++, soff += rstep) 
            {
                char *ppm = T.thumb + row*S.width*P1.colors;
                for (int col=0; col < S.width; col++, soff += cstep)
                    for(int c = 0; c < P1.colors; c++)
                        ppm [col*P1.colors+c] = imgdata.color.curve[imgdata.image[soff][c]]>>8;
            }
    }

    memmove(C.curve,t_curve,sizeof(C.curve));
    free(t_curve);

    // restore variables
    free(imgdata.image);
    imgdata.image  = s_image;
    
    T.twidth = S.width;
    S.width = s_width;

    S.iwidth = s_iwidth;
    S.iheight = s_iheight;

    T.theight = S.height;
    S.height = s_height;

    T.tcolors = P1.colors;
    P1.colors = s_colors;

    P1.filters = s_filters;
}

Project: LibRaw
File: libraw_cxx.cpp

void* LibRaw:: malloc(size_t t)
{
    void *p = memmgr.malloc(t);
    return p;
}

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw::dcraw_document_mode_processing(void)
{
//    CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE);
    CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);

    try {

        int no_crop = 1;

        if (~O.cropbox[2] && ~O.cropbox[3])
            no_crop=0;

        raw2image_ex(); // raw2image+crop+rotate_fuji_raw

        if (IO.zero_is_bad)
            {
                remove_zeroes();
                SET_PROC_FLAG(LIBRAW_PROGRESS_REMOVE_ZEROES);
            }

        if(!IO.fuji_width)
            subtract_black();
        
        O.document_mode = 2;
        
        if(P1.is_foveon)
            {
                // filter image data for foveon document mode
                short *iptr = (short *)imgdata.image;
                for (int i=0; i < S.height*S.width*4; i++)
                    {
                        if ((short) iptr[i] < 0) 
                            iptr[i] = 0;
                    }
                SET_PROC_FLAG(LIBRAW_PROGRESS_FOVEON_INTERPOLATE);
            }

        O.use_fuji_rotate = 0;

        if(O.bad_pixels && no_crop) 
            {
                bad_pixels(O.bad_pixels);
                SET_PROC_FLAG(LIBRAW_PROGRESS_BAD_PIXELS);
            }
        if (O.dark_frame && no_crop)
            {
                subtract (O.dark_frame);
                SET_PROC_FLAG(LIBRAW_PROGRESS_DARK_FRAME);
            }


        adjust_maximum();

        if (O.user_sat > 0) 
            C.maximum = O.user_sat;

        pre_interpolate();
        SET_PROC_FLAG(LIBRAW_PROGRESS_PRE_INTERPOLATE);

        if (libraw_internal_data.internal_output_params.mix_green)
            {
                int i;
                for (P1.colors=3, i=0; i < S.height*S.width; i++)
                    imgdata.image[i][1] = (imgdata.image[i][1] + imgdata.image[i][3]) >> 1;
            }
        SET_PROC_FLAG(LIBRAW_PROGRESS_MIX_GREEN);

        if (!P1.is_foveon && P1.colors == 3) 
            median_filter();
        SET_PROC_FLAG(LIBRAW_PROGRESS_MEDIAN_FILTER);

        if (!P1.is_foveon && O.highlight == 2) 
            blend_highlights();

        if (!P1.is_foveon && O.highlight > 2) 
            recover_highlights();
        SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS);

        if (O.use_fuji_rotate) 
            fuji_rotate();
        SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE);
#ifndef NO_LCMS
	if(O.camera_profile)
            {
                apply_profile(O.camera_profile,O.output_profile);
                SET_PROC_FLAG(LIBRAW_PROGRESS_APPLY_PROFILE);
            }
#endif
        if(!libraw_internal_data.output_data.histogram)
            {
                libraw_internal_data.output_data.histogram = (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4);
                merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_document_mode_processing()");
            }
        convert_to_rgb();
        SET_PROC_FLAG(LIBRAW_PROGRESS_CONVERT_RGB);

        if (O.use_fuji_rotate)
            stretch();
        SET_PROC_FLAG(LIBRAW_PROGRESS_STRETCH);

        return 0;
    }
    catch ( LibRaw_exceptions err) {
        EXCEPTION_HANDLER(err);
    }

}

Project: LibRaw
File: libraw_cxx.cpp

    const char *libraw_strerror(int e)
    {
        enum LibRaw_errors errorcode = (LibRaw_errors)e;
        switch(errorcode)
            {
            case        LIBRAW_SUCCESS:
                return "No error";
            case        LIBRAW_UNSPECIFIED_ERROR:
                return "Unspecified error";
            case        LIBRAW_FILE_UNSUPPORTED:
                return "Unsupported file format or not RAW file";
            case        LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE:
                return "Request for nonexisting image number";
            case        LIBRAW_OUT_OF_ORDER_CALL:
                return "Out of order call of libraw function";
            case    LIBRAW_NO_THUMBNAIL:
                return "No thumbnail in file";
            case    LIBRAW_UNSUPPORTED_THUMBNAIL:
                return "Unsupported thumbnail format";
            case    LIBRAW_UNSUFFICIENT_MEMORY:
                return "Unsufficient memory";
            case    LIBRAW_DATA_ERROR:
                return "Corrupted data or unexpected EOF";
            case    LIBRAW_IO_ERROR:
                return "Input/output error";
            case LIBRAW_CANCELLED_BY_CALLBACK:
                return "Cancelled by user callback";
            case LIBRAW_BAD_CROP:
                return "Bad crop box";
            default:
                return "Unknown error code";
        }
    }

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw::adjust_maximum()
{
    int i;
    ushort real_max;
    float  auto_threshold;

    if(O.adjust_maximum_thr < 0.00001)
        return LIBRAW_SUCCESS;
    else if (O.adjust_maximum_thr > 0.99999)
        auto_threshold = LIBRAW_DEFAULT_ADJUST_MAXIMUM_THRESHOLD;
    else
        auto_threshold = O.adjust_maximum_thr;
        
    
    real_max = C.channel_maximum[0];
    for(i = 1; i< 4; i++)
        if(real_max < C.channel_maximum[i])
            real_max = C.channel_maximum[i];

    if (real_max > 0 && real_max < C.maximum && real_max > C.maximum* auto_threshold)
        {
            C.maximum = real_max;
        }
    return LIBRAW_SUCCESS;
}

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw:: fc (int row, int col)
{
    static const char filter[16][16] =
        { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 },
          { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 },
          { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 },
          { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 },
          { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 },
          { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 },
          { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 },
          { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 },
          { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 },
          { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 },
          { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 },
          { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 },
          { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 },
          { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 },
          { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 },
          { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } };
    
    if (imgdata.idata.filters != 1) return FC(row,col);
    return filter[(row+imgdata.sizes.top_margin) & 15][(col+imgdata.sizes.left_margin) & 15];
}

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw::unpack_thumb(void)
{
    CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY);
    CHECK_ORDER_BIT(LIBRAW_PROGRESS_THUMB_LOAD);

    try {
        if ( !ID.toffset) 
            {
                return LIBRAW_NO_THUMBNAIL;
            } 
        else if (thumb_load_raw) 
            {
                kodak_thumb_loader();
                T.tformat = LIBRAW_THUMBNAIL_BITMAP;
                SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD);
                return 0;
            } 
        else 
            {
                ID.input->seek(ID.toffset, SEEK_SET);
                if ( write_thumb == &LibRaw::jpeg_thumb)
                    {
                        if(T.thumb) free(T.thumb);
                        T.thumb = (char *) malloc (T.tlength);
                        merror (T.thumb, "jpeg_thumb()");
                        ID.input->read (T.thumb, 1, T.tlength);
                        T.tcolors = 3;
                        T.tformat = LIBRAW_THUMBNAIL_JPEG;
                        SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD);
                        return 0;
                    }
                else if (write_thumb == &LibRaw::ppm_thumb)
                    {
                        T.tlength = T.twidth * T.theight*3;
                        if(T.thumb) free(T.thumb);

                        T.thumb = (char *) malloc (T.tlength);
                        merror (T.thumb, "ppm_thumb()");

                        ID.input->read(T.thumb, 1, T.tlength);

                        T.tformat = LIBRAW_THUMBNAIL_BITMAP;
                        SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD);
                        return 0;

                    }
                else if (write_thumb == &LibRaw::foveon_thumb)
                    {
                        foveon_thumb_loader();
                        // may return with error, so format is set in
                        // foveon thumb loader itself
                        SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD);
                        return 0;
                    }
                // else if -- all other write_thumb cases!
                else
                    {
                        return LIBRAW_UNSUPPORTED_THUMBNAIL;
                    }
            }
        // last resort
        return LIBRAW_UNSUPPORTED_THUMBNAIL;
    }
    catch ( LibRaw_exceptions err) {
        EXCEPTION_HANDLER(err);
    }

}

Project: LibRaw
File: libraw_cxx.cpp

void LibRaw::exp_bef(float shift, float smooth)
{
    // params limits
    if(shift>8) shift = 8;
    if(shift<0.25) shift = 0.25;
    if(smooth < 0.0) smooth = 0.0;
    if(smooth > 1.0) smooth = 1.0;
    
    unsigned short *lut = (ushort*)malloc((TBLN+1)*sizeof(unsigned short));

    if(shift <=1.0)
        {
            for(int i=0;i<=TBLN;i++)
                lut[i] = (unsigned short)((float)i*shift);
        }
    else
        {
            float x1,x2,y1,y2;

            float cstops = log(shift)/log(2.0f);
            float room = cstops*2;
            float roomlin = powf(2.0f,room);
            x2 = (float)TBLN;
            x1 = (x2+1)/roomlin-1;
            y1 = x1*shift;
            y2 = x2*(1+(1-smooth)*(shift-1));
            float sq3x=powf(x1*x1*x2,1.0f/3.0f);
            float B = (y2-y1+shift*(3*x1-3.0f*sq3x)) / (x2+2.0f*x1-3.0f*sq3x);
            float A = (shift - B)*3.0f*powf(x1*x1,1.0f/3.0f);
            float CC = y2 - A*powf(x2,1.0f/3.0f)-B*x2;
            for(int i=0;i<=TBLN;i++)
                {
                    float X = (float)i;
                    float Y = A*powf(X,1.0f/3.0f)+B*X+CC;
                    if(i<x1)
                        lut[i] = (unsigned short)((float)i*shift);
                    else
                        lut[i] = Y<0?0:(Y>TBLN?TBLN:(unsigned short)(Y));
                }
        }
    for(int i=0; i< S.height*S.width; i++)
        {
            imgdata.image[i][0] = lut[imgdata.image[i][0]];
            imgdata.image[i][1] = lut[imgdata.image[i][1]];
            imgdata.image[i][2] = lut[imgdata.image[i][2]];
            imgdata.image[i][3] = lut[imgdata.image[i][3]];
        }
    for(int i=0;i<4;i++)
        C.channel_maximum[i] = lut[C.channel_maximum[i]];
    C.maximum = lut[C.maximum];
    // no need to adjust the minumum, black is already subtracted
    free(lut);
}

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw::unpack(void)
{
    CHECK_ORDER_HIGH(LIBRAW_PROGRESS_LOAD_RAW);
    CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY);
    try {

        RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW,0,2);
        if (O.shot_select >= P1.raw_count)
            return LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE;
        
        if(!load_raw)
            return LIBRAW_UNSPECIFIED_ERROR;
        
        if (O.use_camera_matrix && C.cmatrix[0][0] > 0.25) 
            {
                memcpy (C.rgb_cam, C.cmatrix, sizeof (C.cmatrix));
                IO.raw_color = 0;
            }
        // already allocated ?
        if(imgdata.image)
            {
                free(imgdata.image);
                imgdata.image = 0;
            }

        if (libraw_internal_data.unpacker_data.meta_length) 
            {
                libraw_internal_data.internal_data.meta_data = 
                    (char *) malloc (libraw_internal_data.unpacker_data.meta_length);
                merror (libraw_internal_data.internal_data.meta_data, "LibRaw::unpack()");
            }
        ID.input->seek(libraw_internal_data.unpacker_data.data_offset, SEEK_SET);
        int save_document_mode = O.document_mode;
        O.document_mode = 0;

        libraw_decoder_info_t decoder_info;
        get_decoder_info(&decoder_info);

        int save_iwidth = S.iwidth, save_iheight = S.iheight, save_shrink = IO.shrink;

        int rwidth = S.raw_width, rheight = S.raw_height;
        if( !IO.fuji_width)
            {
                // adjust non-Fuji allocation
                if(rwidth < S.width + S.left_margin)
                    rwidth = S.width + S.left_margin;
                if(rheight < S.height + S.top_margin)
                    rheight = S.height + S.top_margin;
            }
        
        if(decoder_info.decoder_flags &  LIBRAW_DECODER_FLATFIELD)
            {
                imgdata.rawdata.raw_alloc = malloc(rwidth*rheight*sizeof(imgdata.rawdata.raw_image[0]));
                imgdata.rawdata.raw_image = (ushort*) imgdata.rawdata.raw_alloc;
            }
        else if (decoder_info.decoder_flags &  LIBRAW_DECODER_4COMPONENT)
            {
                S.iwidth = S.width;
                S.iheight= S.height;
                IO.shrink = 0;
                imgdata.rawdata.raw_alloc = calloc(rwidth*rheight,sizeof(*imgdata.rawdata.color_image));
                imgdata.rawdata.color_image = (ushort(*)[4]) imgdata.rawdata.raw_alloc;
            }
        else if (decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY)
            {
                // sRAW and Foveon only, so extra buffer size is just 1/4
                // Legacy converters does not supports half mode!
                S.iwidth = S.width;
                S.iheight= S.height;
                IO.shrink = 0;
                // allocate image as temporary buffer, size 
                imgdata.rawdata.raw_alloc = 0;
                imgdata.image = (ushort (*)[4]) calloc(S.iwidth*S.iheight,sizeof(*imgdata.image));
            }


        (this->*load_raw)();


        // recover saved
        if( decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY)
            {
              imgdata.rawdata.raw_alloc = imgdata.rawdata.color_image = imgdata.image;
              imgdata.image = 0; 
            }

        // calculate channel maximum
        {
            for(int c=0;c<4;c++) C.channel_maximum[c] = 0;
            if(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY)
                {
                    for(int rc = 0; rc < S.iwidth*S.iheight; rc++)
                        {
                            if(C.channel_maximum[0]<imgdata.rawdata.color_image[rc][0]) 
                                C.channel_maximum[0]=imgdata.rawdata.color_image[rc][0];
                            if(C.channel_maximum[1]<imgdata.rawdata.color_image[rc][1]) 
                                C.channel_maximum[1]=imgdata.rawdata.color_image[rc][1];
                            if(C.channel_maximum[2]<imgdata.rawdata.color_image[rc][2]) 
                                C.channel_maximum[2]=imgdata.rawdata.color_image[rc][2];
                            if(C.channel_maximum[3]<imgdata.rawdata.color_image[rc][3]) 
                                C.channel_maximum[3]=imgdata.rawdata.color_image[rc][3];
                        }
                }
            else if(decoder_info.decoder_flags &  LIBRAW_DECODER_4COMPONENT)
                {
                    for(int row = S.top_margin; row < S.height+S.top_margin; row++)
                        for(int col = S.left_margin; col < S.width+S.left_margin; col++)
                        {
                            int rc = row*S.raw_width+col;
                            if(C.channel_maximum[0]<imgdata.rawdata.color_image[rc][0]) 
                                C.channel_maximum[0]=imgdata.rawdata.color_image[rc][0];
                            if(C.channel_maximum[1]<imgdata.rawdata.color_image[rc][1]) 
                                C.channel_maximum[1]=imgdata.rawdata.color_image[rc][1];
                            if(C.channel_maximum[2]<imgdata.rawdata.color_image[rc][2]) 
                                C.channel_maximum[2]=imgdata.rawdata.color_image[rc][2];
                            if(C.channel_maximum[3]<imgdata.rawdata.color_image[rc][3]) 
                                C.channel_maximum[3]=imgdata.rawdata.color_image[rc][4];
                        }
                }
            else if (decoder_info.decoder_flags &  LIBRAW_DECODER_FLATFIELD)
                {
                        for(int row = 0; row < S.height; row++)
                            {
                                int colors[4];
                                for (int xx=0;xx<4;xx++)
                                    colors[xx] = COLOR(row,xx);
                                for(int col = 0; col < S.width; col++)
                                    {
                                        int cc = colors[col&3];
                                        if(C.channel_maximum[cc] 
                                           < imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_width
                                                                       +(col+S.left_margin)])
                                            C.channel_maximum[cc] = 
                                                imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_width
                                                                          +(col+S.left_margin)];
                                    }
                            }
                }
        }
        // recover image sizes
        S.iwidth = save_iwidth;
        S.iheight = save_iheight;
        IO.shrink = save_shrink;

        // phase-one black
        if(imgdata.rawdata.ph1_black)
            C.ph1_black = imgdata.rawdata.ph1_black;
        O.document_mode = save_document_mode;

        // adjust black to possible maximum
        unsigned int i = C.cblack[3];
        unsigned int c;
        for(c=0;c<3;c++)
            if (i > C.cblack[c]) i = C.cblack[c];
        for (c=0;c<4;c++)
            C.cblack[c] -= i;
        C.black += i;


        // Save color,sizes and internal data into raw_image fields
        memmove(&imgdata.rawdata.color,&imgdata.color,sizeof(imgdata.color));
        memmove(&imgdata.rawdata.sizes,&imgdata.sizes,sizeof(imgdata.sizes));
        memmove(&imgdata.rawdata.iparams,&imgdata.idata,sizeof(imgdata.idata));
        memmove(&imgdata.rawdata.ioparams,&libraw_internal_data.internal_output_params,sizeof(libraw_internal_data.internal_output_params));

        SET_PROC_FLAG(LIBRAW_PROGRESS_LOAD_RAW);
        RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW,1,2);
        
        return 0;
    }
    catch ( LibRaw_exceptions err) {
        EXCEPTION_HANDLER(err);
    }
    catch (std::exception ee) {
        EXCEPTION_HANDLER(LIBRAW_EXCEPTION_IO_CORRUPT);
    }
}

Project: LibRaw
File: libraw_cxx.cpp

void* LibRaw:: realloc(void *q,size_t t)
{
    void *p = memmgr.realloc(q,t);
    return p;
}

Project: LibRaw
File: libraw_cxx.cpp

void LibRaw:: recycle() 
{
    if(libraw_internal_data.internal_data.input && libraw_internal_data.internal_data.input_internal) 
        { 
            delete libraw_internal_data.internal_data.input; 
            libraw_internal_data.internal_data.input = NULL;
        }
    libraw_internal_data.internal_data.input_internal = 0;
#define FREE(a) do { if(a) { free(a); a = NULL;} }while(0)
            
    FREE(imgdata.image); 
    FREE(imgdata.thumbnail.thumb);
    FREE(libraw_internal_data.internal_data.meta_data);
    FREE(libraw_internal_data.output_data.histogram);
    FREE(libraw_internal_data.output_data.oprof);
    FREE(imgdata.color.profile);
    FREE(imgdata.rawdata.ph1_black);
    FREE(imgdata.rawdata.raw_alloc); 
#undef FREE
    ZERO(imgdata.rawdata);
    ZERO(imgdata.sizes);
    ZERO(imgdata.color);
    ZERO(libraw_internal_data);
    memmgr.cleanup();
    imgdata.thumbnail.tformat = LIBRAW_THUMBNAIL_UNKNOWN;
    imgdata.progress_flags = 0;
    
    tls->init();
}

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw::adjust_sizes_info_only(void)
{
    CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY);

    raw2image_start();
    if (O.use_fuji_rotate)
        {
            if (IO.fuji_width) 
                {
                    // restore saved values
                    if(IO.fheight)
                        {
                            S.height = IO.fheight;
                            S.width = IO.fwidth;
                            S.iheight = (S.height + IO.shrink) >> IO.shrink;
                            S.iwidth  = (S.width  + IO.shrink) >> IO.shrink;
                            S.raw_height -= 2*S.top_margin;
                            IO.fheight = IO.fwidth = 0; // prevent repeated calls
                        }
                    // dcraw code
                    IO.fuji_width = (IO.fuji_width - 1 + IO.shrink) >> IO.shrink;
                    S.iwidth = (ushort)(IO.fuji_width / sqrt(0.5));
                    S.iheight = (ushort)( (S.iheight - IO.fuji_width) / sqrt(0.5));
                } 
            else 
                {
                    if (S.pixel_aspect < 1) S.iheight = (ushort)( S.iheight / S.pixel_aspect + 0.5);
                    if (S.pixel_aspect > 1) S.iwidth  = (ushort) (S.iwidth  * S.pixel_aspect + 0.5);
                }
        }
    SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE);
    if ( S.flip & 4)
        {
            unsigned short t = S.iheight;
            S.iheight=S.iwidth;
            S.iwidth = t;
            SET_PROC_FLAG(LIBRAW_PROGRESS_FLIP);
        }
    return 0;
}

Project: LibRaw
File: libraw_cxx.cpp

LibRaw:: LibRaw(unsigned int flags)
{
    double aber[4] = {1,1,1,1};
    double gamm[6] = { 0.45,4.5,0,0,0,0 };
    unsigned greybox[4] =  { 0, 0, UINT_MAX, UINT_MAX };
    unsigned cropbox[4] =  { 0, 0, UINT_MAX, UINT_MAX };
#ifdef DCRAW_VERBOSE
    verbose = 1;
#else
    verbose = 0;
#endif
    ZERO(imgdata);
    ZERO(libraw_internal_data);
    ZERO(callbacks);
    callbacks.mem_cb = (flags & LIBRAW_OPIONS_NO_MEMERR_CALLBACK) ? NULL:  &default_memory_callback;
    callbacks.data_cb = (flags & LIBRAW_OPIONS_NO_DATAERR_CALLBACK)? NULL : &default_data_callback;
    memmove(&imgdata.params.aber,&aber,sizeof(aber));
    memmove(&imgdata.params.gamm,&gamm,sizeof(gamm));
    memmove(&imgdata.params.greybox,&greybox,sizeof(greybox));
    memmove(&imgdata.params.cropbox,&cropbox,sizeof(cropbox));
    
    imgdata.params.bright=1;
    imgdata.params.use_camera_matrix=-1;
    imgdata.params.user_flip=-1;
    imgdata.params.user_black=-1;
    imgdata.params.user_sat=-1;
    imgdata.params.user_qual=-1;
    imgdata.params.output_color=1;
    imgdata.params.output_bps=8;
    imgdata.params.use_fuji_rotate=1;
    imgdata.params.exp_shift = 1.0;
    imgdata.params.auto_bright_thr = LIBRAW_DEFAULT_AUTO_BRIGHTNESS_THRESHOLD;
    imgdata.params.adjust_maximum_thr= LIBRAW_DEFAULT_ADJUST_MAXIMUM_THRESHOLD;
    imgdata.params.green_matching = 0;
    imgdata.parent_class = this;
    imgdata.progress_flags = 0;
    tls = new LibRaw_TLS;
    tls->init();
}

Project: LibRaw
File: libraw_cxx.cpp

void LibRaw::raw2image_start()
{
        // restore color,sizes and internal data into raw_image fields
        memmove(&imgdata.color,&imgdata.rawdata.color,sizeof(imgdata.color));
        memmove(&imgdata.sizes,&imgdata.rawdata.sizes,sizeof(imgdata.sizes));
        memmove(&imgdata.idata,&imgdata.rawdata.iparams,sizeof(imgdata.idata));
        memmove(&libraw_internal_data.internal_output_params,&imgdata.rawdata.ioparams,sizeof(libraw_internal_data.internal_output_params));

        if (O.user_flip >= 0)
            S.flip = O.user_flip;
        
        switch ((S.flip+3600) % 360) 
            {
            case 270:  S.flip = 5;  break;
            case 180:  S.flip = 3;  break;
            case  90:  S.flip = 6;  break;
            }

        // adjust for half mode!
        IO.shrink = P1.filters && (O.half_size ||
                                   ((O.threshold || O.aber[0] != 1 || O.aber[2] != 1) ));
        
        S.iheight = (S.height + IO.shrink) >> IO.shrink;
        S.iwidth  = (S.width  + IO.shrink) >> IO.shrink;

        if (O.user_black >= 0) 
            C.black = O.user_black;
}

Project: LibRaw
File: libraw_cxx.cpp

int LibRaw::open_datastream(LibRaw_abstract_datastream *stream)
{

    if(!stream)
        return ENOENT;
    if(!stream->valid())
        return LIBRAW_IO_ERROR;
    recycle();

    try {
        ID.input = stream;
        SET_PROC_FLAG(LIBRAW_PROGRESS_OPEN);

        if (O.use_camera_matrix < 0)
            O.use_camera_matrix = O.use_camera_wb;

        identify();

        if(IO.fuji_width)
            {
                IO.fwidth = S.width;
                IO.fheight = S.height;
                S.iwidth = S.width = IO.fuji_width << (int)(!libraw_internal_data.unpacker_data.fuji_layout);
                S.iheight = S.height = S.raw_height;
                S.raw_height += 2*S.top_margin;
            }

        if(C.profile_length)
            {
                if(C.profile) free(C.profile);
                C.profile = malloc(C.profile_length);
                merror(C.profile,"LibRaw::open_file()");
                ID.input->seek(ID.profile_offset,SEEK_SET);
                ID.input->read(C.profile,C.profile_length,1);
            }
        
        SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY);
    }
    catch ( LibRaw_exceptions err) {
        EXCEPTION_HANDLER(err);
    }
    catch (std::exception ee) {
        EXCEPTION_HANDLER(LIBRAW_EXCEPTION_IO_CORRUPT);
    }

    if(P1.raw_count < 1) 
        return LIBRAW_FILE_UNSUPPORTED;

    
    write_fun = &LibRaw::write_ppm_tiff;
    
    if (load_raw == &LibRaw::kodak_ycbcr_load_raw) 
        {
            S.height += S.height & 1;
            S.width  += S.width  & 1;
        }

    IO.shrink = P1.filters && (O.half_size ||
	((O.threshold || O.aber[0] != 1 || O.aber[2] != 1) ));

    S.iheight = (S.height + IO.shrink) >> IO.shrink;
    S.iwidth  = (S.width  + IO.shrink) >> IO.shrink;

    // Save color,sizes and internal data into raw_image fields
    memmove(&imgdata.rawdata.color,&imgdata.color,sizeof(imgdata.color));
    memmove(&imgdata.rawdata.sizes,&imgdata.sizes,sizeof(imgdata.sizes));
    memmove(&imgdata.rawdata.iparams,&imgdata.idata,sizeof(imgdata.idata));
    memmove(&imgdata.rawdata.ioparams,&libraw_internal_data.internal_output_params,sizeof(libraw_internal_data.internal_output_params));
    
    SET_PROC_FLAG(LIBRAW_PROGRESS_SIZE_ADJUST);


    return LIBRAW_SUCCESS;
}