iPXE
png.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdint.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <errno.h>
00030 #include <byteswap.h>
00031 #include <ipxe/umalloc.h>
00032 #include <ipxe/pixbuf.h>
00033 #include <ipxe/deflate.h>
00034 #include <ipxe/png.h>
00035 
00036 /** @file
00037  *
00038  * Portable Network Graphics (PNG) format
00039  *
00040  * The PNG format is defined in RFC 2083.
00041  */
00042 
00043 /** PNG context */
00044 struct png_context {
00045         /** Offset within image */
00046         size_t offset;
00047 
00048         /** Pixel buffer */
00049         struct pixel_buffer *pixbuf;
00050 
00051         /** Bit depth */
00052         unsigned int depth;
00053         /** Colour type */
00054         unsigned int colour_type;
00055         /** Number of channels */
00056         unsigned int channels;
00057         /** Number of interlace passes */
00058         unsigned int passes;
00059         /** Palette, in iPXE's pixel buffer format */
00060         uint32_t palette[PNG_PALETTE_COUNT];
00061 
00062         /** Decompression buffer for raw PNG data */
00063         struct deflate_chunk raw;
00064         /** Decompressor */
00065         struct deflate deflate;
00066 };
00067 
00068 /** A PNG interlace pass */
00069 struct png_interlace {
00070         /** Pass number */
00071         unsigned int pass;
00072         /** X starting indent */
00073         unsigned int x_indent;
00074         /** Y starting indent */
00075         unsigned int y_indent;
00076         /** X stride */
00077         unsigned int x_stride;
00078         /** Y stride */
00079         unsigned int y_stride;
00080         /** Width */
00081         unsigned int width;
00082         /** Height */
00083         unsigned int height;
00084 };
00085 
00086 /** PNG file signature */
00087 static struct png_signature png_signature = PNG_SIGNATURE;
00088 
00089 /** Number of interlacing passes */
00090 static uint8_t png_interlace_passes[] = {
00091         [PNG_INTERLACE_NONE] = 1,
00092         [PNG_INTERLACE_ADAM7] = 7,
00093 };
00094 
00095 /**
00096  * Transcribe PNG chunk type name (for debugging)
00097  *
00098  * @v type              Chunk type
00099  * @ret name            Chunk type name
00100  */
00101 static const char * png_type_name ( uint32_t type ) {
00102         static union {
00103                 uint32_t type;
00104                 char name[ sizeof ( uint32_t ) + 1 /* NUL */ ];
00105         } u;
00106 
00107         u.type = type;
00108         return u.name;
00109 }
00110 
00111 /**
00112  * Calculate PNG interlace pass parameters
00113  *
00114  * @v png               PNG context
00115  * @v pass              Pass number (0=first pass)
00116  * @v interlace         Interlace pass to fill in
00117  */
00118 static void png_interlace ( struct png_context *png, unsigned int pass,
00119                             struct png_interlace *interlace ) {
00120         unsigned int grid_width_log2;
00121         unsigned int grid_height_log2;
00122         unsigned int x_indent;
00123         unsigned int y_indent;
00124         unsigned int x_stride_log2;
00125         unsigned int y_stride_log2;
00126         unsigned int x_stride;
00127         unsigned int y_stride;
00128         unsigned int width;
00129         unsigned int height;
00130 
00131         /* Sanity check */
00132         assert ( png->passes > 0 );
00133 
00134         /* Store pass number */
00135         interlace->pass = pass;
00136 
00137         /* Calculate interlace grid dimensions */
00138         grid_width_log2 = ( png->passes / 2 );
00139         grid_height_log2 = ( ( png->passes - 1 ) / 2 );
00140 
00141         /* Calculate starting indents */
00142         interlace->x_indent = x_indent =
00143                 ( ( pass & 1 ) ?
00144                   ( 1 << ( grid_width_log2 - ( pass / 2 ) - 1 ) ) : 0 );
00145         interlace->y_indent = y_indent =
00146                 ( ( pass && ! ( pass & 1 ) ) ?
00147                   ( 1 << ( grid_height_log2 - ( ( pass - 1 ) / 2 ) - 1 ) ) : 0);
00148 
00149         /* Calculate strides */
00150         x_stride_log2 = ( grid_width_log2 - ( pass / 2 ) );
00151         y_stride_log2 =
00152                 ( grid_height_log2 - ( pass ? ( ( pass - 1 ) / 2 ) : 0 ) );
00153         interlace->x_stride = x_stride = ( 1 << x_stride_log2 );
00154         interlace->y_stride = y_stride = ( 1 << y_stride_log2 );
00155 
00156         /* Calculate pass dimensions */
00157         width = png->pixbuf->width;
00158         height = png->pixbuf->height;
00159         interlace->width =
00160                 ( ( width - x_indent + x_stride - 1 ) >> x_stride_log2 );
00161         interlace->height =
00162                 ( ( height - y_indent + y_stride - 1 ) >> y_stride_log2 );
00163 }
00164 
00165 /**
00166  * Calculate PNG pixel length
00167  *
00168  * @v png               PNG context
00169  * @ret pixel_len       Pixel length
00170  */
00171 static unsigned int png_pixel_len ( struct png_context *png ) {
00172 
00173         return ( ( ( png->channels * png->depth ) + 7 ) / 8 );
00174 }
00175 
00176 /**
00177  * Calculate PNG scanline length
00178  *
00179  * @v png               PNG context
00180  * @v interlace         Interlace pass
00181  * @ret scanline_len    Scanline length (including filter byte)
00182  */
00183 static size_t png_scanline_len ( struct png_context *png,
00184                                  struct png_interlace *interlace ) {
00185 
00186         return ( 1 /* Filter byte */ +
00187                  ( ( interlace->width * png->channels * png->depth ) + 7 ) / 8);
00188 }
00189 
00190 /**
00191  * Handle PNG image header chunk
00192  *
00193  * @v image             PNG image
00194  * @v png               PNG context
00195  * @v len               Chunk length
00196  * @ret rc              Return status code
00197  */
00198 static int png_image_header ( struct image *image, struct png_context *png,
00199                               size_t len ) {
00200         struct png_image_header ihdr;
00201         struct png_interlace interlace;
00202         unsigned int pass;
00203 
00204         /* Sanity check */
00205         if ( len != sizeof ( ihdr ) ) {
00206                 DBGC ( image, "PNG %s invalid IHDR length %zd\n",
00207                        image->name, len );
00208                 return -EINVAL;
00209         }
00210         if ( png->pixbuf ) {
00211                 DBGC ( image, "PNG %s duplicate IHDR\n", image->name );
00212                 return -EINVAL;
00213         }
00214 
00215         /* Extract image header */
00216         copy_from_user ( &ihdr, image->data, png->offset, len );
00217         DBGC ( image, "PNG %s %dx%d depth %d type %d compression %d filter %d "
00218                "interlace %d\n", image->name, ntohl ( ihdr.width ),
00219                ntohl ( ihdr.height ), ihdr.depth, ihdr.colour_type,
00220                ihdr.compression, ihdr.filter, ihdr.interlace );
00221 
00222         /* Sanity checks */
00223         if ( ihdr.compression >= PNG_COMPRESSION_UNKNOWN ) {
00224                 DBGC ( image, "PNG %s unknown compression method %d\n",
00225                        image->name, ihdr.compression );
00226                 return -ENOTSUP;
00227         }
00228         if ( ihdr.filter >= PNG_FILTER_UNKNOWN ) {
00229                 DBGC ( image, "PNG %s unknown filter method %d\n",
00230                        image->name, ihdr.filter );
00231                 return -ENOTSUP;
00232         }
00233         if ( ihdr.interlace >= PNG_INTERLACE_UNKNOWN ) {
00234                 DBGC ( image, "PNG %s unknown interlace method %d\n",
00235                        image->name, ihdr.interlace );
00236                 return -ENOTSUP;
00237         }
00238 
00239         /* Allocate pixel buffer */
00240         png->pixbuf = alloc_pixbuf ( ntohl ( ihdr.width ),
00241                                      ntohl ( ihdr.height ) );
00242         if ( ! png->pixbuf ) {
00243                 DBGC ( image, "PNG %s could not allocate pixel buffer\n",
00244                        image->name );
00245                 return -ENOMEM;
00246         }
00247 
00248         /* Extract bit depth */
00249         png->depth = ihdr.depth;
00250         if ( ( png->depth == 0 ) ||
00251              ( ( png->depth & ( png->depth - 1 ) ) != 0 ) ) {
00252                 DBGC ( image, "PNG %s invalid depth %d\n",
00253                        image->name, png->depth );
00254                 return -EINVAL;
00255         }
00256 
00257         /* Calculate number of channels */
00258         png->colour_type = ihdr.colour_type;
00259         png->channels = 1;
00260         if ( ! ( ihdr.colour_type & PNG_COLOUR_TYPE_PALETTE ) ) {
00261                 if ( ihdr.colour_type & PNG_COLOUR_TYPE_RGB )
00262                         png->channels += 2;
00263                 if ( ihdr.colour_type & PNG_COLOUR_TYPE_ALPHA )
00264                         png->channels += 1;
00265         }
00266 
00267         /* Calculate number of interlace passes */
00268         png->passes = png_interlace_passes[ihdr.interlace];
00269 
00270         /* Calculate length of raw data buffer */
00271         for ( pass = 0 ; pass < png->passes ; pass++ ) {
00272                 png_interlace ( png, pass, &interlace );
00273                 if ( interlace.width == 0 )
00274                         continue;
00275                 png->raw.len += ( interlace.height *
00276                                   png_scanline_len ( png, &interlace ) );
00277         }
00278 
00279         /* Allocate raw data buffer */
00280         png->raw.data = umalloc ( png->raw.len );
00281         if ( ! png->raw.data ) {
00282                 DBGC ( image, "PNG %s could not allocate data buffer\n",
00283                        image->name );
00284                 return -ENOMEM;
00285         }
00286 
00287         return 0;
00288 }
00289 
00290 /**
00291  * Handle PNG palette chunk
00292  *
00293  * @v image             PNG image
00294  * @v png               PNG context
00295  * @v len               Chunk length
00296  * @ret rc              Return status code
00297  */
00298 static int png_palette ( struct image *image, struct png_context *png,
00299                          size_t len ) {
00300         size_t offset = png->offset;
00301         struct png_palette_entry palette;
00302         unsigned int i;
00303 
00304         /* Populate palette */
00305         for ( i = 0 ; i < ( sizeof ( png->palette ) /
00306                             sizeof ( png->palette[0] ) ) ; i++ ) {
00307 
00308                 /* Stop when we run out of palette data */
00309                 if ( len < sizeof ( palette ) )
00310                         break;
00311 
00312                 /* Extract palette entry */
00313                 copy_from_user ( &palette, image->data, offset,
00314                                  sizeof ( palette ) );
00315                 png->palette[i] = ( ( palette.red << 16 ) |
00316                                     ( palette.green << 8 ) |
00317                                     ( palette.blue << 0 ) );
00318                 DBGC2 ( image, "PNG %s palette entry %d is %#06x\n",
00319                         image->name, i, png->palette[i] );
00320 
00321                 /* Move to next entry */
00322                 offset += sizeof ( palette );
00323                 len -= sizeof ( palette );
00324         }
00325 
00326         return 0;
00327 }
00328 
00329 /**
00330  * Handle PNG image data chunk
00331  *
00332  * @v image             PNG image
00333  * @v png               PNG context
00334  * @v len               Chunk length
00335  * @ret rc              Return status code
00336  */
00337 static int png_image_data ( struct image *image, struct png_context *png,
00338                             size_t len ) {
00339         struct deflate_chunk in;
00340         int rc;
00341 
00342         /* Deflate this chunk */
00343         deflate_chunk_init ( &in, image->data, png->offset,
00344                              ( png->offset + len ) );
00345         if ( ( rc = deflate_inflate ( &png->deflate, &in, &png->raw ) ) != 0 ) {
00346                 DBGC ( image, "PNG %s could not decompress: %s\n",
00347                        image->name, strerror ( rc ) );
00348                 return rc;
00349         }
00350 
00351         return 0;
00352 }
00353 
00354 /**
00355  * Unfilter byte using the "None" filter
00356  *
00357  * @v current           Filtered current byte
00358  * @v left              Unfiltered left byte
00359  * @v above             Unfiltered above byte
00360  * @v above_left        Unfiltered above-left byte
00361  * @ret current         Unfiltered current byte
00362  */
00363 static unsigned int png_unfilter_none ( unsigned int current,
00364                                         unsigned int left __unused,
00365                                         unsigned int above __unused,
00366                                         unsigned int above_left __unused ) {
00367 
00368         return current;
00369 }
00370 
00371 /**
00372  * Unfilter byte using the "Sub" filter
00373  *
00374  * @v current           Filtered current byte
00375  * @v left              Unfiltered left byte
00376  * @v above             Unfiltered above byte
00377  * @v above_left        Unfiltered above-left byte
00378  * @ret current         Unfiltered current byte
00379  */
00380 static unsigned int png_unfilter_sub ( unsigned int current,
00381                                        unsigned int left,
00382                                        unsigned int above __unused,
00383                                        unsigned int above_left __unused ) {
00384 
00385         return ( current + left );
00386 }
00387 
00388 /**
00389  * Unfilter byte using the "Up" filter
00390  *
00391  * @v current           Filtered current byte
00392  * @v left              Unfiltered left byte
00393  * @v above             Unfiltered above byte
00394  * @v above_left        Unfiltered above-left byte
00395  * @ret current         Unfiltered current byte
00396  */
00397 static unsigned int png_unfilter_up ( unsigned int current,
00398                                       unsigned int left __unused,
00399                                       unsigned int above,
00400                                       unsigned int above_left __unused ) {
00401 
00402         return ( current + above );
00403 }
00404 
00405 /**
00406  * Unfilter byte using the "Average" filter
00407  *
00408  * @v current           Filtered current byte
00409  * @v left              Unfiltered left byte
00410  * @v above             Unfiltered above byte
00411  * @v above_left        Unfiltered above-left byte
00412  * @ret current         Unfiltered current byte
00413  */
00414 static unsigned int png_unfilter_average ( unsigned int current,
00415                                            unsigned int left,
00416                                            unsigned int above,
00417                                            unsigned int above_left __unused ) {
00418 
00419         return ( current + ( ( above + left ) >> 1 ) );
00420 }
00421 
00422 /**
00423  * Paeth predictor function (defined in RFC 2083)
00424  *
00425  * @v a                 Pixel A
00426  * @v b                 Pixel B
00427  * @v c                 Pixel C
00428  * @ret predictor       Predictor pixel
00429  */
00430 static unsigned int png_paeth_predictor ( unsigned int a, unsigned int b,
00431                                           unsigned int c ) {
00432         unsigned int p;
00433         unsigned int pa;
00434         unsigned int pb;
00435         unsigned int pc;
00436 
00437         /* Algorithm as defined in RFC 2083 section 6.6 */
00438         p = ( a + b - c );
00439         pa = abs ( p - a );
00440         pb = abs ( p - b );
00441         pc = abs ( p - c );
00442         if ( ( pa <= pb ) && ( pa <= pc ) ) {
00443                 return a;
00444         } else if ( pb <= pc ) {
00445                 return b;
00446         } else {
00447                 return c;
00448         }
00449 }
00450 
00451 /**
00452  * Unfilter byte using the "Paeth" filter
00453  *
00454  * @v current           Filtered current byte
00455  * @v above_left        Unfiltered above-left byte
00456  * @v above             Unfiltered above byte
00457  * @v left              Unfiltered left byte
00458  * @ret current         Unfiltered current byte
00459  */
00460 static unsigned int png_unfilter_paeth ( unsigned int current,
00461                                          unsigned int left,
00462                                          unsigned int above,
00463                                          unsigned int above_left ) {
00464 
00465         return ( current + png_paeth_predictor ( left, above, above_left ) );
00466 }
00467 
00468 /** A PNG filter */
00469 struct png_filter {
00470         /**
00471          * Unfilter byte
00472          *
00473          * @v current           Filtered current byte
00474          * @v left              Unfiltered left byte
00475          * @v above             Unfiltered above byte
00476          * @v above_left        Unfiltered above-left byte
00477          * @ret current         Unfiltered current byte
00478          */
00479         unsigned int ( * unfilter ) ( unsigned int current,
00480                                       unsigned int left,
00481                                       unsigned int above,
00482                                       unsigned int above_left );
00483 };
00484 
00485 /** PNG filter types */
00486 static struct png_filter png_filters[] = {
00487         [PNG_FILTER_BASIC_NONE] = { png_unfilter_none },
00488         [PNG_FILTER_BASIC_SUB] = { png_unfilter_sub },
00489         [PNG_FILTER_BASIC_UP] = { png_unfilter_up },
00490         [PNG_FILTER_BASIC_AVERAGE] = { png_unfilter_average },
00491         [PNG_FILTER_BASIC_PAETH] = { png_unfilter_paeth },
00492 };
00493 
00494 /**
00495  * Unfilter one interlace pass of PNG raw data
00496  *
00497  * @v image             PNG image
00498  * @v png               PNG context
00499  * @v interlace         Interlace pass
00500  * @ret rc              Return status code
00501  *
00502  * This routine may assume that it is impossible to overrun the raw
00503  * data buffer, since the size is determined by the image dimensions.
00504  */
00505 static int png_unfilter_pass ( struct image *image, struct png_context *png,
00506                                struct png_interlace *interlace ) {
00507         size_t offset = png->raw.offset;
00508         size_t pixel_len = png_pixel_len ( png );
00509         size_t scanline_len = png_scanline_len ( png, interlace );
00510         struct png_filter *filter;
00511         unsigned int scanline;
00512         unsigned int byte;
00513         uint8_t filter_type;
00514         uint8_t left;
00515         uint8_t above;
00516         uint8_t above_left;
00517         uint8_t current;
00518 
00519         /* On the first scanline of a pass, above bytes are assumed to
00520          * be zero.
00521          */
00522         above = 0;
00523 
00524         /* Iterate over each scanline in turn */
00525         for ( scanline = 0 ; scanline < interlace->height ; scanline++ ) {
00526 
00527                 /* Extract filter byte and determine filter type */
00528                 copy_from_user ( &filter_type, png->raw.data, offset++,
00529                                  sizeof ( filter_type ) );
00530                 if ( filter_type >= ( sizeof ( png_filters ) /
00531                                       sizeof ( png_filters[0] ) ) ) {
00532                         DBGC ( image, "PNG %s unknown filter type %d\n",
00533                                image->name, filter_type );
00534                         return -ENOTSUP;
00535                 }
00536                 filter = &png_filters[filter_type];
00537                 assert ( filter->unfilter != NULL );
00538                 DBGC2 ( image, "PNG %s pass %d scanline %d filter type %d\n",
00539                         image->name, interlace->pass, scanline, filter_type );
00540 
00541                 /* At the start of a line, both above-left and left
00542                  * bytes are taken to be zero.
00543                  */
00544                 left = 0;
00545                 above_left = 0;
00546 
00547                 /* Iterate over each byte (not pixel) in turn */
00548                 for ( byte = 0 ; byte < ( scanline_len - 1 ) ; byte++ ) {
00549 
00550                         /* Extract predictor bytes, if applicable */
00551                         if ( byte >= pixel_len ) {
00552                                 copy_from_user ( &left, png->raw.data,
00553                                                  ( offset - pixel_len ),
00554                                                  sizeof ( left ) );
00555                         }
00556                         if ( scanline > 0 ) {
00557                                 copy_from_user ( &above, png->raw.data,
00558                                                  ( offset - scanline_len ),
00559                                                  sizeof ( above ) );
00560                         }
00561                         if ( ( scanline > 0 ) && ( byte >= pixel_len ) ) {
00562                                 copy_from_user ( &above_left, png->raw.data,
00563                                                  ( offset - scanline_len -
00564                                                    pixel_len ),
00565                                                  sizeof ( above_left ) );
00566                         }
00567 
00568                         /* Unfilter current byte */
00569                         copy_from_user ( &current, png->raw.data,
00570                                          offset, sizeof ( current ) );
00571                         current = filter->unfilter ( current, left, above,
00572                                                      above_left );
00573                         copy_to_user ( png->raw.data, offset++,
00574                                        &current, sizeof ( current ) );
00575                 }
00576         }
00577 
00578         /* Update offset */
00579         png->raw.offset = offset;
00580 
00581         return 0;
00582 }
00583 
00584 /**
00585  * Unfilter PNG raw data
00586  *
00587  * @v image             PNG image
00588  * @v png               PNG context
00589  * @ret rc              Return status code
00590  *
00591  * This routine may assume that it is impossible to overrun the raw
00592  * data buffer, since the size is determined by the image dimensions.
00593  */
00594 static int png_unfilter ( struct image *image, struct png_context *png ) {
00595         struct png_interlace interlace;
00596         unsigned int pass;
00597         int rc;
00598 
00599         /* Process each interlace pass */
00600         png->raw.offset = 0;
00601         for ( pass = 0 ; pass < png->passes ; pass++ ) {
00602 
00603                 /* Calculate interlace pass parameters */
00604                 png_interlace ( png, pass, &interlace );
00605 
00606                 /* Skip zero-width rows (which have no filter bytes) */
00607                 if ( interlace.width == 0 )
00608                         continue;
00609 
00610                 /* Unfilter this pass */
00611                 if ( ( rc = png_unfilter_pass ( image, png,
00612                                                 &interlace ) ) != 0 )
00613                         return rc;
00614         }
00615         assert ( png->raw.offset == png->raw.len );
00616 
00617         return 0;
00618 }
00619 
00620 /**
00621  * Calculate PNG pixel component value
00622  *
00623  * @v raw               Raw component value
00624  * @v alpha             Alpha value
00625  * @v max               Maximum raw/alpha value
00626  * @ret value           Component value in range 0-255
00627  */
00628 static inline unsigned int png_pixel ( unsigned int raw, unsigned int alpha,
00629                                        unsigned int max ) {
00630 
00631         /* The basic calculation is 255*(raw/max)*(value/max).  We use
00632          * fixed-point arithmetic (scaling up to the maximum range for
00633          * a 32-bit integer), in order to get the same results for
00634          * alpha blending as the test cases (produced using
00635          * ImageMagick).
00636          */
00637         return ( ( ( ( ( 0xff00 * raw * alpha ) / max ) / max ) + 0x80 ) >> 8 );
00638 }
00639 
00640 /**
00641  * Fill one interlace pass of PNG pixels
00642  *
00643  * @v image             PNG image
00644  * @v png               PNG context
00645  * @v interlace         Interlace pass
00646  *
00647  * This routine may assume that it is impossible to overrun either the
00648  * raw data buffer or the pixel buffer, since the sizes of both are
00649  * determined by the image dimensions.
00650  */
00651 static void png_pixels_pass ( struct image *image,
00652                               struct png_context *png,
00653                               struct png_interlace *interlace ) {
00654         size_t raw_offset = png->raw.offset;
00655         uint8_t channel[png->channels];
00656         int is_indexed = ( png->colour_type & PNG_COLOUR_TYPE_PALETTE );
00657         int is_rgb = ( png->colour_type & PNG_COLOUR_TYPE_RGB );
00658         int has_alpha = ( png->colour_type & PNG_COLOUR_TYPE_ALPHA );
00659         size_t pixbuf_y_offset;
00660         size_t pixbuf_offset;
00661         size_t pixbuf_x_stride;
00662         size_t pixbuf_y_stride;
00663         size_t raw_stride;
00664         unsigned int y;
00665         unsigned int x;
00666         unsigned int c;
00667         unsigned int bits;
00668         unsigned int depth;
00669         unsigned int max;
00670         unsigned int alpha;
00671         unsigned int raw;
00672         unsigned int value;
00673         uint8_t current = 0;
00674         uint32_t pixel;
00675 
00676         /* We only ever use the top byte of 16-bit pixels.  Model this
00677          * as a bit depth of 8 with a stride of more than one.
00678          */
00679         depth = png->depth;
00680         raw_stride = ( ( depth + 7 ) / 8 );
00681         if ( depth > 8 )
00682                 depth = 8;
00683         max = ( ( 1 << depth ) - 1 );
00684 
00685         /* Calculate pixel buffer offset and strides */
00686         pixbuf_y_offset = ( ( ( interlace->y_indent * png->pixbuf->width ) +
00687                               interlace->x_indent ) * sizeof ( pixel ) );
00688         pixbuf_x_stride = ( interlace->x_stride * sizeof ( pixel ) );
00689         pixbuf_y_stride = ( interlace->y_stride * png->pixbuf->width *
00690                             sizeof ( pixel ) );
00691         DBGC2 ( image, "PNG %s pass %d %dx%d at (%d,%d) stride (%d,%d)\n",
00692                 image->name, interlace->pass, interlace->width,
00693                 interlace->height, interlace->x_indent, interlace->y_indent,
00694                 interlace->x_stride, interlace->y_stride );
00695 
00696         /* Iterate over each scanline in turn */
00697         for ( y = 0 ; y < interlace->height ; y++ ) {
00698 
00699                 /* Skip filter byte */
00700                 raw_offset++;
00701 
00702                 /* Iterate over each pixel in turn */
00703                 bits = depth;
00704                 pixbuf_offset = pixbuf_y_offset;
00705                 for ( x = 0 ; x < interlace->width ; x++ ) {
00706 
00707                         /* Extract sample value */
00708                         for ( c = 0 ; c < png->channels ; c++ ) {
00709 
00710                                 /* Get sample value into high bits of current */
00711                                 current <<= depth;
00712                                 bits -= depth;
00713                                 if ( ! bits ) {
00714                                         copy_from_user ( &current,
00715                                                          png->raw.data,
00716                                                          raw_offset,
00717                                                          sizeof ( current ) );
00718                                         raw_offset += raw_stride;
00719                                         bits = 8;
00720                                 }
00721 
00722                                 /* Extract sample value */
00723                                 channel[c] = ( current >> ( 8 - depth ) );
00724                         }
00725 
00726                         /* Convert to native pixel format */
00727                         if ( is_indexed ) {
00728 
00729                                 /* Indexed */
00730                                 pixel = png->palette[channel[0]];
00731 
00732                         } else {
00733 
00734                                 /* Determine alpha value */
00735                                 alpha = ( has_alpha ?
00736                                           channel[ png->channels - 1 ] : max );
00737 
00738                                 /* Convert to RGB value */
00739                                 pixel = 0;
00740                                 for ( c = 0 ; c < 3 ; c++ ) {
00741                                         raw = channel[ is_rgb ? c : 0 ];
00742                                         value = png_pixel ( raw, alpha, max );
00743                                         assert ( value <= 255 );
00744                                         pixel = ( ( pixel << 8 ) | value );
00745                                 }
00746                         }
00747 
00748                         /* Store pixel */
00749                         copy_to_user ( png->pixbuf->data, pixbuf_offset,
00750                                        &pixel, sizeof ( pixel ) );
00751                         pixbuf_offset += pixbuf_x_stride;
00752                 }
00753 
00754                 /* Move to next output row */
00755                 pixbuf_y_offset += pixbuf_y_stride;
00756         }
00757 
00758         /* Update offset */
00759         png->raw.offset = raw_offset;
00760 }
00761 
00762 /**
00763  * Fill PNG pixels
00764  *
00765  * @v image             PNG image
00766  * @v png               PNG context
00767  *
00768  * This routine may assume that it is impossible to overrun either the
00769  * raw data buffer or the pixel buffer, since the sizes of both are
00770  * determined by the image dimensions.
00771  */
00772 static void png_pixels ( struct image *image, struct png_context *png ) {
00773         struct png_interlace interlace;
00774         unsigned int pass;
00775 
00776         /* Process each interlace pass */
00777         png->raw.offset = 0;
00778         for ( pass = 0 ; pass < png->passes ; pass++ ) {
00779 
00780                 /* Calculate interlace pass parameters */
00781                 png_interlace ( png, pass, &interlace );
00782 
00783                 /* Skip zero-width rows (which have no filter bytes) */
00784                 if ( interlace.width == 0 )
00785                         continue;
00786 
00787                 /* Unfilter this pass */
00788                 png_pixels_pass ( image, png, &interlace );
00789         }
00790         assert ( png->raw.offset == png->raw.len );
00791 }
00792 
00793 /**
00794  * Handle PNG image end chunk
00795  *
00796  * @v image             PNG image
00797  * @v png               PNG context
00798  * @v len               Chunk length
00799  * @ret rc              Return status code
00800  */
00801 static int png_image_end ( struct image *image, struct png_context *png,
00802                            size_t len ) {
00803         int rc;
00804 
00805         /* Sanity checks */
00806         if ( len != 0 ) {
00807                 DBGC ( image, "PNG %s invalid IEND length %zd\n",
00808                        image->name, len );
00809                 return -EINVAL;
00810         }
00811         if ( ! png->pixbuf ) {
00812                 DBGC ( image, "PNG %s missing pixel buffer (no IHDR?)\n",
00813                        image->name );
00814                 return -EINVAL;
00815         }
00816         if ( ! deflate_finished ( &png->deflate ) ) {
00817                 DBGC ( image, "PNG %s decompression not complete\n",
00818                        image->name );
00819                 return -EINVAL;
00820         }
00821         if ( png->raw.offset != png->raw.len ) {
00822                 DBGC ( image, "PNG %s incorrect decompressed length (expected "
00823                        "%zd, got %zd)\n", image->name, png->raw.len,
00824                        png->raw.offset );
00825                 return -EINVAL;
00826         }
00827 
00828         /* Unfilter raw data */
00829         if ( ( rc = png_unfilter ( image, png ) ) != 0 )
00830                 return rc;
00831 
00832         /* Fill pixel buffer */
00833         png_pixels ( image, png );
00834 
00835         return 0;
00836 }
00837 
00838 /** A PNG chunk handler */
00839 struct png_chunk_handler {
00840         /** Chunk type */
00841         uint32_t type;
00842         /**
00843          * Handle chunk
00844          *
00845          * @v image             PNG image
00846          * @v png               PNG context
00847          * @v len               Chunk length
00848          * @ret rc              Return status code
00849          */
00850         int ( * handle ) ( struct image *image, struct png_context *png,
00851                            size_t len );
00852 };
00853 
00854 /** PNG chunk handlers */
00855 static struct png_chunk_handler png_chunk_handlers[] = {
00856         { htonl ( PNG_TYPE_IHDR ), png_image_header },
00857         { htonl ( PNG_TYPE_PLTE ), png_palette },
00858         { htonl ( PNG_TYPE_IDAT ), png_image_data },
00859         { htonl ( PNG_TYPE_IEND ), png_image_end },
00860 };
00861 
00862 /**
00863  * Handle PNG chunk
00864  *
00865  * @v image             PNG image
00866  * @v png               PNG context
00867  * @v type              Chunk type
00868  * @v len               Chunk length
00869  * @ret rc              Return status code
00870  */
00871 static int png_chunk ( struct image *image, struct png_context *png,
00872                        uint32_t type, size_t len ) {
00873         struct png_chunk_handler *handler;
00874         unsigned int i;
00875 
00876         DBGC ( image, "PNG %s chunk type %s offset %zd length %zd\n",
00877                image->name, png_type_name ( type ), png->offset, len );
00878 
00879         /* Handle according to chunk type */
00880         for ( i = 0 ; i < ( sizeof ( png_chunk_handlers ) /
00881                             sizeof ( png_chunk_handlers[0] ) ) ; i++ ) {
00882                 handler = &png_chunk_handlers[i];
00883                 if ( handler->type == type )
00884                         return handler->handle ( image, png, len );
00885         }
00886 
00887         /* Fail if unknown chunk type is critical */
00888         if ( ! ( type & htonl ( PNG_CHUNK_ANCILLARY ) ) ) {
00889                 DBGC ( image, "PNG %s unknown critical chunk type %s\n",
00890                        image->name, png_type_name ( type ) );
00891                 return -ENOTSUP;
00892         }
00893 
00894         /* Ignore non-critical unknown chunk types */
00895         return 0;
00896 }
00897 
00898 /**
00899  * Convert PNG image to pixel buffer
00900  *
00901  * @v image             PNG image
00902  * @v pixbuf            Pixel buffer to fill in
00903  * @ret rc              Return status code
00904  */
00905 static int png_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ) {
00906         struct png_context *png;
00907         struct png_chunk_header header;
00908         struct png_chunk_footer footer;
00909         size_t remaining;
00910         size_t chunk_len;
00911         int rc;
00912 
00913         /* Allocate and initialise context */
00914         png = zalloc ( sizeof ( *png ) );
00915         if ( ! png ) {
00916                 rc = -ENOMEM;
00917                 goto err_alloc;
00918         }
00919         png->offset = sizeof ( struct png_signature );
00920         deflate_init ( &png->deflate, DEFLATE_ZLIB );
00921 
00922         /* Process chunks */
00923         do {
00924 
00925                 /* Extract chunk header */
00926                 remaining = ( image->len - png->offset );
00927                 if ( remaining < sizeof ( header ) ) {
00928                         DBGC ( image, "PNG %s truncated chunk header at offset "
00929                                "%zd\n", image->name, png->offset );
00930                         rc = -EINVAL;
00931                         goto err_truncated;
00932                 }
00933                 copy_from_user ( &header, image->data, png->offset,
00934                                  sizeof ( header ) );
00935                 png->offset += sizeof ( header );
00936 
00937                 /* Validate chunk length */
00938                 chunk_len = ntohl ( header.len );
00939                 if ( remaining < ( sizeof ( header ) + chunk_len +
00940                                    sizeof ( footer ) ) ) {
00941                         DBGC ( image, "PNG %s truncated chunk data/footer at "
00942                                "offset %zd\n", image->name, png->offset );
00943                         rc = -EINVAL;
00944                         goto err_truncated;
00945                 }
00946 
00947                 /* Handle chunk */
00948                 if ( ( rc = png_chunk ( image, png, header.type,
00949                                         chunk_len ) ) != 0 )
00950                         goto err_chunk;
00951 
00952                 /* Move to next chunk */
00953                 png->offset += ( chunk_len + sizeof ( footer ) );
00954 
00955         } while ( png->offset < image->len );
00956 
00957         /* Check that we finished with an IEND chunk */
00958         if ( header.type != htonl ( PNG_TYPE_IEND ) ) {
00959                 DBGC ( image, "PNG %s did not finish with IEND\n",
00960                        image->name );
00961                 rc = -EINVAL;
00962                 goto err_iend;
00963         }
00964 
00965         /* Return pixel buffer */
00966         *pixbuf = pixbuf_get ( png->pixbuf );
00967 
00968         /* Success */
00969         rc = 0;
00970 
00971  err_iend:
00972  err_chunk:
00973  err_truncated:
00974         pixbuf_put ( png->pixbuf );
00975         ufree ( png->raw.data );
00976         free ( png );
00977  err_alloc:
00978         return rc;
00979 }
00980 
00981 /**
00982  * Probe PNG image
00983  *
00984  * @v image             PNG image
00985  * @ret rc              Return status code
00986  */
00987 static int png_probe ( struct image *image ) {
00988         struct png_signature signature;
00989 
00990         /* Sanity check */
00991         if ( image->len < sizeof ( signature ) ) {
00992                 DBGC ( image, "PNG %s is too short\n", image->name );
00993                 return -ENOEXEC;
00994         }
00995 
00996         /* Check signature */
00997         copy_from_user ( &signature, image->data, 0, sizeof ( signature ) );
00998         if ( memcmp ( &signature, &png_signature, sizeof ( signature ) ) != 0 ){
00999                 DBGC ( image, "PNG %s has invalid signature\n", image->name );
01000                 return -ENOEXEC;
01001         }
01002 
01003         return 0;
01004 }
01005 
01006 /** PNG image type */
01007 struct image_type png_image_type __image_type ( PROBE_NORMAL ) = {
01008         .name = "PNG",
01009         .probe = png_probe,
01010         .pixbuf = png_pixbuf,
01011 };