diff options
author | RajithaY <rajithax.yerrumsetty@intel.com> | 2017-04-25 03:31:15 -0700 |
---|---|---|
committer | Rajitha Yerrumchetty <rajithax.yerrumsetty@intel.com> | 2017-05-22 06:48:08 +0000 |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/roms/ipxe/src/image/png.c | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/roms/ipxe/src/image/png.c')
-rw-r--r-- | qemu/roms/ipxe/src/image/png.c | 1011 |
1 files changed, 0 insertions, 1011 deletions
diff --git a/qemu/roms/ipxe/src/image/png.c b/qemu/roms/ipxe/src/image/png.c deleted file mode 100644 index 5c4bcb3a0..000000000 --- a/qemu/roms/ipxe/src/image/png.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* - * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * You can also choose to distribute this program under the terms of - * the Unmodified Binary Distribution Licence (as given in the file - * COPYING.UBDL), provided that you have satisfied its requirements. - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <byteswap.h> -#include <ipxe/umalloc.h> -#include <ipxe/pixbuf.h> -#include <ipxe/deflate.h> -#include <ipxe/png.h> - -/** @file - * - * Portable Network Graphics (PNG) format - * - * The PNG format is defined in RFC 2083. - */ - -/** PNG context */ -struct png_context { - /** Offset within image */ - size_t offset; - - /** Pixel buffer */ - struct pixel_buffer *pixbuf; - - /** Bit depth */ - unsigned int depth; - /** Colour type */ - unsigned int colour_type; - /** Number of channels */ - unsigned int channels; - /** Number of interlace passes */ - unsigned int passes; - /** Palette, in iPXE's pixel buffer format */ - uint32_t palette[PNG_PALETTE_COUNT]; - - /** Decompression buffer for raw PNG data */ - struct deflate_chunk raw; - /** Decompressor */ - struct deflate deflate; -}; - -/** A PNG interlace pass */ -struct png_interlace { - /** Pass number */ - unsigned int pass; - /** X starting indent */ - unsigned int x_indent; - /** Y starting indent */ - unsigned int y_indent; - /** X stride */ - unsigned int x_stride; - /** Y stride */ - unsigned int y_stride; - /** Width */ - unsigned int width; - /** Height */ - unsigned int height; -}; - -/** PNG file signature */ -static struct png_signature png_signature = PNG_SIGNATURE; - -/** Number of interlacing passes */ -static uint8_t png_interlace_passes[] = { - [PNG_INTERLACE_NONE] = 1, - [PNG_INTERLACE_ADAM7] = 7, -}; - -/** - * Transcribe PNG chunk type name (for debugging) - * - * @v type Chunk type - * @ret name Chunk type name - */ -static const char * png_type_name ( uint32_t type ) { - static union { - uint32_t type; - char name[ sizeof ( uint32_t ) + 1 /* NUL */ ]; - } u; - - u.type = type; - return u.name; -} - -/** - * Calculate PNG interlace pass parameters - * - * @v png PNG context - * @v pass Pass number (0=first pass) - * @v interlace Interlace pass to fill in - */ -static void png_interlace ( struct png_context *png, unsigned int pass, - struct png_interlace *interlace ) { - unsigned int grid_width_log2; - unsigned int grid_height_log2; - unsigned int x_indent; - unsigned int y_indent; - unsigned int x_stride_log2; - unsigned int y_stride_log2; - unsigned int x_stride; - unsigned int y_stride; - unsigned int width; - unsigned int height; - - /* Sanity check */ - assert ( png->passes > 0 ); - - /* Store pass number */ - interlace->pass = pass; - - /* Calculate interlace grid dimensions */ - grid_width_log2 = ( png->passes / 2 ); - grid_height_log2 = ( ( png->passes - 1 ) / 2 ); - - /* Calculate starting indents */ - interlace->x_indent = x_indent = - ( ( pass & 1 ) ? - ( 1 << ( grid_width_log2 - ( pass / 2 ) - 1 ) ) : 0 ); - interlace->y_indent = y_indent = - ( ( pass && ! ( pass & 1 ) ) ? - ( 1 << ( grid_height_log2 - ( ( pass - 1 ) / 2 ) - 1 ) ) : 0); - - /* Calculate strides */ - x_stride_log2 = ( grid_width_log2 - ( pass / 2 ) ); - y_stride_log2 = - ( grid_height_log2 - ( pass ? ( ( pass - 1 ) / 2 ) : 0 ) ); - interlace->x_stride = x_stride = ( 1 << x_stride_log2 ); - interlace->y_stride = y_stride = ( 1 << y_stride_log2 ); - - /* Calculate pass dimensions */ - width = png->pixbuf->width; - height = png->pixbuf->height; - interlace->width = - ( ( width - x_indent + x_stride - 1 ) >> x_stride_log2 ); - interlace->height = - ( ( height - y_indent + y_stride - 1 ) >> y_stride_log2 ); -} - -/** - * Calculate PNG pixel length - * - * @v png PNG context - * @ret pixel_len Pixel length - */ -static unsigned int png_pixel_len ( struct png_context *png ) { - - return ( ( ( png->channels * png->depth ) + 7 ) / 8 ); -} - -/** - * Calculate PNG scanline length - * - * @v png PNG context - * @v interlace Interlace pass - * @ret scanline_len Scanline length (including filter byte) - */ -static size_t png_scanline_len ( struct png_context *png, - struct png_interlace *interlace ) { - - return ( 1 /* Filter byte */ + - ( ( interlace->width * png->channels * png->depth ) + 7 ) / 8); -} - -/** - * Handle PNG image header chunk - * - * @v image PNG image - * @v png PNG context - * @v len Chunk length - * @ret rc Return status code - */ -static int png_image_header ( struct image *image, struct png_context *png, - size_t len ) { - struct png_image_header ihdr; - struct png_interlace interlace; - unsigned int pass; - - /* Sanity check */ - if ( len != sizeof ( ihdr ) ) { - DBGC ( image, "PNG %s invalid IHDR length %zd\n", - image->name, len ); - return -EINVAL; - } - if ( png->pixbuf ) { - DBGC ( image, "PNG %s duplicate IHDR\n", image->name ); - return -EINVAL; - } - - /* Extract image header */ - copy_from_user ( &ihdr, image->data, png->offset, len ); - DBGC ( image, "PNG %s %dx%d depth %d type %d compression %d filter %d " - "interlace %d\n", image->name, ntohl ( ihdr.width ), - ntohl ( ihdr.height ), ihdr.depth, ihdr.colour_type, - ihdr.compression, ihdr.filter, ihdr.interlace ); - - /* Sanity checks */ - if ( ihdr.compression >= PNG_COMPRESSION_UNKNOWN ) { - DBGC ( image, "PNG %s unknown compression method %d\n", - image->name, ihdr.compression ); - return -ENOTSUP; - } - if ( ihdr.filter >= PNG_FILTER_UNKNOWN ) { - DBGC ( image, "PNG %s unknown filter method %d\n", - image->name, ihdr.filter ); - return -ENOTSUP; - } - if ( ihdr.interlace >= PNG_INTERLACE_UNKNOWN ) { - DBGC ( image, "PNG %s unknown interlace method %d\n", - image->name, ihdr.interlace ); - return -ENOTSUP; - } - - /* Allocate pixel buffer */ - png->pixbuf = alloc_pixbuf ( ntohl ( ihdr.width ), - ntohl ( ihdr.height ) ); - if ( ! png->pixbuf ) { - DBGC ( image, "PNG %s could not allocate pixel buffer\n", - image->name ); - return -ENOMEM; - } - - /* Extract bit depth */ - png->depth = ihdr.depth; - if ( ( png->depth == 0 ) || - ( ( png->depth & ( png->depth - 1 ) ) != 0 ) ) { - DBGC ( image, "PNG %s invalid depth %d\n", - image->name, png->depth ); - return -EINVAL; - } - - /* Calculate number of channels */ - png->colour_type = ihdr.colour_type; - png->channels = 1; - if ( ! ( ihdr.colour_type & PNG_COLOUR_TYPE_PALETTE ) ) { - if ( ihdr.colour_type & PNG_COLOUR_TYPE_RGB ) - png->channels += 2; - if ( ihdr.colour_type & PNG_COLOUR_TYPE_ALPHA ) - png->channels += 1; - } - - /* Calculate number of interlace passes */ - png->passes = png_interlace_passes[ihdr.interlace]; - - /* Calculate length of raw data buffer */ - for ( pass = 0 ; pass < png->passes ; pass++ ) { - png_interlace ( png, pass, &interlace ); - if ( interlace.width == 0 ) - continue; - png->raw.len += ( interlace.height * - png_scanline_len ( png, &interlace ) ); - } - - /* Allocate raw data buffer */ - png->raw.data = umalloc ( png->raw.len ); - if ( ! png->raw.data ) { - DBGC ( image, "PNG %s could not allocate data buffer\n", - image->name ); - return -ENOMEM; - } - - return 0; -} - -/** - * Handle PNG palette chunk - * - * @v image PNG image - * @v png PNG context - * @v len Chunk length - * @ret rc Return status code - */ -static int png_palette ( struct image *image, struct png_context *png, - size_t len ) { - size_t offset = png->offset; - struct png_palette_entry palette; - unsigned int i; - - /* Populate palette */ - for ( i = 0 ; i < ( sizeof ( png->palette ) / - sizeof ( png->palette[0] ) ) ; i++ ) { - - /* Stop when we run out of palette data */ - if ( len < sizeof ( palette ) ) - break; - - /* Extract palette entry */ - copy_from_user ( &palette, image->data, offset, - sizeof ( palette ) ); - png->palette[i] = ( ( palette.red << 16 ) | - ( palette.green << 8 ) | - ( palette.blue << 0 ) ); - DBGC2 ( image, "PNG %s palette entry %d is %#06x\n", - image->name, i, png->palette[i] ); - - /* Move to next entry */ - offset += sizeof ( palette ); - len -= sizeof ( palette ); - } - - return 0; -} - -/** - * Handle PNG image data chunk - * - * @v image PNG image - * @v png PNG context - * @v len Chunk length - * @ret rc Return status code - */ -static int png_image_data ( struct image *image, struct png_context *png, - size_t len ) { - struct deflate_chunk in; - int rc; - - /* Deflate this chunk */ - deflate_chunk_init ( &in, image->data, png->offset, - ( png->offset + len ) ); - if ( ( rc = deflate_inflate ( &png->deflate, &in, &png->raw ) ) != 0 ) { - DBGC ( image, "PNG %s could not decompress: %s\n", - image->name, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Unfilter byte using the "None" filter - * - * @v current Filtered current byte - * @v left Unfiltered left byte - * @v above Unfiltered above byte - * @v above_left Unfiltered above-left byte - * @ret current Unfiltered current byte - */ -static unsigned int png_unfilter_none ( unsigned int current, - unsigned int left __unused, - unsigned int above __unused, - unsigned int above_left __unused ) { - - return current; -} - -/** - * Unfilter byte using the "Sub" filter - * - * @v current Filtered current byte - * @v left Unfiltered left byte - * @v above Unfiltered above byte - * @v above_left Unfiltered above-left byte - * @ret current Unfiltered current byte - */ -static unsigned int png_unfilter_sub ( unsigned int current, - unsigned int left, - unsigned int above __unused, - unsigned int above_left __unused ) { - - return ( current + left ); -} - -/** - * Unfilter byte using the "Up" filter - * - * @v current Filtered current byte - * @v left Unfiltered left byte - * @v above Unfiltered above byte - * @v above_left Unfiltered above-left byte - * @ret current Unfiltered current byte - */ -static unsigned int png_unfilter_up ( unsigned int current, - unsigned int left __unused, - unsigned int above, - unsigned int above_left __unused ) { - - return ( current + above ); -} - -/** - * Unfilter byte using the "Average" filter - * - * @v current Filtered current byte - * @v left Unfiltered left byte - * @v above Unfiltered above byte - * @v above_left Unfiltered above-left byte - * @ret current Unfiltered current byte - */ -static unsigned int png_unfilter_average ( unsigned int current, - unsigned int left, - unsigned int above, - unsigned int above_left __unused ) { - - return ( current + ( ( above + left ) >> 1 ) ); -} - -/** - * Paeth predictor function (defined in RFC 2083) - * - * @v a Pixel A - * @v b Pixel B - * @v c Pixel C - * @ret predictor Predictor pixel - */ -static unsigned int png_paeth_predictor ( unsigned int a, unsigned int b, - unsigned int c ) { - unsigned int p; - unsigned int pa; - unsigned int pb; - unsigned int pc; - - /* Algorithm as defined in RFC 2083 section 6.6 */ - p = ( a + b - c ); - pa = abs ( p - a ); - pb = abs ( p - b ); - pc = abs ( p - c ); - if ( ( pa <= pb ) && ( pa <= pc ) ) { - return a; - } else if ( pb <= pc ) { - return b; - } else { - return c; - } -} - -/** - * Unfilter byte using the "Paeth" filter - * - * @v current Filtered current byte - * @v above_left Unfiltered above-left byte - * @v above Unfiltered above byte - * @v left Unfiltered left byte - * @ret current Unfiltered current byte - */ -static unsigned int png_unfilter_paeth ( unsigned int current, - unsigned int left, - unsigned int above, - unsigned int above_left ) { - - return ( current + png_paeth_predictor ( left, above, above_left ) ); -} - -/** A PNG filter */ -struct png_filter { - /** - * Unfilter byte - * - * @v current Filtered current byte - * @v left Unfiltered left byte - * @v above Unfiltered above byte - * @v above_left Unfiltered above-left byte - * @ret current Unfiltered current byte - */ - unsigned int ( * unfilter ) ( unsigned int current, - unsigned int left, - unsigned int above, - unsigned int above_left ); -}; - -/** PNG filter types */ -static struct png_filter png_filters[] = { - [PNG_FILTER_BASIC_NONE] = { png_unfilter_none }, - [PNG_FILTER_BASIC_SUB] = { png_unfilter_sub }, - [PNG_FILTER_BASIC_UP] = { png_unfilter_up }, - [PNG_FILTER_BASIC_AVERAGE] = { png_unfilter_average }, - [PNG_FILTER_BASIC_PAETH] = { png_unfilter_paeth }, -}; - -/** - * Unfilter one interlace pass of PNG raw data - * - * @v image PNG image - * @v png PNG context - * @v interlace Interlace pass - * @ret rc Return status code - * - * This routine may assume that it is impossible to overrun the raw - * data buffer, since the size is determined by the image dimensions. - */ -static int png_unfilter_pass ( struct image *image, struct png_context *png, - struct png_interlace *interlace ) { - size_t offset = png->raw.offset; - size_t pixel_len = png_pixel_len ( png ); - size_t scanline_len = png_scanline_len ( png, interlace ); - struct png_filter *filter; - unsigned int scanline; - unsigned int byte; - uint8_t filter_type; - uint8_t left; - uint8_t above; - uint8_t above_left; - uint8_t current; - - /* On the first scanline of a pass, above bytes are assumed to - * be zero. - */ - above = 0; - - /* Iterate over each scanline in turn */ - for ( scanline = 0 ; scanline < interlace->height ; scanline++ ) { - - /* Extract filter byte and determine filter type */ - copy_from_user ( &filter_type, png->raw.data, offset++, - sizeof ( filter_type ) ); - if ( filter_type >= ( sizeof ( png_filters ) / - sizeof ( png_filters[0] ) ) ) { - DBGC ( image, "PNG %s unknown filter type %d\n", - image->name, filter_type ); - return -ENOTSUP; - } - filter = &png_filters[filter_type]; - assert ( filter->unfilter != NULL ); - DBGC2 ( image, "PNG %s pass %d scanline %d filter type %d\n", - image->name, interlace->pass, scanline, filter_type ); - - /* At the start of a line, both above-left and left - * bytes are taken to be zero. - */ - left = 0; - above_left = 0; - - /* Iterate over each byte (not pixel) in turn */ - for ( byte = 0 ; byte < ( scanline_len - 1 ) ; byte++ ) { - - /* Extract predictor bytes, if applicable */ - if ( byte >= pixel_len ) { - copy_from_user ( &left, png->raw.data, - ( offset - pixel_len ), - sizeof ( left ) ); - } - if ( scanline > 0 ) { - copy_from_user ( &above, png->raw.data, - ( offset - scanline_len ), - sizeof ( above ) ); - } - if ( ( scanline > 0 ) && ( byte >= pixel_len ) ) { - copy_from_user ( &above_left, png->raw.data, - ( offset - scanline_len - - pixel_len ), - sizeof ( above_left ) ); - } - - /* Unfilter current byte */ - copy_from_user ( ¤t, png->raw.data, - offset, sizeof ( current ) ); - current = filter->unfilter ( current, left, above, - above_left ); - copy_to_user ( png->raw.data, offset++, - ¤t, sizeof ( current ) ); - } - } - - /* Update offset */ - png->raw.offset = offset; - - return 0; -} - -/** - * Unfilter PNG raw data - * - * @v image PNG image - * @v png PNG context - * @ret rc Return status code - * - * This routine may assume that it is impossible to overrun the raw - * data buffer, since the size is determined by the image dimensions. - */ -static int png_unfilter ( struct image *image, struct png_context *png ) { - struct png_interlace interlace; - unsigned int pass; - int rc; - - /* Process each interlace pass */ - png->raw.offset = 0; - for ( pass = 0 ; pass < png->passes ; pass++ ) { - - /* Calculate interlace pass parameters */ - png_interlace ( png, pass, &interlace ); - - /* Skip zero-width rows (which have no filter bytes) */ - if ( interlace.width == 0 ) - continue; - - /* Unfilter this pass */ - if ( ( rc = png_unfilter_pass ( image, png, - &interlace ) ) != 0 ) - return rc; - } - assert ( png->raw.offset == png->raw.len ); - - return 0; -} - -/** - * Calculate PNG pixel component value - * - * @v raw Raw component value - * @v alpha Alpha value - * @v max Maximum raw/alpha value - * @ret value Component value in range 0-255 - */ -static inline unsigned int png_pixel ( unsigned int raw, unsigned int alpha, - unsigned int max ) { - - /* The basic calculation is 255*(raw/max)*(value/max). We use - * fixed-point arithmetic (scaling up to the maximum range for - * a 32-bit integer), in order to get the same results for - * alpha blending as the test cases (produced using - * ImageMagick). - */ - return ( ( ( ( ( 0xff00 * raw * alpha ) / max ) / max ) + 0x80 ) >> 8 ); -} - -/** - * Fill one interlace pass of PNG pixels - * - * @v image PNG image - * @v png PNG context - * @v interlace Interlace pass - * - * This routine may assume that it is impossible to overrun either the - * raw data buffer or the pixel buffer, since the sizes of both are - * determined by the image dimensions. - */ -static void png_pixels_pass ( struct image *image, - struct png_context *png, - struct png_interlace *interlace ) { - size_t raw_offset = png->raw.offset; - uint8_t channel[png->channels]; - int is_indexed = ( png->colour_type & PNG_COLOUR_TYPE_PALETTE ); - int is_rgb = ( png->colour_type & PNG_COLOUR_TYPE_RGB ); - int has_alpha = ( png->colour_type & PNG_COLOUR_TYPE_ALPHA ); - size_t pixbuf_y_offset; - size_t pixbuf_offset; - size_t pixbuf_x_stride; - size_t pixbuf_y_stride; - size_t raw_stride; - unsigned int y; - unsigned int x; - unsigned int c; - unsigned int bits; - unsigned int depth; - unsigned int max; - unsigned int alpha; - unsigned int raw; - unsigned int value; - uint8_t current = 0; - uint32_t pixel; - - /* We only ever use the top byte of 16-bit pixels. Model this - * as a bit depth of 8 with a stride of more than one. - */ - depth = png->depth; - raw_stride = ( ( depth + 7 ) / 8 ); - if ( depth > 8 ) - depth = 8; - max = ( ( 1 << depth ) - 1 ); - - /* Calculate pixel buffer offset and strides */ - pixbuf_y_offset = ( ( ( interlace->y_indent * png->pixbuf->width ) + - interlace->x_indent ) * sizeof ( pixel ) ); - pixbuf_x_stride = ( interlace->x_stride * sizeof ( pixel ) ); - pixbuf_y_stride = ( interlace->y_stride * png->pixbuf->width * - sizeof ( pixel ) ); - DBGC2 ( image, "PNG %s pass %d %dx%d at (%d,%d) stride (%d,%d)\n", - image->name, interlace->pass, interlace->width, - interlace->height, interlace->x_indent, interlace->y_indent, - interlace->x_stride, interlace->y_stride ); - - /* Iterate over each scanline in turn */ - for ( y = 0 ; y < interlace->height ; y++ ) { - - /* Skip filter byte */ - raw_offset++; - - /* Iterate over each pixel in turn */ - bits = depth; - pixbuf_offset = pixbuf_y_offset; - for ( x = 0 ; x < interlace->width ; x++ ) { - - /* Extract sample value */ - for ( c = 0 ; c < png->channels ; c++ ) { - - /* Get sample value into high bits of current */ - current <<= depth; - bits -= depth; - if ( ! bits ) { - copy_from_user ( ¤t, - png->raw.data, - raw_offset, - sizeof ( current ) ); - raw_offset += raw_stride; - bits = 8; - } - - /* Extract sample value */ - channel[c] = ( current >> ( 8 - depth ) ); - } - - /* Convert to native pixel format */ - if ( is_indexed ) { - - /* Indexed */ - pixel = png->palette[channel[0]]; - - } else { - - /* Determine alpha value */ - alpha = ( has_alpha ? - channel[ png->channels - 1 ] : max ); - - /* Convert to RGB value */ - pixel = 0; - for ( c = 0 ; c < 3 ; c++ ) { - raw = channel[ is_rgb ? c : 0 ]; - value = png_pixel ( raw, alpha, max ); - assert ( value <= 255 ); - pixel = ( ( pixel << 8 ) | value ); - } - } - - /* Store pixel */ - copy_to_user ( png->pixbuf->data, pixbuf_offset, - &pixel, sizeof ( pixel ) ); - pixbuf_offset += pixbuf_x_stride; - } - - /* Move to next output row */ - pixbuf_y_offset += pixbuf_y_stride; - } - - /* Update offset */ - png->raw.offset = raw_offset; -} - -/** - * Fill PNG pixels - * - * @v image PNG image - * @v png PNG context - * - * This routine may assume that it is impossible to overrun either the - * raw data buffer or the pixel buffer, since the sizes of both are - * determined by the image dimensions. - */ -static void png_pixels ( struct image *image, struct png_context *png ) { - struct png_interlace interlace; - unsigned int pass; - - /* Process each interlace pass */ - png->raw.offset = 0; - for ( pass = 0 ; pass < png->passes ; pass++ ) { - - /* Calculate interlace pass parameters */ - png_interlace ( png, pass, &interlace ); - - /* Skip zero-width rows (which have no filter bytes) */ - if ( interlace.width == 0 ) - continue; - - /* Unfilter this pass */ - png_pixels_pass ( image, png, &interlace ); - } - assert ( png->raw.offset == png->raw.len ); -} - -/** - * Handle PNG image end chunk - * - * @v image PNG image - * @v png PNG context - * @v len Chunk length - * @ret rc Return status code - */ -static int png_image_end ( struct image *image, struct png_context *png, - size_t len ) { - int rc; - - /* Sanity checks */ - if ( len != 0 ) { - DBGC ( image, "PNG %s invalid IEND length %zd\n", - image->name, len ); - return -EINVAL; - } - if ( ! png->pixbuf ) { - DBGC ( image, "PNG %s missing pixel buffer (no IHDR?)\n", - image->name ); - return -EINVAL; - } - if ( ! deflate_finished ( &png->deflate ) ) { - DBGC ( image, "PNG %s decompression not complete\n", - image->name ); - return -EINVAL; - } - if ( png->raw.offset != png->raw.len ) { - DBGC ( image, "PNG %s incorrect decompressed length (expected " - "%zd, got %zd)\n", image->name, png->raw.len, - png->raw.offset ); - return -EINVAL; - } - - /* Unfilter raw data */ - if ( ( rc = png_unfilter ( image, png ) ) != 0 ) - return rc; - - /* Fill pixel buffer */ - png_pixels ( image, png ); - - return 0; -} - -/** A PNG chunk handler */ -struct png_chunk_handler { - /** Chunk type */ - uint32_t type; - /** - * Handle chunk - * - * @v image PNG image - * @v png PNG context - * @v len Chunk length - * @ret rc Return status code - */ - int ( * handle ) ( struct image *image, struct png_context *png, - size_t len ); -}; - -/** PNG chunk handlers */ -static struct png_chunk_handler png_chunk_handlers[] = { - { htonl ( PNG_TYPE_IHDR ), png_image_header }, - { htonl ( PNG_TYPE_PLTE ), png_palette }, - { htonl ( PNG_TYPE_IDAT ), png_image_data }, - { htonl ( PNG_TYPE_IEND ), png_image_end }, -}; - -/** - * Handle PNG chunk - * - * @v image PNG image - * @v png PNG context - * @v type Chunk type - * @v len Chunk length - * @ret rc Return status code - */ -static int png_chunk ( struct image *image, struct png_context *png, - uint32_t type, size_t len ) { - struct png_chunk_handler *handler; - unsigned int i; - - DBGC ( image, "PNG %s chunk type %s offset %zd length %zd\n", - image->name, png_type_name ( type ), png->offset, len ); - - /* Handle according to chunk type */ - for ( i = 0 ; i < ( sizeof ( png_chunk_handlers ) / - sizeof ( png_chunk_handlers[0] ) ) ; i++ ) { - handler = &png_chunk_handlers[i]; - if ( handler->type == type ) - return handler->handle ( image, png, len ); - } - - /* Fail if unknown chunk type is critical */ - if ( ! ( type & htonl ( PNG_CHUNK_ANCILLARY ) ) ) { - DBGC ( image, "PNG %s unknown critical chunk type %s\n", - image->name, png_type_name ( type ) ); - return -ENOTSUP; - } - - /* Ignore non-critical unknown chunk types */ - return 0; -} - -/** - * Convert PNG image to pixel buffer - * - * @v image PNG image - * @v pixbuf Pixel buffer to fill in - * @ret rc Return status code - */ -static int png_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ) { - struct png_context *png; - struct png_chunk_header header; - struct png_chunk_footer footer; - size_t remaining; - size_t chunk_len; - int rc; - - /* Allocate and initialise context */ - png = zalloc ( sizeof ( *png ) ); - if ( ! png ) { - rc = -ENOMEM; - goto err_alloc; - } - png->offset = sizeof ( struct png_signature ); - deflate_init ( &png->deflate, DEFLATE_ZLIB ); - - /* Process chunks */ - do { - - /* Extract chunk header */ - remaining = ( image->len - png->offset ); - if ( remaining < sizeof ( header ) ) { - DBGC ( image, "PNG %s truncated chunk header at offset " - "%zd\n", image->name, png->offset ); - rc = -EINVAL; - goto err_truncated; - } - copy_from_user ( &header, image->data, png->offset, - sizeof ( header ) ); - png->offset += sizeof ( header ); - - /* Validate chunk length */ - chunk_len = ntohl ( header.len ); - if ( remaining < ( sizeof ( header ) + chunk_len + - sizeof ( footer ) ) ) { - DBGC ( image, "PNG %s truncated chunk data/footer at " - "offset %zd\n", image->name, png->offset ); - rc = -EINVAL; - goto err_truncated; - } - - /* Handle chunk */ - if ( ( rc = png_chunk ( image, png, header.type, - chunk_len ) ) != 0 ) - goto err_chunk; - - /* Move to next chunk */ - png->offset += ( chunk_len + sizeof ( footer ) ); - - } while ( png->offset < image->len ); - - /* Check that we finished with an IEND chunk */ - if ( header.type != htonl ( PNG_TYPE_IEND ) ) { - DBGC ( image, "PNG %s did not finish with IEND\n", - image->name ); - rc = -EINVAL; - goto err_iend; - } - - /* Return pixel buffer */ - *pixbuf = pixbuf_get ( png->pixbuf ); - - /* Success */ - rc = 0; - - err_iend: - err_chunk: - err_truncated: - pixbuf_put ( png->pixbuf ); - ufree ( png->raw.data ); - free ( png ); - err_alloc: - return rc; -} - -/** - * Probe PNG image - * - * @v image PNG image - * @ret rc Return status code - */ -static int png_probe ( struct image *image ) { - struct png_signature signature; - - /* Sanity check */ - if ( image->len < sizeof ( signature ) ) { - DBGC ( image, "PNG %s is too short\n", image->name ); - return -ENOEXEC; - } - - /* Check signature */ - copy_from_user ( &signature, image->data, 0, sizeof ( signature ) ); - if ( memcmp ( &signature, &png_signature, sizeof ( signature ) ) != 0 ){ - DBGC ( image, "PNG %s has invalid signature\n", image->name ); - return -ENOEXEC; - } - - return 0; -} - -/** PNG image type */ -struct image_type png_image_type __image_type ( PROBE_NORMAL ) = { - .name = "PNG", - .probe = png_probe, - .pixbuf = png_pixbuf, -}; |