From 9587f22834fd71d2137815776a4dd706ab98bf68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 2 May 2020 19:16:26 +0200 Subject: [PATCH] Add bug hunting test case for CVE-2019-19888 --- test/bug-hunting/cve/CVE-2019-19888/jfif.c | 862 +++++++++++++++++++++ 1 file changed, 862 insertions(+) create mode 100644 test/bug-hunting/cve/CVE-2019-19888/jfif.c diff --git a/test/bug-hunting/cve/CVE-2019-19888/jfif.c b/test/bug-hunting/cve/CVE-2019-19888/jfif.c new file mode 100644 index 000000000..8476ff5e6 --- /dev/null +++ b/test/bug-hunting/cve/CVE-2019-19888/jfif.c @@ -0,0 +1,862 @@ +/* 包含头文件 */ +#include +#include +#include +#include "stdefine.h" +#include "bitstr.h" +#include "huffman.h" +#include "quant.h" +#include "zigzag.h" +#include "dct.h" +#include "bmp.h" +#include "color.h" +#include "jfif.h" + +// 预编译开关 +#define DEBUG_JFIF 0 + +// 内部类型定义 +typedef struct { + // width & height + int width; + int height; + + // quantization table + int *pqtab[16]; + + // huffman codec ac + HUFCODEC *phcac[16]; + + // huffman codec dc + HUFCODEC *phcdc[16]; + + // components + int comp_num; + struct { + int id; + int samp_factor_v; + int samp_factor_h; + int qtab_idx; + int htab_idx_ac; + int htab_idx_dc; + } comp_info[4]; + + int datalen; + BYTE *databuf; +} JFIF; + +/* 内部函数实现 */ +#if DEBUG_JFIF +static void jfif_dump(JFIF *jfif) +{ + int i, j; + + printf("++ jfif dump ++\n"); + printf("width : %d\n", jfif->width ); + printf("height: %d\n", jfif->height); + printf("\n"); + + for (i=0; i<16; i++) { + if (!jfif->pqtab[i]) continue; + printf("qtab%d\n", i); + for (j=0; j<64; j++) { + printf("%3d,%c", jfif->pqtab[i][j], j%8 == 7 ? '\n' : ' '); + } + printf("\n"); + } + + for (i=0; i<16; i++) { + int size = 16; + if (!jfif->phcac[i]) continue; + printf("htabac%d\n", i); + for (j=0; j<16; j++) { + size += jfif->phcac[i]->huftab[j]; + } + for (j=0; jphcac[i]->huftab[j], j%16 == 15 ? '\n' : ' '); + } + printf("\n\n"); + } + + for (i=0; i<16; i++) { + int size = 16; + if (!jfif->phcdc[i]) continue; + printf("htabdc%d\n", i); + for (j=0; j<16; j++) { + size += jfif->phcdc[i]->huftab[j]; + } + for (j=0; jphcdc[i]->huftab[j], j%16 == 15 ? '\n' : ' '); + } + printf("\n\n"); + } + + printf("comp_num : %d\n", jfif->comp_num); + for (i=0; icomp_num; i++) { + printf("id:%d samp_factor_v:%d samp_factor_h:%d qtab_idx:%d htab_idx_ac:%d htab_idx_dc:%d\n", + jfif->comp_info[i].id, + jfif->comp_info[i].samp_factor_v, + jfif->comp_info[i].samp_factor_h, + jfif->comp_info[i].qtab_idx, + jfif->comp_info[i].htab_idx_ac, + jfif->comp_info[i].htab_idx_dc); + } + printf("\n"); + + printf("datalen : %d\n", jfif->datalen); + printf("-- jfif dump --\n"); +} + +static void dump_du(int *du) +{ + int i; + for (i=0; i<64; i++) { + printf("%3d%c", du[i], i % 8 == 7 ? '\n' : ' '); + } + printf("\n"); +} +#endif + +static int ALIGN(int x, int y) { + // y must be a power of 2. + return (x + y - 1) & ~(y - 1); +} + +static void category_encode(int *code, int *size) +{ + unsigned absc = abs(*code); + unsigned mask = (1 << 15); + int i = 15; + if (absc == 0) { *size = 0; return; } + while (i && !(absc & mask)) { mask >>= 1; i--; } + *size = i + 1; + if (*code < 0) *code = (1 << *size) - absc - 1; +} + +static int category_decode(int code, int size) +{ + return code >= (1 << (size - 1)) ? code : code - (1 << size) + 1; +} + +/* 函数实现 */ +void* jfif_load(char *file) +{ + JFIF *jfif = NULL; + FILE *fp = NULL; + int header = 0; + int type = 0; + WORD size = 0; + BYTE *buf = NULL; + BYTE *end = NULL; + BYTE *dqt, *dht; + int ret =-1; + long offset = 0; + int i; + + jfif = calloc(1, sizeof(JFIF)); + buf = calloc(1, 0x10000); + end = buf + 0x10000; + if (!jfif || !buf) goto done; + + fp = fopen(file, "rb"); + if (!fp) goto done; + + while (1) { + do { header = fgetc(fp); } while (header != EOF && header != 0xff); // get header + do { type = fgetc(fp); } while (type != EOF && type == 0xff); // get type + if (header == EOF || type == EOF) { + printf("file eof !\n"); + break; + } + + if ((type == 0xd8) || (type == 0xd9) || (type == 0x01) || (type >= 0xd0 && type <= 0xd7)) { + size = 0; + } else { + size = fgetc(fp) << 8; + size |= fgetc(fp) << 0; + size -= 2; + } + + size = fread(buf, 1, size, fp); + switch (type) { + case 0xc0: // SOF0 + jfif->width = (buf[3] << 8) | (buf[4] << 0); + jfif->height = (buf[1] << 8) | (buf[2] << 0); + jfif->comp_num = buf[5] < 4 ? buf[5] : 4; + for (i=0; icomp_num; i++) { + jfif->comp_info[i].id = buf[6 + i * 3]; + jfif->comp_info[i].samp_factor_v = (buf[7 + i * 3] >> 0) & 0x0f; + jfif->comp_info[i].samp_factor_h = (buf[7 + i * 3] >> 4) & 0x0f; + jfif->comp_info[i].qtab_idx = buf[8 + i * 3] & 0x0f; + } + break; + + case 0xda: // SOS + jfif->comp_num = buf[0] < 4 ? buf[0] : 4; + for (i=0; icomp_num; i++) { + jfif->comp_info[i].id = buf[1 + i * 2]; + jfif->comp_info[i].htab_idx_ac = (buf[2 + i * 2] >> 0) & 0x0f; + jfif->comp_info[i].htab_idx_dc = (buf[2 + i * 2] >> 4) & 0x0f; + } + offset = ftell(fp); + ret = 0; + goto read_data; + + case 0xdb: // DQT + dqt = buf; + while (size > 0 && dqt < end) { + int idx = dqt[0] & 0x0f; + int f16 = dqt[0] & 0xf0; + if (!jfif->pqtab[idx]) jfif->pqtab[idx] = malloc(64 * sizeof(int)); + if (!jfif->pqtab[idx]) break; + if (dqt + 1 + 64 + (f16 ? 64 : 0) < end) { + for (i=0; i<64; i++) { + jfif->pqtab[idx][ZIGZAG[i]] = f16 ? ((dqt[1 + i * 2] << 8) | (dqt[2 + i * 2] << 0)) : dqt[1 + i]; + } + } + dqt += 1 + 64 + (f16 ? 64 : 0); + size-= 1 + 64 + (f16 ? 64 : 0); + } + break; + + case 0xc4: // DHT + dht = buf; + while (size > 0 && dht + 17 < end) { + int idx = dht[0] & 0x0f; + int fac = dht[0] & 0xf0; + int len = 0; + for (i=1; i<1+16; i++) len += dht[i]; + if (len > end - dht - 17) len = end - dht - 17; + if (len > 256) len = 256; + if (fac) { + if (!jfif->phcac[idx]) jfif->phcac[idx] = calloc(1, sizeof(HUFCODEC)); + if ( jfif->phcac[idx]) memcpy(jfif->phcac[idx]->huftab, &dht[1], 16 + len); + } else { + if (!jfif->phcdc[idx]) jfif->phcdc[idx] = calloc(1, sizeof(HUFCODEC)); + if ( jfif->phcdc[idx]) memcpy(jfif->phcdc[idx]->huftab, &dht[1], 16 + len); + } + dht += 17 + len; + size-= 17 + len; + } + break; + } + } + +read_data: + fseek(fp, 0, SEEK_END); + jfif->datalen = ftell(fp) - offset; + jfif->databuf = malloc(jfif->datalen); + if (jfif->databuf) { + fseek(fp, offset, SEEK_SET); + fread(jfif->databuf, 1, jfif->datalen, fp); + } + +done: + if (buf) free (buf); + if (fp ) fclose(fp ); + if (ret == -1) { + jfif_free(jfif); + jfif = NULL; + } + return jfif; +} + +int jfif_save(void *ctxt, char *file) +{ + JFIF *jfif = (JFIF*)ctxt; + FILE *fp = NULL; + int len = 0; + int i, j; + int ret = -1; + + fp = fopen(file, "wb"); + if (!fp) goto done; + + // output SOI + fputc(0xff, fp); + fputc(0xd8, fp); + + // output DQT + for (i=0; i<16; i++) { + if (!jfif->pqtab[i]) continue; + len = 2 + 1 + 64; + fputc(0xff, fp); + fputc(0xdb, fp); + fputc(len >> 8, fp); + fputc(len >> 0, fp); + fputc(i , fp); + for (j=0; j<64; j++) { + fputc(jfif->pqtab[i][ZIGZAG[j]], fp); + } + } + + // output SOF0 + len = 2 + 1 + 2 + 2 + 1 + 3 * jfif->comp_num; + fputc(0xff, fp); + fputc(0xc0, fp); + fputc(len >> 8, fp); + fputc(len >> 0, fp); + fputc(8 , fp); // precision 8bit + fputc(jfif->height >> 8, fp); // height + fputc(jfif->height >> 0, fp); // height + fputc(jfif->width >> 8, fp); // width + fputc(jfif->width >> 0, fp); // width + fputc(jfif->comp_num, fp); + for (i=0; icomp_num; i++) { + fputc(jfif->comp_info[i].id, fp); + fputc((jfif->comp_info[i].samp_factor_v << 0)|(jfif->comp_info[i].samp_factor_h << 4), fp); + fputc(jfif->comp_info[i].qtab_idx, fp); + } + + // output DHT AC + for (i=0; i<16; i++) { + if (!jfif->phcac[i]) continue; + fputc(0xff, fp); + fputc(0xc4, fp); + len = 2 + 1 + 16; + for (j=0; j<16; j++) len += jfif->phcac[i]->huftab[j]; + fputc(len >> 8, fp); + fputc(len >> 0, fp); + fputc(i + 0x10, fp); + fwrite(jfif->phcac[i]->huftab, len - 3, 1, fp); + } + + // output DHT DC + for (i=0; i<16; i++) { + if (!jfif->phcdc[i]) continue; + fputc(0xff, fp); + fputc(0xc4, fp); + len = 2 + 1 + 16; + for (j=0; j<16; j++) len += jfif->phcdc[i]->huftab[j]; + fputc(len >> 8, fp); + fputc(len >> 0, fp); + fputc(i + 0x00, fp); + fwrite(jfif->phcdc[i]->huftab, len - 3, 1, fp); + } + + // output SOS + len = 2 + 1 + 2 * jfif->comp_num + 3; + fputc(0xff, fp); + fputc(0xda, fp); + fputc(len >> 8, fp); + fputc(len >> 0, fp); + fputc(jfif->comp_num, fp); + for (i=0; icomp_num; i++) { + fputc(jfif->comp_info[i].id, fp); + fputc((jfif->comp_info[i].htab_idx_ac << 0)|(jfif->comp_info[i].htab_idx_dc << 4), fp); + } + fputc(0x00, fp); + fputc(0x00, fp); + fputc(0x00, fp); + + // output data + if (jfif->databuf) { + fwrite(jfif->databuf, jfif->datalen, 1, fp); + } + ret = 0; + +done: + if (fp) fclose(fp); + return ret; +} + +void jfif_free(void *ctxt) +{ + JFIF *jfif = (JFIF*)ctxt; + int i; + if (!jfif) return; + for (i=0; i<16; i++) { + if (jfif->pqtab[i]) free(jfif->pqtab[i]); + if (jfif->phcac[i]) free(jfif->phcac[i]); + if (jfif->phcdc[i]) free(jfif->phcdc[i]); + } + if (jfif->databuf) free(jfif->databuf); + free(jfif); +} + +int jfif_decode(void *ctxt, BMP *pb) +{ + JFIF *jfif = (JFIF*)ctxt; + void *bs = NULL; + int *ftab[16]= {0}; + int dc[4] = {0}; + int mcuw, mcuh, mcuc, mcur, mcui, jw, jh; + int i, j, c, h, v, x, y; + int sfh_max = 0; + int sfv_max = 0; + int yuv_stride[3] = {0}; + int yuv_height[3] = {0}; + int *yuv_datbuf[3] = {0}; + int *idst, *isrc; + int *ysrc, *usrc, *vsrc; + BYTE *bdst; + int ret = -1; + + if (!ctxt || !pb) { + printf("invalid input params !\n"); + return -1; + } + + // init dct module + init_dct_module(); + + //++ init ftab + for (i=0; i<16; i++) { + if (jfif->pqtab[i]) { + ftab[i] = malloc(64 * sizeof(int)); + if (ftab[i]) { + init_idct_ftab(ftab[i], jfif->pqtab[i]); + } else { + goto done; + } + } + } + //-- init ftab + + //++ calculate mcu info + for (c=0; ccomp_num; c++) { + if (sfh_max < jfif->comp_info[c].samp_factor_h) { + sfh_max = jfif->comp_info[c].samp_factor_h; + } + if (sfv_max < jfif->comp_info[c].samp_factor_v) { + sfv_max = jfif->comp_info[c].samp_factor_v; + } + } + mcuw = sfh_max * 8; + mcuh = sfv_max * 8; + jw = ALIGN(jfif->width , mcuw); + jh = ALIGN(jfif->height, mcuh); + mcuc = jw / mcuw; // cppcheck-suppress bughuntingDivByZero + mcur = jh / mcuh; + //-- calculate mcu info + + // create yuv buffer for decoding + yuv_stride[0] = jw; + yuv_stride[1] = jw * jfif->comp_info[1].samp_factor_h / sfh_max; + yuv_stride[2] = jw * jfif->comp_info[2].samp_factor_h / sfh_max; + yuv_height[0] = jh; + yuv_height[1] = jh * jfif->comp_info[1].samp_factor_v / sfv_max; + yuv_height[2] = jh * jfif->comp_info[2].samp_factor_v / sfv_max; + yuv_datbuf[0] = malloc(yuv_stride[0] * yuv_height[0] * sizeof(int)); + yuv_datbuf[1] = malloc(yuv_stride[1] * yuv_height[1] * sizeof(int)); + yuv_datbuf[2] = malloc(yuv_stride[2] * yuv_height[2] * sizeof(int)); + if (!yuv_datbuf[0] || !yuv_datbuf[1] || !yuv_datbuf[2]) { + goto done; + } + + // open bit stream + bs = bitstr_open(jfif->databuf, "mem", jfif->datalen); + if (!bs) { + printf("failed to open bitstr for jfif_decode !"); + return -1; + } + + // init huffman codec + for (i=0; i<16; i++) { + if (jfif->phcac[i]) { + jfif->phcac[i]->input = bs; + huffman_decode_init(jfif->phcac[i]); + } + if (jfif->phcdc[i]) { + jfif->phcdc[i]->input = bs; + huffman_decode_init(jfif->phcdc[i]); + } + } + + for (mcui=0; mcuicomp_num; c++) { + for (v=0; vcomp_info[c].samp_factor_v; v++) { + for (h=0; hcomp_info[c].samp_factor_h; h++) { + HUFCODEC *hcac = jfif->phcac[jfif->comp_info[c].htab_idx_ac]; + HUFCODEC *hcdc = jfif->phcdc[jfif->comp_info[c].htab_idx_dc]; + int fidx = jfif->comp_info[c].qtab_idx; + int size, znum, code; + int du[64] = {0}; + + //+ decode dc + size = huffman_decode_step(hcdc) & 0xf; + if (size) { + code = bitstr_get_bits(bs , size); + code = category_decode(code, size); + } + else { + code = 0; + } + dc[c] += code; + du[0] = dc[c]; + //- decode dc + + //+ decode ac + for (i=1; i<64; ) { + code = huffman_decode_step(hcac); + if (code <= 0) break; + size = (code >> 0) & 0xf; + znum = (code >> 4) & 0xf; + i += znum; + code = bitstr_get_bits(bs , size); + code = category_decode(code, size); + if (i < 64) du[i++] = code; + } + //- decode ac + + // de-zigzag + zigzag_decode(du); + + // idct + idct2d8x8(du, ftab[fidx]); + + // copy du to yuv buffer + x = ((mcui % mcuc) * mcuw + h * 8) * jfif->comp_info[c].samp_factor_h / sfh_max; + y = ((mcui / mcuc) * mcuh + v * 8) * jfif->comp_info[c].samp_factor_v / sfv_max; + idst = yuv_datbuf[c] + y * yuv_stride[c] + x; + isrc = du; + for (i=0; i<8; i++) { + memcpy(idst, isrc, 8 * sizeof(int)); + idst += yuv_stride[c]; + isrc += 8; + } + } + } + } + } + + // close huffman codec + for (i=0; i<16; i++) { + if (jfif->phcac[i]) huffman_decode_done(jfif->phcac[i]); + if (jfif->phcdc[i]) huffman_decode_done(jfif->phcdc[i]); + } + + // close bit stream + bitstr_close(bs); + + // create bitmap, and convert yuv to rgb + bmp_create(pb, jfif->width, jfif->height); + bdst = (BYTE*)pb->pdata; + ysrc = yuv_datbuf[0]; + for (i=0; iheight; i++) { + int uy = i * jfif->comp_info[1].samp_factor_v / sfv_max; + int vy = i * jfif->comp_info[2].samp_factor_v / sfv_max; + for (j=0; jwidth; j++) { + int ux = j * jfif->comp_info[1].samp_factor_h / sfh_max; + int vx = j * jfif->comp_info[2].samp_factor_h / sfh_max; + usrc = yuv_datbuf[2] + uy * yuv_stride[2] + ux; + vsrc = yuv_datbuf[1] + vy * yuv_stride[1] + vx; + yuv_to_rgb(*ysrc, *vsrc, *usrc, bdst + 2, bdst + 1, bdst + 0); + bdst += 3; + ysrc += 1; + } + bdst -= jfif->width * 3; + bdst += pb->stride; + ysrc -= jfif->width * 1; + ysrc += yuv_stride[0]; + } + + // success + ret = 0; + +done: + if (yuv_datbuf[0]) free(yuv_datbuf[0]); + if (yuv_datbuf[1]) free(yuv_datbuf[1]); + if (yuv_datbuf[2]) free(yuv_datbuf[2]); + //++ free ftab + for (i=0; i<16; i++) { + if (ftab[i]) { + free(ftab[i]); + } + } + //-- free ftab + return ret; +} + +#define DU_TYPE_LUMIN 0 +#define DU_TYPE_CHROM 1 + +typedef struct { + unsigned runlen : 4; + unsigned codesize : 4; + unsigned codedata : 16; +} RLEITEM; + +static void jfif_encode_du(JFIF *jfif, int type, int du[64], int *dc) +{ + HUFCODEC *hfcac = jfif->phcac[type]; + HUFCODEC *hfcdc = jfif->phcdc[type]; + int *pqtab = jfif->pqtab[type]; + void *bs = hfcac->output; + int diff, code, size; + RLEITEM rlelist[63]; + int i, j, n, eob; + + // fdct + fdct2d8x8(du, NULL); + + // quant + quant_encode(du, pqtab); + + // zigzag + zigzag_encode(du); + + // dc + diff = du[0] - *dc; + *dc = du[0]; + + // category encode for dc + code = diff; + category_encode(&code, &size); + + // huffman encode for dc + huffman_encode_step(hfcdc, size); + bitstr_put_bits(bs, code, size); + + // rle encode for ac + for (i=1, j=0, n=0, eob=0; i<64 && j<63; i++) { + if (du[i] == 0 && n < 15) { + n++; + } else { + code = du[i]; size = 0; + category_encode(&code, &size); + rlelist[j].runlen = n; + rlelist[j].codesize = size; + rlelist[j].codedata = code; + n = 0; + j++; + if (size != 0) eob = j; + } + } + + // set eob + if (du[63] == 0) { + rlelist[eob].runlen = 0; + rlelist[eob].codesize = 0; + rlelist[eob].codedata = 0; + j = eob + 1; + } + + // huffman encode for ac + for (i=0; iwidth = pb->width; + jfif->height = pb->height; + jfif->pqtab[0] = malloc(64*sizeof(int)); + jfif->pqtab[1] = malloc(64*sizeof(int)); + jfif->phcac[0] = calloc(1, sizeof(HUFCODEC)); + jfif->phcac[1] = calloc(1, sizeof(HUFCODEC)); + jfif->phcdc[0] = calloc(1, sizeof(HUFCODEC)); + jfif->phcdc[1] = calloc(1, sizeof(HUFCODEC)); + jfif->datalen = jfif->width * jfif->height * 2; + jfif->databuf = malloc(jfif->datalen); + if ( !jfif->pqtab[0] || !jfif->pqtab[1] + || !jfif->phcac[0] || !jfif->phcac[1] + || !jfif->phcdc[0] || !jfif->phcdc[1] + || !jfif->databuf ) { + goto done; + } + + // init qtab + memcpy(jfif->pqtab[0], STD_QUANT_TAB_LUMIN, 64*sizeof(int)); + memcpy(jfif->pqtab[1], STD_QUANT_TAB_CHROM, 64*sizeof(int)); + + // open bit stream + bs = bitstr_open(jfif->databuf, "mem", jfif->datalen); + if (!bs) { + printf("failed to open bitstr for jfif_decode !"); + goto done; + } + + // init huffman codec + memcpy(jfif->phcac[0]->huftab, STD_HUFTAB_LUMIN_AC, MAX_HUFFMAN_CODE_LEN + 256); + memcpy(jfif->phcac[1]->huftab, STD_HUFTAB_CHROM_AC, MAX_HUFFMAN_CODE_LEN + 256); + memcpy(jfif->phcdc[0]->huftab, STD_HUFTAB_LUMIN_DC, MAX_HUFFMAN_CODE_LEN + 256); + memcpy(jfif->phcdc[1]->huftab, STD_HUFTAB_CHROM_DC, MAX_HUFFMAN_CODE_LEN + 256); + jfif->phcac[0]->output = bs; huffman_encode_init(jfif->phcac[0], 1); + jfif->phcac[1]->output = bs; huffman_encode_init(jfif->phcac[1], 1); + jfif->phcdc[0]->output = bs; huffman_encode_init(jfif->phcdc[0], 1); + jfif->phcdc[1]->output = bs; huffman_encode_init(jfif->phcdc[1], 1); + + // init comp_num & comp_info + jfif->comp_num = 3; + jfif->comp_info[0].id = 1; + jfif->comp_info[0].samp_factor_v = 2; + jfif->comp_info[0].samp_factor_h = 2; + jfif->comp_info[0].qtab_idx = 0; + jfif->comp_info[0].htab_idx_ac = 0; + jfif->comp_info[0].htab_idx_dc = 0; + jfif->comp_info[1].id = 2; + jfif->comp_info[1].samp_factor_v = 1; + jfif->comp_info[1].samp_factor_h = 1; + jfif->comp_info[1].qtab_idx = 1; + jfif->comp_info[1].htab_idx_ac = 1; + jfif->comp_info[1].htab_idx_dc = 1; + jfif->comp_info[2].id = 3; + jfif->comp_info[2].samp_factor_v = 1; + jfif->comp_info[2].samp_factor_h = 1; + jfif->comp_info[2].qtab_idx = 1; + jfif->comp_info[2].htab_idx_ac = 1; + jfif->comp_info[2].htab_idx_dc = 1; + + // init jw & jw, init yuv data buffer + jw = ALIGN(pb->width , 16); + jh = ALIGN(pb->height, 16); + yuv_datbuf[0] = calloc(1, jw * jh / 1 * sizeof(int)); + yuv_datbuf[1] = calloc(1, jw * jh / 4 * sizeof(int)); + yuv_datbuf[2] = calloc(1, jw * jh / 4 * sizeof(int)); + if (!yuv_datbuf[0] || !yuv_datbuf[1] || !yuv_datbuf[2]) { + goto done; + } + + // convert rgb to yuv + bsrc = pb->pdata; + ydst = yuv_datbuf[0]; + udst = yuv_datbuf[1]; + vdst = yuv_datbuf[2]; + for (i=0; iheight; i++) { + for (j=0; jwidth; j++) { + rgb_to_yuv(bsrc[2], bsrc[1], bsrc[0], ydst, udst, vdst); + bsrc += 3; + ydst += 1; + if (j & 1) { + udst += 1; + vdst += 1; + } + } + bsrc -= pb->width * 3; bsrc += pb->stride; + ydst -= pb->width * 1; ydst += jw; + udst -= pb->width / 2; + vdst -= pb->width / 2; + if (i & 1) { + udst += jw / 2; + vdst += jw / 2; + } + } + + for (m=0; mphcac[0]); + huffman_encode_done(jfif->phcac[1]); + huffman_encode_done(jfif->phcdc[0]); + huffman_encode_done(jfif->phcdc[1]); + jfif->datalen = bitstr_tell(bs); + + // close bit stream + bitstr_close(bs); + + // if failed free context + if (failed) { + jfif_free(jfif); + jfif = NULL; + } + + // return context + return jfif; +} + + + + + + +