/* * Receive and process new chunks of JPEG image data */ static void Jpeg_write(DilloJpeg *jpeg, void *Buf, uint_t BufSize) { DilloImgType type; uchar_t *linebuf; JSAMPLE *array[1]; int num_read; _MSG("Jpeg_write: (%p) Bytes in buff: %ld Ofs: %lu\n", jpeg, (long) BufSize, (ulong_t)jpeg->Start_Ofs); /* See if we are supposed to skip ahead. */ if (BufSize <= jpeg->Start_Ofs) return; /* Concatenate with the partial input, if any. */ jpeg->cinfo.src->next_input_byte = (uchar_t *)Buf + jpeg->Start_Ofs; jpeg->cinfo.src->bytes_in_buffer = BufSize - jpeg->Start_Ofs; jpeg->NewStart = BufSize; jpeg->Data = Buf; if (setjmp(jpeg->jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. */ jpeg->state = DILLO_JPEG_ERROR; } /* Process the bytes in the input buffer. */ if (jpeg->state == DILLO_JPEG_INIT) { /* decompression step 3 (see libjpeg.doc) */ if (jpeg_read_header(&(jpeg->cinfo), TRUE) != JPEG_SUSPENDED) { type = DILLO_IMG_TYPE_GRAY; if (jpeg->cinfo.num_components == 1) { type = DILLO_IMG_TYPE_GRAY; } else if (jpeg->cinfo.num_components == 3) { type = DILLO_IMG_TYPE_RGB; } else { MSG("4-component JPEG!\n"); if (jpeg->cinfo.jpeg_color_space == JCS_YCCK) MSG("YCCK. Are the colors wrong?\n"); if (!jpeg->cinfo.saw_Adobe_marker) MSG("No adobe marker! Is the image shown in reverse video?\n"); type = DILLO_IMG_TYPE_CMYK_INV; } /* * If a multiple-scan image is not completely in cache, * use progressive display, updating as it arrives. */ if (jpeg_has_multiple_scans(&jpeg->cinfo) && !(a_Capi_get_flags(jpeg->url) & CAPI_Completed)) jpeg->cinfo.buffered_image = TRUE; /* check max image size */ if (jpeg->cinfo.image_width <= 0 || jpeg->cinfo.image_height <= 0 || jpeg->cinfo.image_width > IMAGE_MAX_AREA / jpeg->cinfo.image_height) { MSG("Jpeg_write: suspicious image size request %u x %u\n", (uint_t)jpeg->cinfo.image_width, (uint_t)jpeg->cinfo.image_height); jpeg->state = DILLO_JPEG_ERROR; return; } a_Dicache_set_parms(jpeg->url, jpeg->version, jpeg->Image, (uint_t)jpeg->cinfo.image_width, (uint_t)jpeg->cinfo.image_height, type); /* decompression step 4 (see libjpeg.doc) */ jpeg->state = DILLO_JPEG_STARTING; } } if (jpeg->state == DILLO_JPEG_STARTING) { /* decompression step 5 (see libjpeg.doc) */ if (jpeg_start_decompress(&(jpeg->cinfo))) { jpeg->y = 0; jpeg->state = jpeg->cinfo.buffered_image ? DILLO_JPEG_READ_BEGIN_SCAN : DILLO_JPEG_READ_IN_SCAN; } } /* * A progressive jpeg contains multiple scans that can be used to display * an increasingly sharp image as it is being received. The reading of each * scan must be surrounded by jpeg_start_output()/jpeg_finish_output(). */ if (jpeg->state == DILLO_JPEG_READ_END_SCAN) { if (jpeg_finish_output(&jpeg->cinfo)) { if (jpeg_input_complete(&jpeg->cinfo)) { jpeg->state = DILLO_JPEG_DONE; } else { jpeg->state = DILLO_JPEG_READ_BEGIN_SCAN; } } } if (jpeg->state == DILLO_JPEG_READ_BEGIN_SCAN) { if (jpeg_start_output(&jpeg->cinfo, jpeg->cinfo.input_scan_number)) { a_Dicache_new_scan(jpeg->url, jpeg->version); jpeg->state = DILLO_JPEG_READ_IN_SCAN; } } if (jpeg->state == DILLO_JPEG_READ_IN_SCAN) { linebuf = dMalloc(jpeg->cinfo.image_width * jpeg->cinfo.num_components); array[0] = linebuf; while (1) { num_read = jpeg_read_scanlines(&(jpeg->cinfo), array, 1); if (num_read == 0) { /* out of input */ break; } a_Dicache_write(jpeg->url, jpeg->version, linebuf, jpeg->y); jpeg->y++; if (jpeg->y == jpeg->cinfo.image_height) { /* end of scan */ if (!jpeg->cinfo.buffered_image) { /* single scan */ jpeg->state = DILLO_JPEG_DONE; break; } else { jpeg->y = 0; if (jpeg_input_complete(&jpeg->cinfo)) { if (jpeg->cinfo.input_scan_number == jpeg->cinfo.output_scan_number) { jpeg->state = DILLO_JPEG_DONE; break; } else { /* one final loop through the scanlines */ jpeg_finish_output(&jpeg->cinfo); jpeg_start_output(&jpeg->cinfo, jpeg->cinfo.input_scan_number); continue; } } jpeg->state = DILLO_JPEG_READ_END_SCAN; if (!jpeg_finish_output(&jpeg->cinfo)) { /* out of input */ break; } else { if (jpeg_input_complete(&jpeg->cinfo)) { jpeg->state = DILLO_JPEG_DONE; break; } else { jpeg->state = DILLO_JPEG_READ_BEGIN_SCAN; } } if (!jpeg_start_output(&jpeg->cinfo, jpeg->cinfo.input_scan_number)) { /* out of input */ break; } a_Dicache_new_scan(jpeg->url, jpeg->version); jpeg->state = DILLO_JPEG_READ_IN_SCAN; } } } dFree(linebuf); } }
/* * Most used function for requesting a URL. * TODO: clean up the ad-hoc bindings with an API that allows dynamic * addition of new plugins. * * Return value: A primary key for identifying the client, * 0 if the client is aborted in the process. */ int a_Capi_open_url(DilloWeb *web, CA_Callback_t Call, void *CbData) { int reload; char *cmd, *server; capi_conn_t *conn = NULL; const char *scheme = URL_SCHEME(web->url); int safe = 0, ret = 0, use_cache = 0; /* reload test */ reload = (!(a_Capi_get_flags(web->url) & CAPI_IsCached) || (URL_FLAGS(web->url) & URL_E2EQuery)); if (web->flags & WEB_Download) { /* download request: if cached save from cache, else * for http, ftp or https, use the downloads dpi */ if (a_Capi_get_flags_with_redirection(web->url) & CAPI_IsCached) { if (web->filename) { if ((web->stream = fopen(web->filename, "w"))) { use_cache = 1; } else { MSG_WARN("Cannot open \"%s\" for writing.\n", web->filename); } } } else if (a_Cache_download_enabled(web->url)) { server = "downloads"; cmd = Capi_dpi_build_cmd(web, server); a_Capi_dpi_send_cmd(web->url, web->bw, cmd, server, 1); dFree(cmd); } } else if (Capi_url_uses_dpi(web->url, &server)) { /* dpi request */ if ((safe = a_Capi_dpi_verify_request(web->bw, web->url))) { if (dStrcasecmp(scheme, "dpi") == 0) { /* make "dpi:/" prefixed urls always reload. */ a_Url_set_flags(web->url, URL_FLAGS(web->url) | URL_E2EQuery); reload = 1; } if (reload) { a_Capi_conn_abort_by_url(web->url); /* Send dpip command */ cmd = Capi_dpi_build_cmd(web, server); a_Capi_dpi_send_cmd(web->url, web->bw, cmd, server, 1); dFree(cmd); } use_cache = 1; } dFree(server); } else if (!dStrcasecmp(scheme, "http")) { /* http request */ if (reload) { a_Capi_conn_abort_by_url(web->url); /* create a new connection and start the CCC operations */ conn = Capi_conn_new(web->url, web->bw, "http", "none"); /* start the reception branch before the query one because the DNS * may callback immediatly. This may avoid a race condition. */ a_Capi_ccc(OpStart, 2, BCK, a_Chain_new(), conn, "http"); a_Capi_ccc(OpStart, 1, BCK, a_Chain_new(), conn, web); } use_cache = 1; } else if (!dStrcasecmp(scheme, "about")) { /* internal request */ use_cache = 1; } if (use_cache) { if (!conn || (conn && Capi_conn_valid(conn))) { /* not aborted, let's continue... */ ret = a_Cache_open_url(web, Call, CbData); } } else { a_Web_free(web); } return ret; }