LCOV - code coverage report
Current view: top level - source/pintoLib - pinto.c (source / functions) Hit Total Coverage
Test: pinto.info Lines: 456 456 100.0 %
Date: 2014-01-26 Functions: 9 9 100.0 %
Branches: 334 334 100.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            : Copyright (C) 2012-2014 Jeremiah Martell
       3                 :            : All rights reserved.
       4                 :            : 
       5                 :            : Redistribution and use in source and binary forms, with or without modification,
       6                 :            : are permitted provided that the following conditions are met:
       7                 :            : 
       8                 :            :     - Redistributions of source code must retain the above copyright notice,
       9                 :            :       this list of conditions and the following disclaimer.
      10                 :            :     - Redistributions in binary form must reproduce the above copyright notice,
      11                 :            :       this list of conditions and the following disclaimer in the documentation
      12                 :            :       and/or other materials provided with the distribution.
      13                 :            :     - Neither the name of Jeremiah Martell nor the name of GeekHorse nor the
      14                 :            :       name of Pinto nor the names of its contributors may be used to endorse
      15                 :            :       or promote products derived from this software without specific prior
      16                 :            :       written permission.
      17                 :            : 
      18                 :            : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
      19                 :            : ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      20                 :            : WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      21                 :            : DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
      22                 :            : ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      23                 :            : (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      24                 :            : LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
      25                 :            : ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      26                 :            : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      27                 :            : SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      28                 :            : */
      29                 :            : 
      30                 :            : /******************************************************************************/
      31                 :            : /*!
      32                 :            :         \file
      33                 :            :         Encoding and decoding functions.
      34                 :            : */
      35                 :            : #define PINTO_FILE_NUMBER 1
      36                 :            : 
      37                 :            : /******************************************************************************/
      38                 :            : #include "pinto.h"
      39                 :            : #include "pintoInternal.h"
      40                 :            : 
      41                 :            : /******************************************************************************/
      42                 :            : extern const char valueToChar[];
      43                 :            : 
      44                 :            : /******************************************************************************/
      45                 :            : /*!
      46                 :            :         \brief Encodes an image into the Pinto format.
      47                 :            :         \param[in] image The image to be encoded.
      48                 :            :         \param[out] string_A On success, the string that contains the encoded image.
      49                 :            :                 Will be allocated with the pintoHook memory functions. The caller is
      50                 :            :                 responsible for freeing by passing to the pintoHook memory free
      51                 :            :                 function, or its equivalent.
      52                 :            :         \return PINTO_RC
      53                 :            : */
      54                 :     100853 : PINTO_RC pintoImageEncode( const PintoImage *image, char **string_A )
      55                 :            : {
      56                 :            :         /* DATA */
      57                 :     100853 :         PINTO_RC rc = PINTO_RC_SUCCESS;
      58                 :            : 
      59                 :     100853 :         PintoText *newText = NULL;
      60                 :     100853 :         PintoText *newTextDeflated = NULL;
      61                 :     100853 :         u8 *palette = NULL;
      62                 :            : 
      63                 :            :         /* This is the indexed image data.
      64                 :            :            Instead of holding RGB, it holds an index into the palette.
      65                 :            :            The special value -1 is for transparent pixels. */
      66                 :     100853 :         char *indexedData = NULL;
      67                 :            : 
      68                 :     100853 :         s32 color = 0;
      69                 :     100853 :         s32 pixel = 0;
      70                 :            : 
      71                 :     100853 :         s32 colorAmount = 0;
      72                 :     100853 :         s32 colorFound = 0;
      73                 :            : 
      74                 :     100853 :         char needToAddStandardHeader = 1;
      75                 :            : 
      76                 :     100853 :         u8 red = 0;
      77                 :     100853 :         u8 green = 0;
      78                 :     100853 :         u8 blue = 0;
      79                 :            : 
      80                 :     100853 :         char rleState = 0;
      81                 :     100853 :         s32 rleCount = 0;
      82                 :            : 
      83                 :     100853 :         PintoImage *verifyImage = NULL;
      84                 :            : 
      85                 :     100853 :         char *givebackString = NULL;
      86                 :            : 
      87                 :            : 
      88                 :            :         /* PRECOND */
      89         [ +  + ]:     100853 :         ERR_IF( image == NULL, PINTO_RC_ERROR_PRECOND );
      90         [ +  + ]:     100852 :         ERR_IF( string_A == NULL, PINTO_RC_ERROR_PRECOND );
      91         [ +  + ]:     100851 :         ERR_IF( (*string_A) != NULL, PINTO_RC_ERROR_PRECOND );
      92                 :            : 
      93                 :            : 
      94                 :            :         /* CODE */
      95                 :            : 
      96                 :            :         /* check size */
      97         [ +  + ]:     100850 :         ERR_IF_1( image->width  <= 0, PINTO_RC_ERROR_IMAGE_BAD_SIZE, image->width );
      98         [ +  + ]:     100849 :         ERR_IF_1( image->height <= 0, PINTO_RC_ERROR_IMAGE_BAD_SIZE, image->height );
      99                 :            : 
     100         [ +  + ]:     100848 :         ERR_IF_1( image->width  > PINTO_MAX_WIDTH,  PINTO_RC_ERROR_IMAGE_BAD_SIZE, image->width );
     101         [ +  + ]:     100847 :         ERR_IF_1( image->height > PINTO_MAX_HEIGHT, PINTO_RC_ERROR_IMAGE_BAD_SIZE, image->height );
     102                 :            : 
     103                 :            :         /* malloc data, which is the palette-ized version of the image.
     104                 :            :            instead of rgba, it'll hold the index of the color, with -1
     105                 :            :            being a special case of transparent. */
     106         [ +  + ]:     100846 :         PINTO_MALLOC( indexedData, char, image->width * image->height );
     107                 :            : 
     108                 :            :         /* determine palette */
     109         [ +  + ]:     100832 :         PINTO_CALLOC( palette, u8, PINTO_MAX_COLORS * 3 );
     110                 :            : 
     111                 :            :         /* foreach pixel */
     112         [ +  + ]: 1534579252 :         for ( pixel = 0; pixel < ( image->width * image->height ); pixel += 1 )
     113                 :            :         {
     114                 :            :                 /* if alpha is 0, fully transparent, ignore */
     115         [ +  + ]: 1534478437 :                 if ( image->rgba[ ( pixel * 4 ) + 3 ] == 0 )
     116                 :            :                 {
     117                 :            :                         /* mark pixel in data as transparent */
     118                 : 1395381800 :                         indexedData[ pixel ] = -1;
     119                 :            : 
     120                 : 1395381800 :                         continue;
     121                 :            :                 }
     122                 :            : 
     123                 :            :                 /* if alpha is not 255, fully opaque, then it's partially
     124                 :            :                    transparent, and not allowed */
     125         [ +  + ]:  139096637 :                 ERR_IF( image->rgba[ ( pixel * 4 ) + 3 ] != 255, PINTO_RC_ERROR_IMAGE_PARTIAL_TRANSPARENCY );
     126                 :            : 
     127                 :            :                 /* reset colorFound flag */
     128                 :  139096635 :                 colorFound = 0;
     129                 :            : 
     130                 :            :                 /* get the red, green, and blue of the pixel */
     131                 :  139096635 :                 red   = image->rgba[ ( pixel * 4 )     ];
     132                 :  139096635 :                 green = image->rgba[ ( pixel * 4 ) + 1 ];
     133                 :  139096635 :                 blue  = image->rgba[ ( pixel * 4 ) + 2 ];
     134                 :            : 
     135                 :  139096635 :                 red   = PINTO_8_BITS_TO_6_BITS( red   );
     136                 :  139096635 :                 green = PINTO_8_BITS_TO_6_BITS( green );
     137                 :  139096635 :                 blue  = PINTO_8_BITS_TO_6_BITS( blue  );
     138                 :            : 
     139                 :            :                 /* is this color already in our palette? */
     140                 :            : 
     141                 :            :                 /* foreach color */
     142         [ +  + ]:  864222372 :                 for ( color = 0; color < colorAmount; color += 1 )
     143                 :            :                 {
     144                 :            :                         /* does the current pixel match this color? */
     145         [ +  + ]:  864028554 :                         if (    red   == palette[ ( color * 3 )     ]
     146         [ +  + ]:  149958346 :                              && green == palette[ ( color * 3 ) + 1 ]
     147         [ +  + ]:  139158308 :                              && blue  == palette[ ( color * 3 ) + 2 ]
     148                 :            :                            )
     149                 :            :                         {
     150                 :  138902817 :                                 colorFound = 1;
     151                 :  138902817 :                                 break;
     152                 :            :                         }
     153                 :            :                 }
     154                 :            : 
     155                 :            :                 /* if color wasn't found, it's new, so add it to our palette */
     156         [ +  + ]:  139096635 :                 if ( colorFound == 0 )
     157                 :            :                 {
     158                 :            :                         /* make sure we dont go over PINTO_MAX_COLORS */
     159         [ +  + ]:     193818 :                         ERR_IF( colorAmount == PINTO_MAX_COLORS, PINTO_RC_ERROR_IMAGE_TOO_MANY_COLORS );
     160                 :            : 
     161                 :            :                         /* add it to palette */
     162                 :     193817 :                         palette[ ( colorAmount * 3 )     ] = red;
     163                 :     193817 :                         palette[ ( colorAmount * 3 ) + 1 ] = green;
     164                 :     193817 :                         palette[ ( colorAmount * 3 ) + 2 ] = blue;
     165                 :            : 
     166                 :     193817 :                         colorAmount += 1;
     167                 :            :                 }
     168                 :            : 
     169                 :            :                 /* mark this pixel in data */
     170                 :  139096634 :                 indexedData[ pixel ] = color;
     171                 :            :         }
     172                 :            : 
     173                 :            :         /* we've created out palette, now lets start creating the pinto encoding */
     174                 :            : 
     175                 :            :         /* create text */
     176                 :     100815 :         rc = pintoTextInit( &newText );
     177         [ +  + ]:     100815 :         ERR_IF_PASSTHROUGH;
     178                 :            : 
     179                 :            :         /* See if it's a certain image, and we can use a shorter header */
     180         [ +  + ]:     100787 :         if (    colorAmount == 1
     181 [ +  + ][ +  + ]:      37711 :              && palette[ 0 ] == 0 && palette[ 1 ] == 0 && palette[ 2 ] == 0
                 [ +  + ]
     182         [ +  + ]:        606 :              && image->width == image->height
     183                 :            :            )
     184                 :            :         {
     185         [ +  + ]:        515 :                 if ( image->width == 8 )
     186                 :            :                 {
     187                 :         36 :                         rc = pintoTextAddChar( newText, '0' );
     188         [ +  + ]:         36 :                         ERR_IF_PASSTHROUGH;
     189                 :            : 
     190                 :         35 :                         needToAddStandardHeader = 0;
     191                 :            :                 }
     192         [ +  + ]:        514 :                 if ( image->width == 16 )
     193                 :            :                 {
     194                 :         41 :                         rc = pintoTextAddChar( newText, '1' );
     195         [ +  + ]:         41 :                         ERR_IF_PASSTHROUGH;
     196                 :            : 
     197                 :         40 :                         needToAddStandardHeader = 0;
     198                 :            :                 }
     199         [ +  + ]:        473 :                 else if ( image->width == 32 )
     200                 :            :                 {
     201                 :         39 :                         rc = pintoTextAddChar( newText, '2' );
     202         [ +  + ]:         39 :                         ERR_IF_PASSTHROUGH;
     203                 :            : 
     204                 :         38 :                         needToAddStandardHeader = 0;
     205                 :            :                 }
     206         [ +  + ]:        434 :                 else if ( image->width == 64 )
     207                 :            :                 {
     208                 :         35 :                         rc = pintoTextAddChar( newText, '3' );
     209         [ +  + ]:         35 :                         ERR_IF_PASSTHROUGH;
     210                 :            : 
     211                 :         34 :                         needToAddStandardHeader = 0;
     212                 :            :                 }
     213         [ +  + ]:        399 :                 else if ( image->width == 128 )
     214                 :            :                 {
     215                 :         37 :                         rc = pintoTextAddChar( newText, '4' );
     216         [ +  + ]:         37 :                         ERR_IF_PASSTHROUGH;
     217                 :            : 
     218                 :         36 :                         needToAddStandardHeader = 0;
     219                 :            :                 }
     220         [ +  + ]:        362 :                 else if ( image->width == 256 )
     221                 :            :                 {
     222                 :         39 :                         rc = pintoTextAddChar( newText, '5' );
     223         [ +  + ]:         39 :                         ERR_IF_PASSTHROUGH;
     224                 :            : 
     225                 :         38 :                         needToAddStandardHeader = 0;
     226                 :            :                 }
     227         [ +  + ]:        323 :                 else if ( image->width == 512 )
     228                 :            :                 {
     229                 :         35 :                         rc = pintoTextAddChar( newText, '6' );
     230         [ +  + ]:         35 :                         ERR_IF_PASSTHROUGH;
     231                 :            : 
     232                 :         34 :                         needToAddStandardHeader = 0;
     233                 :            :                 }
     234         [ +  + ]:        288 :                 else if ( image->width == 1024 )
     235                 :            :                 {
     236                 :         35 :                         rc = pintoTextAddChar( newText, '7' );
     237         [ +  + ]:         35 :                         ERR_IF_PASSTHROUGH;
     238                 :            : 
     239                 :         34 :                         needToAddStandardHeader = 0;
     240                 :            :                 }
     241         [ +  + ]:        253 :                 else if ( image->width == 2048 )
     242                 :            :                 {
     243                 :         34 :                         rc = pintoTextAddChar( newText, '8' );
     244         [ +  + ]:         34 :                         ERR_IF_PASSTHROUGH;
     245                 :            : 
     246                 :         33 :                         needToAddStandardHeader = 0;
     247                 :            :                 }
     248         [ +  + ]:        219 :                 else if ( image->width == 4096 )
     249                 :            :                 {
     250                 :         37 :                         rc = pintoTextAddChar( newText, '9' );
     251         [ +  + ]:         37 :                         ERR_IF_PASSTHROUGH;
     252                 :            : 
     253                 :         36 :                         needToAddStandardHeader = 0;
     254                 :            :                 }
     255                 :            :         }
     256                 :            : 
     257         [ +  + ]:     100777 :         if ( needToAddStandardHeader )
     258                 :            :         {
     259                 :            :                         /* 'a' means standard header follows */
     260                 :     100419 :                         rc = pintoTextAddChar( newText, 'a' );
     261         [ +  + ]:     100419 :                         ERR_IF_PASSTHROUGH;
     262                 :            : 
     263                 :            :                         /* add width */
     264                 :     100415 :                         rc = pintoTextAddValue( newText, image->width );
     265         [ +  + ]:     100415 :                         ERR_IF_PASSTHROUGH;
     266                 :            : 
     267                 :            :                         /* add height */
     268                 :     100411 :                         rc = pintoTextAddValue( newText, image->height );
     269         [ +  + ]:     100411 :                         ERR_IF_PASSTHROUGH;
     270                 :            : 
     271                 :            :                         /* add colorAmount */
     272                 :     100407 :                         rc = pintoTextAddValue( newText, colorAmount );
     273         [ +  + ]:     100407 :                         ERR_IF_PASSTHROUGH;
     274                 :            : 
     275                 :            :                         /* add colors to palette */
     276         [ +  + ]:     680405 :                         for ( color = 0; color < ( colorAmount * 3 ); color += 1 )
     277                 :            :                         {
     278                 :            :                                 /* divide by 4 because pinto's colors are 6-bit */
     279                 :     580014 :                                 rc = pintoTextAddChar( newText, valueToChar[ palette[ color ] / 4 ] );
     280         [ +  + ]:     580014 :                                 ERR_IF_PASSTHROUGH;
     281                 :            :                         }
     282                 :            :         }
     283                 :            : 
     284                 :            :         /* add RLE data */
     285                 :            : 
     286                 :            :         /* foreach color */
     287         [ +  + ]:     294384 :         for ( color = 0; color < colorAmount; color += 1 )
     288                 :            :         {
     289                 :     193688 :                 rleState = 0;
     290                 :     193688 :                 rleCount = 0;
     291                 :            : 
     292                 :            :                 /* foreach pixel */
     293         [ +  + ]:17899321318 :                 for ( pixel = 0; pixel < ( image->width * image->height ); pixel += 1 )
     294                 :            :                 {
     295                 :            :                         /* if off */
     296         [ +  + ]:17899127669 :                         if ( rleState == 0 )
     297                 :            :                         {
     298                 :            :                                 /* if same color */
     299         [ +  + ]:17735812039 :                                 if ( color == indexedData[ pixel ] )
     300                 :            :                                 {
     301                 :            :                                         /* add rle count */
     302                 :   49865332 :                                         rc = pintoTextAddValue( newText, rleCount );
     303         [ +  + ]:   49865332 :                                         ERR_IF_PASSTHROUGH;
     304                 :            : 
     305                 :            :                                         /* reset rleState and rleCount */
     306                 :   49865312 :                                         rleState = 1;
     307                 :   49865312 :                                         rleCount = 1;
     308                 :            :                                 }
     309                 :            :                                 /* else if different color */
     310                 :            :                                 else
     311                 :            :                                 {
     312                 :17685946707 :                                         rleCount += 1;
     313                 :            :                                 }
     314                 :            :                         }
     315                 :            :                         /* else, on */
     316                 :            :                         else
     317                 :            :                         {
     318                 :            :                                 PARANOID_ERR_IF( rleState != 1 );
     319                 :            : 
     320                 :            :                                 /* if same or higher color */
     321         [ +  + ]:  163315630 :                                 if ( indexedData[ pixel ] >= color )
     322                 :            :                                 {
     323                 :  113473059 :                                         rleCount += 1;
     324                 :            :                                 }
     325                 :            :                                 /* else if lower color */
     326                 :            :                                 else
     327                 :            :                                 {
     328                 :            :                                         /* add rle count */
     329                 :   49842571 :                                         rc = pintoTextAddValue( newText, rleCount );
     330         [ +  + ]:   49842571 :                                         ERR_IF_PASSTHROUGH;
     331                 :            : 
     332                 :   49842552 :                                         rleState = 0;
     333                 :   49842552 :                                         rleCount = 1;
     334                 :            :                                 }
     335                 :            :                         }
     336                 :            : 
     337                 :            :                 } /* end foreach pixel */
     338                 :            : 
     339                 :            :                 /* add '^', which signals end of color */
     340                 :     193649 :                 rc = pintoTextAddChar( newText, '^' );
     341         [ +  + ]:     193649 :                 ERR_IF_PASSTHROUGH;
     342                 :            : 
     343                 :            :         } /* end foreach color */
     344                 :            : 
     345                 :            :         /* deflate */
     346                 :     100696 :         rc = pintoSimpleDeflate( &newText, &newTextDeflated );
     347         [ +  + ]:     100696 :         ERR_IF_PASSTHROUGH;
     348                 :            : 
     349                 :            :         /* get string */
     350                 :     100586 :         pintoTextFreeAndGetString( &newTextDeflated, &givebackString );
     351                 :            : 
     352                 :            :         /* give back */
     353                 :     100586 :         (*string_A) = givebackString;
     354                 :     100586 :         givebackString = NULL;
     355                 :            : 
     356                 :            : 
     357                 :            :         /* CLEANUP */
     358                 :            :         cleanup:
     359                 :            : 
     360                 :     100853 :         pintoHookFree( palette );
     361                 :     100853 :         palette = NULL;
     362                 :            : 
     363                 :     100853 :         pintoHookFree( indexedData );
     364                 :     100853 :         indexedData = NULL;
     365                 :            : 
     366                 :     100853 :         pintoTextFree( &newText );
     367                 :     100853 :         pintoTextFree( &newTextDeflated );
     368                 :            : 
     369                 :     100853 :         pintoImageFree( &verifyImage );
     370                 :            : 
     371                 :     100853 :         pintoHookFree( givebackString );
     372                 :     100853 :         givebackString = NULL;
     373                 :            : 
     374                 :     100853 :         return rc;
     375                 :            : }
     376                 :            : 
     377                 :            : /******************************************************************************/
     378                 :            : /*!
     379                 :            :         \brief Decodes a string into an image.
     380                 :            :         \param[in] string The string to be decoded.
     381                 :            :         \param[out] image_A On success, the decoded image.
     382                 :            :                 Will be allocated with the pintoHook memory functions. The caller is
     383                 :            :                 responsible for freeing by passing the image to the pintoImageFree()
     384                 :            :                 function.
     385                 :            :         \return PINTO_RC
     386                 :            : */
     387                 :     100643 : PINTO_RC pintoImageDecodeString( const char *string, PintoImage **image_A )
     388                 :            : {
     389                 :            :         /* DATA */
     390                 :     100643 :         PINTO_RC rc = PINTO_RC_SUCCESS;
     391                 :            : 
     392                 :     100643 :         PintoText *text = NULL;
     393                 :            : 
     394                 :            : 
     395                 :            :         /* PRECOND */
     396         [ +  + ]:     100643 :         ERR_IF( string == NULL, PINTO_RC_ERROR_PRECOND );
     397         [ +  + ]:     100642 :         ERR_IF( image_A == NULL, PINTO_RC_ERROR_PRECOND );
     398         [ +  + ]:     100641 :         ERR_IF( (*image_A) != NULL, PINTO_RC_ERROR_PRECOND );
     399                 :            : 
     400                 :            : 
     401                 :            :         /* CODE */
     402                 :            :         /* create our text */
     403                 :     100640 :         rc = pintoTextInit( &text );
     404         [ +  + ]:     100640 :         ERR_IF_PASSTHROUGH;
     405                 :            : 
     406                 :            :         /* add string to our pintoText */
     407         [ +  + ]:   10886090 :         while ( (*string) != '\0' )
     408                 :            :         {
     409                 :   10785560 :                 rc = pintoTextAddChar( text, (*string) );
     410         [ +  + ]:   10785560 :                 ERR_IF_PASSTHROUGH;
     411                 :            : 
     412                 :   10785478 :                 string += 1;
     413                 :            :         }
     414                 :            : 
     415                 :            :         /* call the text version */
     416                 :     100530 :         rc = pintoImageDecodeText( &text, image_A );
     417         [ +  + ]:     100530 :         ERR_IF_PASSTHROUGH;
     418                 :            : 
     419                 :            : 
     420                 :            :         /* CLEANUP */
     421                 :            :         cleanup:
     422                 :            : 
     423                 :     100643 :         pintoTextFree( &text );
     424                 :            : 
     425                 :     100643 :         return rc;
     426                 :            : }
     427                 :            : 
     428                 :            : /******************************************************************************/
     429                 :            : /*!
     430                 :            :         \brief Decodes a text into an image.
     431                 :            :         \param[in] text_F The text to be decoded. On success, this will be freed
     432                 :            :                 with the pintoHook memory functions.
     433                 :            :         \param[out] image_A On success, the decoded image.
     434                 :            :                 Will be allocated with the pintoHook memory functions. The caller is
     435                 :            :                 responsible for freeing by passing the image to pintoImageFree().
     436                 :            :         \return PINTO_RC
     437                 :            : */
     438                 :     100534 : PINTO_RC pintoImageDecodeText( PintoText **text_F, PintoImage **image_A )
     439                 :            : {
     440                 :            :         /* DATA */
     441                 :     100534 :         PINTO_RC rc = PINTO_RC_SUCCESS;
     442                 :            : 
     443                 :     100534 :         PintoText *text = NULL;
     444                 :            : 
     445                 :     100534 :         PintoImage *newImage = NULL;
     446                 :            : 
     447                 :     100534 :         char header = 0;
     448                 :            : 
     449                 :     100534 :         s32 colorIndex = 0;
     450                 :     100534 :         s32 i = 0;
     451                 :     100534 :         s32 pixelIndex = 0;
     452                 :            : 
     453                 :     100534 :         char ch = 0;
     454                 :     100534 :         s32 value = 0;
     455                 :            : 
     456                 :     100534 :         s32 width = 0;
     457                 :     100534 :         s32 height = 0;
     458                 :            : 
     459                 :     100534 :         s32 colorAmount = 0;
     460                 :     100534 :         u8 *palette = NULL;
     461                 :            : 
     462                 :     100534 :         char flagOn = 0;
     463                 :            : 
     464                 :            : 
     465                 :            :         /* PRECOND */
     466         [ +  + ]:     100534 :         ERR_IF( text_F == NULL, PINTO_RC_ERROR_PRECOND );
     467         [ +  + ]:     100533 :         ERR_IF( (*text_F) == NULL, PINTO_RC_ERROR_PRECOND );
     468         [ +  + ]:     100532 :         ERR_IF( image_A == NULL, PINTO_RC_ERROR_PRECOND );
     469         [ +  + ]:     100531 :         ERR_IF( (*image_A) != NULL, PINTO_RC_ERROR_PRECOND );
     470                 :            : 
     471                 :            : 
     472                 :            :         /* CODE */
     473                 :            : 
     474                 :            :         /* inflate */
     475                 :     100530 :         rc = pintoSimpleInflate( text_F, &text );
     476         [ +  + ]:     100530 :         ERR_IF_PASSTHROUGH;
     477                 :            : 
     478                 :            :         /* get header */
     479                 :     100411 :         rc = pintoTextGetChar( text, &header );
     480         [ +  + ]:     100411 :         ERR_IF_PASSTHROUGH;
     481                 :            : 
     482                 :            :         /* standard header marker */
     483         [ +  + ]:     100410 :         if ( header == 'a' )
     484                 :            :         {
     485                 :            :                 /* get width */
     486                 :     100261 :                 rc = pintoTextGetValue( text, &width );
     487         [ +  + ]:     100261 :                 ERR_IF_PASSTHROUGH;
     488                 :            : 
     489         [ +  + ]:     100259 :                 ERR_IF_1( width <= 0, PINTO_RC_ERROR_FORMAT_INVALID, width );
     490         [ +  + ]:     100258 :                 ERR_IF_1( width > PINTO_MAX_WIDTH, PINTO_RC_ERROR_FORMAT_INVALID, width );
     491                 :            : 
     492                 :            :                 /* get height */
     493                 :     100257 :                 rc = pintoTextGetValue( text, &height );
     494         [ +  + ]:     100257 :                 ERR_IF_PASSTHROUGH;
     495                 :            : 
     496         [ +  + ]:     100255 :                 ERR_IF_1( height <= 0, PINTO_RC_ERROR_FORMAT_INVALID, height );
     497         [ +  + ]:     100254 :                 ERR_IF_1( height > PINTO_MAX_HEIGHT, PINTO_RC_ERROR_FORMAT_INVALID, height );
     498                 :            : 
     499                 :            :                 /* allocate new image */
     500                 :     100253 :                 rc = pintoImageInit( width, height, &newImage );
     501         [ +  + ]:     100253 :                 ERR_IF_PASSTHROUGH;
     502                 :            : 
     503                 :            :                 /* get number of colors in palette */
     504                 :     100245 :                 rc = pintoTextGetValue( text, &colorAmount );
     505         [ +  + ]:     100245 :                 ERR_IF_PASSTHROUGH;
     506                 :            : 
     507         [ +  + ]:     100243 :                 ERR_IF_1( colorAmount > PINTO_MAX_COLORS, PINTO_RC_ERROR_FORMAT_INVALID, colorAmount );
     508                 :            : 
     509         [ +  + ]:     100242 :                 if ( colorAmount > 0 )
     510                 :            :                 {
     511                 :            :                         /* allocate palette */
     512         [ +  + ]:      99824 :                         PINTO_CALLOC( palette, u8, colorAmount * 3 );
     513                 :            : 
     514                 :            :                         /* read in colors */
     515         [ +  + ]:     679339 :                         for ( colorIndex = 0; colorIndex < ( colorAmount * 3 ); colorIndex += 1 )
     516                 :            :                         {
     517                 :     579525 :                                 value = 0;
     518                 :            : 
     519                 :     579525 :                                 rc = pintoTextUpdateValue( text, &value );
     520         [ +  + ]:     579525 :                                 ERR_IF_PASSTHROUGH;
     521                 :            : 
     522                 :     579519 :                                 palette[ colorIndex ] = PINTO_6_BITS_TO_8_BITS( value );
     523                 :            :                         }
     524                 :            : 
     525                 :            :                 }
     526                 :            :         }
     527                 :            :         /* smaller header */
     528                 :            :         else
     529                 :            :         {
     530         [ +  + ]:        149 :                 if ( header == '0' )
     531                 :            :                 {
     532                 :         14 :                         width = height = 8;
     533                 :            :                 }
     534         [ +  + ]:        135 :                 else if ( header == '1' )
     535                 :            :                 {
     536                 :         19 :                         width = height = 16;
     537                 :            :                 }
     538         [ +  + ]:        116 :                 else if ( header == '2' )
     539                 :            :                 {
     540                 :         17 :                         width = height = 32;
     541                 :            :                 }
     542         [ +  + ]:         99 :                 else if ( header == '3' )
     543                 :            :                 {
     544                 :         13 :                         width = height = 64;
     545                 :            :                 }
     546         [ +  + ]:         86 :                 else if ( header == '4' )
     547                 :            :                 {
     548                 :         15 :                         width = height = 128;
     549                 :            :                 }
     550         [ +  + ]:         71 :                 else if ( header == '5' )
     551                 :            :                 {
     552                 :         17 :                         width = height = 256;
     553                 :            :                 }
     554         [ +  + ]:         54 :                 else if ( header == '6' )
     555                 :            :                 {
     556                 :         13 :                         width = height = 512;
     557                 :            :                 }
     558         [ +  + ]:         41 :                 else if ( header == '7' )
     559                 :            :                 {
     560                 :         13 :                         width = height = 1024;
     561                 :            :                 }
     562         [ +  + ]:         28 :                 else if ( header == '8' )
     563                 :            :                 {
     564                 :         12 :                         width = height = 2048;
     565                 :            :                 }
     566         [ +  + ]:         16 :                 else if ( header == '9' )
     567                 :            :                 {
     568                 :         15 :                         width = height = 4096;
     569                 :            :                 }
     570                 :            :                 else
     571                 :            :                 {
     572                 :          1 :                         ERR_IF_1( 1, PINTO_RC_ERROR_FORMAT_INVALID, header );
     573                 :            :                 }
     574                 :            : 
     575                 :            :                 /* allocate new image */
     576                 :        148 :                 rc = pintoImageInit( width, height, &newImage );
     577         [ +  + ]:        148 :                 ERR_IF_PASSTHROUGH;
     578                 :            : 
     579                 :        128 :                 colorAmount = 1;
     580                 :            : 
     581                 :            :                 /* allocate palette */
     582                 :            :                 /* since this is calloc, our single color will be black, which is
     583                 :            :                    what we want */
     584         [ +  + ]:        128 :                 PINTO_CALLOC( palette, u8, colorAmount * 3 );
     585                 :            :         }
     586                 :            : 
     587                 :            :         /* foreach color */
     588         [ +  + ]:     293618 :         for ( colorIndex = 0; colorIndex < colorAmount; colorIndex += 1 )
     589                 :            :         {
     590                 :     193289 :                 pixelIndex = 0;
     591                 :     193289 :                 flagOn = 0;
     592                 :            : 
     593                 :            :                 /* rle decoding */
     594                 :            :                 while ( 1 )
     595                 :            :                 {
     596                 :            :                         /* peek at current character to see if it's a '^', which
     597                 :            :                            signals end of current color */
     598                 :   99899817 :                         rc = pintoTextPeekChar( text, &ch );
     599         [ +  + ]:   99899817 :                         ERR_IF_PASSTHROUGH;
     600                 :            : 
     601         [ +  + ]:   99899809 :                         if ( ch == '^' )
     602                 :            :                         {
     603                 :            :                                 /* we just peeked, now we must remove it to move
     604                 :            :                                    past it in the text */
     605                 :     193268 :                                 rc = pintoTextGetChar( text, &ch );
     606                 :            :                                 PARANOID_ERR_IF( rc != PINTO_RC_SUCCESS );
     607                 :            : 
     608                 :     193268 :                                 break;
     609                 :            :                         }
     610                 :            : 
     611                 :            :                         /* get the rle value */
     612                 :   99706541 :                         rc = pintoTextGetValue( text, &value );
     613         [ +  + ]:   99706541 :                         ERR_IF_PASSTHROUGH;
     614                 :            : 
     615                 :            :                         /* make sure it doesn't go past end of rgba array */
     616         [ +  + ]:   99706530 :                         ERR_IF( pixelIndex + ( value * 4 ) >= ( width * height * 4 ), PINTO_RC_ERROR_FORMAT_INVALID );
     617                 :            : 
     618                 :            :                         /* if we're in off state, just increment our pixelIndex */
     619         [ +  + ]:   99706528 :                         if ( flagOn == 0 )
     620                 :            :                         {
     621                 :   49864619 :                                 pixelIndex += ( value * 4 );
     622                 :            :                         }
     623                 :            :                         /* else we're in the on state, so draw our run */
     624                 :            :                         else
     625                 :            :                         {
     626         [ +  + ]:  129183993 :                                 for ( i = 0; i < value; i += 1, pixelIndex += 4 )
     627                 :            :                                 {
     628                 :   79342084 :                                         newImage->rgba[ pixelIndex     ] = palette[ ( colorIndex * 3 )     ];
     629                 :   79342084 :                                         newImage->rgba[ pixelIndex + 1 ] = palette[ ( colorIndex * 3 ) + 1 ];
     630                 :   79342084 :                                         newImage->rgba[ pixelIndex + 2 ] = palette[ ( colorIndex * 3 ) + 2 ];
     631                 :   79342084 :                                         newImage->rgba[ pixelIndex + 3 ] = 255;
     632                 :            :                                 }
     633                 :            :                         }
     634                 :            : 
     635                 :            :                         /* switch states */
     636                 :   99706528 :                         flagOn = ( ! flagOn );
     637                 :            : 
     638                 :   99706528 :                 } /* end rle decoding */
     639                 :            : 
     640                 :            :                 /* the last rleValue is implicit,
     641                 :            :                    if we're in on state */
     642         [ +  + ]:     193268 :                 if ( flagOn )
     643                 :            :                 {
     644                 :            :                         /* draw until end of image */
     645         [ +  + ]:   84017920 :                         for ( ; pixelIndex < ( width * height * 4 ); pixelIndex += 4 )
     646                 :            :                         {
     647                 :   83995215 :                                 newImage->rgba[ pixelIndex     ] = palette[ ( colorIndex * 3 )     ];
     648                 :   83995215 :                                 newImage->rgba[ pixelIndex + 1 ] = palette[ ( colorIndex * 3 ) + 1 ];
     649                 :   83995215 :                                 newImage->rgba[ pixelIndex + 2 ] = palette[ ( colorIndex * 3 ) + 2 ];
     650                 :   83995215 :                                 newImage->rgba[ pixelIndex + 3 ] = 255;
     651                 :            :                         }
     652                 :            :                 }
     653                 :            : 
     654                 :            :         } /* end foreach color */
     655                 :            : 
     656                 :            :         /* must be at end of text */
     657         [ +  + ]:     100329 :         ERR_IF( pintoTextAtEnd( text ) == 0, PINTO_RC_ERROR_FORMAT_INVALID );
     658                 :            : 
     659                 :            :         /* give back */
     660                 :     100328 :         (*image_A) = newImage;
     661                 :     100328 :         newImage = NULL;
     662                 :            : 
     663                 :     100328 :         pintoTextFree( text_F );
     664                 :            : 
     665                 :            : 
     666                 :            :         /* CLEANUP */
     667                 :            :         cleanup:
     668                 :            : 
     669                 :     100534 :         pintoHookFree( palette );
     670                 :     100534 :         palette = NULL;
     671                 :            : 
     672                 :     100534 :         pintoTextFree( &text );
     673                 :            : 
     674                 :     100534 :         pintoImageFree( &newImage );
     675                 :            : 
     676                 :     100534 :         return rc;
     677                 :            : }
     678                 :            : 
     679                 :            : /******************************************************************************/
     680                 :            : /*!
     681                 :            :         \brief Allocates a new image that's all transparent.
     682                 :            :         \param[in] width The width of the image.
     683                 :            :         \param[in] height The height of the image.
     684                 :            :         \param[out] image_A On success, the decoded image.
     685                 :            :                 Will be allocated with the pintoHook memory functions. The caller is
     686                 :            :                 responsible for freeing by passing the image to pintoImageFree().
     687                 :            :         \return PINTO_RC
     688                 :            : */
     689                 :     295556 : PINTO_RC pintoImageInit( s32 width, s32 height, PintoImage **image_A )
     690                 :            : {
     691                 :            :         /* DATA */
     692                 :     295556 :         PINTO_RC rc = PINTO_RC_SUCCESS;
     693                 :            : 
     694                 :     295556 :         PintoImage *newImage = NULL;
     695                 :            : 
     696                 :            : 
     697                 :            :         /* PRECOND */
     698 [ +  + ][ +  + ]:     295556 :         ERR_IF_1( width <= 0 || width > PINTO_MAX_WIDTH, PINTO_RC_ERROR_PRECOND, width );
     699 [ +  + ][ +  + ]:     295553 :         ERR_IF_1( height <= 0 || height > PINTO_MAX_HEIGHT, PINTO_RC_ERROR_PRECOND, height );
     700         [ +  + ]:     295550 :         ERR_IF( image_A == NULL, PINTO_RC_ERROR_PRECOND );
     701         [ +  + ]:     295549 :         ERR_IF( (*image_A) != NULL, PINTO_RC_ERROR_PRECOND );
     702                 :            : 
     703                 :            : 
     704                 :            :         /* CODE */
     705                 :            :         /* create our newImage */
     706         [ +  + ]:     295548 :         PINTO_CALLOC( newImage, PintoImage, 1 );
     707                 :            : 
     708                 :            :         /* allocate rgba */
     709         [ +  + ]:     295519 :         PINTO_CALLOC( newImage->rgba, u8, width * height * 4 );
     710                 :            : 
     711                 :     295490 :         newImage->width = width;
     712                 :     295490 :         newImage->height = height;
     713                 :            : 
     714                 :            :         /* give back */
     715                 :     295490 :         (*image_A) = newImage;
     716                 :     295490 :         newImage = NULL;
     717                 :            : 
     718                 :            : 
     719                 :            :         /* CLEANUP */
     720                 :            :         cleanup:
     721                 :            : 
     722                 :     295556 :         pintoHookFree( newImage );
     723                 :     295556 :         newImage = NULL;
     724                 :            : 
     725                 :     295556 :         return rc;
     726                 :            : }
     727                 :            : 
     728                 :            : /******************************************************************************/
     729                 :            : /*!
     730                 :            :         \brief Frees an image.
     731                 :            :         \param[in] image_F The image to be freed. Will be freed with
     732                 :            :                 pintoHookFree(). On return, image_F will be NULL.
     733                 :            :         \return void.
     734                 :            : */
     735                 :     597794 : void pintoImageFree( PintoImage **image_F )
     736                 :            : {
     737                 :            :         /* CODE */
     738 [ +  + ][ +  + ]:     597794 :         if ( image_F == NULL || (*image_F) == NULL )
     739                 :            :         {
     740                 :     302304 :                 return;
     741                 :            :         }
     742                 :            : 
     743                 :     295490 :         pintoHookFree( (*image_F)->rgba );
     744                 :     295490 :         (*image_F)->rgba = NULL;
     745                 :            : 
     746                 :     295490 :         pintoHookFree( (*image_F) );
     747                 :     295490 :         (*image_F) = NULL;
     748                 :            : 
     749                 :     597794 :         return;
     750                 :            : }
     751                 :            : 
     752                 :            : /******************************************************************************/
     753                 :            : /*!
     754                 :            :         \brief Compresses text with a simple version of deflate.
     755                 :            :         \param[in] textToDeflate_F text to be compressed. On success, will be freed.
     756                 :            :         \param[out] text_A On success, will be compressed text.
     757                 :            :                 Will be allocated with the pintoHook memory functions. The caller is
     758                 :            :                 responsible for freeing with pintoTextFree().
     759                 :            :         \return PINTO_RC
     760                 :            : */
     761                 :     100874 : PINTO_RC pintoSimpleDeflate( PintoText **textToDeflate_F, PintoText **text_A )
     762                 :            : {
     763                 :            :         /* DATA */
     764                 :     100874 :         PINTO_RC rc = PINTO_RC_SUCCESS;
     765                 :            : 
     766                 :     100874 :         PintoText *newText = NULL;
     767                 :     100874 :         char *string = NULL;
     768                 :     100874 :         s32 stringLength = 0;
     769                 :            : 
     770                 :     100874 :         s32 i = 0;
     771                 :            : 
     772                 :     100874 :         s32 matchI = 0;
     773                 :     100874 :         s32 matchLength = 0;
     774                 :            : 
     775                 :     100874 :         s32 bestMatchLength = 0;
     776                 :     100874 :         s32 bestMatchDistance = 0;
     777                 :            : 
     778                 :            : 
     779                 :            :         /* CODE */
     780                 :            :         PARANOID_ERR_IF( textToDeflate_F == NULL );
     781                 :            :         PARANOID_ERR_IF( (*textToDeflate_F) == NULL );
     782                 :            :         PARANOID_ERR_IF( text_A == NULL );
     783                 :            :         PARANOID_ERR_IF( (*text_A) != NULL );
     784                 :            : 
     785                 :            :         /* get string length */
     786                 :     100874 :         stringLength = (*textToDeflate_F)->usedSize;
     787                 :            : 
     788                 :            :         /* get string */
     789                 :     100874 :         pintoTextFreeAndGetString( textToDeflate_F, &string );
     790                 :            : 
     791                 :            :         /* create our new text */
     792                 :     100874 :         rc = pintoTextInit( &newText );
     793         [ +  + ]:     100874 :         ERR_IF_PASSTHROUGH;
     794                 :            : 
     795                 :            :         /* go through string */
     796                 :     100842 :         i = 0;
     797                 :            :         /* we go until there's only 4 characters left, since we can only deflate
     798                 :            :            at least 4 characters */
     799         [ +  + ]:    7970921 :         while ( i <= (stringLength - 4) )
     800                 :            :         {
     801                 :            :                 /* reset our length variables */
     802                 :    7870193 :                 matchLength = 0;
     803                 :    7870193 :                 bestMatchLength = 0;
     804                 :            : 
     805                 :            :                 /* set matchI */
     806                 :    7870193 :                 matchI = i - 1;
     807                 :            : 
     808                 :            :                 /* go up to 64 * 64 characters back, finding the best match */
     809 [ +  + ][ +  + ]: 3075444176 :                 while ( matchI >= 0 && ( i - matchI ) < (64 * 64) )
     810                 :            :                 {
     811                 :            :                         /* do at least 4 characters match? */
     812         [ +  + ]: 3067573983 :                         if (    string[ matchI     ] == string[ i     ]
     813         [ +  + ]:  426622182 :                              && string[ matchI + 1 ] == string[ i + 1 ]
     814         [ +  + ]:   70080506 :                              && string[ matchI + 2 ] == string[ i + 2 ]
     815         [ +  + ]:   27304267 :                              && string[ matchI + 3 ] == string[ i + 3 ]
     816                 :            :                            )
     817                 :            :                         {
     818                 :            :                                 /* see how long the match is */
     819                 :            :                                 /* we don't need to worry about going past the end of the string, because
     820                 :            :                                    before we go past the end of the string we won't match the terminating
     821                 :            :                                    '\0' and break out anyway */
     822                 :            :                                 /* we dont need to worry about matchLength becoming larger than we can
     823                 :            :                                    encode, because we only allow PINTO_MAX_WIDTH * PINTO_MAX_HEIGHT
     824                 :            :                                    characters in the string, so the max we'll have to encode is
     825                 :            :                                    ( PINTO_MAX_WIDTH * PINTO_MAX_HEIGHT ) - 1
     826                 :            :                                    which is exactly the max we can encode. (given than the max width
     827                 :            :                                    and height is 4096 and we use 4 64 values in encoding) */
     828                 :   19589857 :                                 matchLength = 4;
     829         [ +  + ]: 4089485479 :                                 while ( string[ matchI + matchLength ] == string[ i + matchLength ] )
     830                 :            :                                 {
     831                 : 4069895622 :                                         matchLength += 1;
     832                 :            :                                 }
     833                 :            : 
     834                 :            :                                 /* is this our best match? */
     835         [ +  + ]:   19589857 :                                 if ( matchLength > bestMatchLength )
     836                 :            :                                 {
     837                 :    3146209 :                                         bestMatchLength = matchLength;
     838                 :    3146209 :                                         bestMatchDistance = i - matchI;
     839                 :            :                                 }
     840                 :            :                         }
     841                 :            : 
     842                 :            :                         /* decrement matchI
     843                 :            :                            try to find match at next spot */
     844                 : 3067573983 :                         matchI -= 1;
     845                 :            :                 }
     846                 :            : 
     847                 :            :                 /*    if no match*/
     848                 :            :                 /* or if best match length was 4 and the distance was farther than 64, then
     849                 :            :                       the match is 4 characters and the encoding will be 4 characters, so there
     850                 :            :                       is no point deflating. */
     851         [ +  + ]:    7870193 :                 if (    bestMatchLength == 0
     852 [ +  + ][ +  + ]:    1274771 :                      || ( bestMatchLength == 4 && bestMatchDistance >= 64 )
     853                 :            :                    )
     854                 :            :                 {
     855                 :    6679521 :                         rc = pintoTextAddChar( newText, string[ i ] );
     856         [ +  + ]:    6679521 :                         ERR_IF_PASSTHROUGH;
     857                 :            : 
     858                 :            :                         /* increment i */
     859                 :    6679417 :                         i += 1;
     860                 :            :                 }
     861                 :            :                 /* there was a match */
     862                 :            :                 else
     863                 :            :                 {
     864         [ +  + ]:    1190672 :                         if ( bestMatchDistance < 64 )
     865                 :            :                         {
     866                 :    1079275 :                                 rc = pintoTextAddChar( newText, '?' );
     867         [ +  + ]:    1079275 :                                 ERR_IF_PASSTHROUGH;
     868                 :            : 
     869                 :    1079273 :                                 rc = pintoTextAddValue( newText, bestMatchDistance );
     870         [ +  + ]:    1079273 :                                 ERR_IF_PASSTHROUGH;
     871                 :            : 
     872                 :    1079271 :                                 rc = pintoTextAddValue( newText, bestMatchLength );
     873         [ +  + ]:    1079271 :                                 ERR_IF_PASSTHROUGH;
     874                 :            :                         }
     875                 :            :                         else
     876                 :            :                         {
     877                 :            :                                 PARANOID_ERR_IF( bestMatchDistance >= ( 64 * 64 ) );
     878                 :            : 
     879                 :     111397 :                                 rc = pintoTextAddChar( newText, '@' );
     880         [ +  + ]:     111397 :                                 ERR_IF_PASSTHROUGH;
     881                 :            : 
     882                 :     111396 :                                 rc = pintoTextAddChar( newText, valueToChar[ ( (bestMatchDistance) / 64 ) % 64 ] );
     883         [ +  + ]:     111396 :                                 ERR_IF_PASSTHROUGH;
     884                 :            : 
     885                 :     111395 :                                 rc = pintoTextAddChar( newText, valueToChar[   (bestMatchDistance)        % 64 ] );
     886         [ +  + ]:     111395 :                                 ERR_IF_PASSTHROUGH;
     887                 :            : 
     888                 :     111394 :                                 rc = pintoTextAddValue( newText, bestMatchLength );
     889         [ +  + ]:     111394 :                                 ERR_IF_PASSTHROUGH;
     890                 :            :                         }
     891                 :            : 
     892                 :            :                         /* increment i */
     893                 :    1190662 :                         i += bestMatchLength;
     894                 :            :                 }
     895                 :            :         }
     896                 :            : 
     897                 :            :         /* add rest of string to newText */
     898         [ +  + ]:     373824 :         while ( i < stringLength )
     899                 :            :         {
     900                 :     273136 :                 rc = pintoTextAddChar( newText, string[ i ] );
     901         [ +  + ]:     273136 :                 ERR_IF_PASSTHROUGH;
     902                 :            : 
     903                 :            :                 /* *** */
     904                 :     273096 :                 i += 1;
     905                 :            :         }
     906                 :            : 
     907                 :            :         /* free textToDeflate */
     908                 :     100688 :         pintoTextFree( textToDeflate_F );
     909                 :            : 
     910                 :            :         /* give back */
     911                 :     100688 :         (*text_A) = newText;
     912                 :     100688 :         newText = NULL;
     913                 :            : 
     914                 :            : 
     915                 :            :         /* CLEANUP */
     916                 :            :         cleanup:
     917                 :            : 
     918                 :     100874 :         pintoTextFree( &newText );
     919                 :            : 
     920                 :     100874 :         pintoHookFree( string );
     921                 :     100874 :         string = NULL;
     922                 :            : 
     923                 :     100874 :         return rc;
     924                 :            : }
     925                 :            : 
     926                 :            : /******************************************************************************/
     927                 :            : /*!
     928                 :            :         \brief Uncompresses text with a simple version of deflate (inflate here).
     929                 :            :         \param[in] textToDeflate_F text to be uncompressed. On success, will be freed.
     930                 :            :         \param[out] text_A On success, will be uncompressed text.
     931                 :            :                 Will be allocated with the pintoHook memory functions. The caller is
     932                 :            :                 responsible for freeing with pintoTextFree().
     933                 :            :         \return PINTO_RC
     934                 :            : */
     935                 :     100634 : PINTO_RC pintoSimpleInflate( PintoText **textToInflate_F, PintoText **text_A )
     936                 :            : {
     937                 :            :         /* DATA */
     938                 :     100634 :         PINTO_RC rc = PINTO_RC_SUCCESS;
     939                 :            : 
     940                 :     100634 :         PintoText *newText = NULL;
     941                 :            : 
     942                 :     100634 :         char ch = 0;
     943                 :            : 
     944                 :     100634 :         s32 distance = 0;
     945                 :     100634 :         s32 length = 0;
     946                 :            : 
     947                 :            : 
     948                 :            :         /* CODE */
     949                 :            :         PARANOID_ERR_IF( textToInflate_F == NULL );
     950                 :            :         PARANOID_ERR_IF( (*textToInflate_F) == NULL );
     951                 :            :         PARANOID_ERR_IF( text_A == NULL );
     952                 :            :         PARANOID_ERR_IF( (*text_A) != NULL );
     953                 :            : 
     954                 :            :         /* create our new text */
     955                 :     100634 :         rc = pintoTextInit( &newText );
     956         [ +  + ]:     100634 :         ERR_IF_PASSTHROUGH;
     957                 :            : 
     958                 :            :         /* go through string, inflating */
     959                 :            :         while ( 1 )
     960                 :            :         {
     961                 :            :                 /* is there another char to get? */
     962         [ +  + ]:    8238288 :                 if ( pintoTextAtEnd( (*textToInflate_F) ) )
     963                 :            :                 {
     964                 :     100443 :                         break;
     965                 :            :                 }
     966                 :            : 
     967                 :            :                 /* get next char */
     968                 :    8137845 :                 pintoTextGetChar( (*textToInflate_F), &ch );
     969                 :            :                 /* since we just called pintoTextAtEnd there is guaranteed to be a char to get.
     970                 :            :                    so no need to check for error
     971                 :            :                 */
     972                 :            : 
     973                 :            :                 /* '?' is used for distances 1-63 */
     974         [ +  + ]:    8137845 :                 if ( ch == '?' )
     975                 :            :                 {
     976                 :            :                         /* get distance */
     977                 :    1079248 :                         distance = 0;
     978                 :            : 
     979                 :    1079248 :                         rc = pintoTextUpdateValue( (*textToInflate_F), &distance );
     980         [ +  + ]:    1079248 :                         ERR_IF_PASSTHROUGH;
     981                 :            : 
     982                 :            :                         /* get length */
     983                 :    1079247 :                         rc = pintoTextGetValue( (*textToInflate_F), &length );
     984         [ +  + ]:    1079247 :                         ERR_IF_PASSTHROUGH;
     985                 :            : 
     986                 :            :                         /* inflate */
     987                 :    1079246 :                         rc = pintoTextInflateHelper( newText, distance, length );
     988         [ +  + ]:    1079246 :                         ERR_IF_PASSTHROUGH;
     989                 :            :                 }
     990                 :            :                 /* '@' is used for distances 64-4095 */
     991         [ +  + ]:    7058597 :                 else if ( ch == '@' )
     992                 :            :                 {
     993                 :            :                         /* get distance */
     994                 :     111333 :                         distance = 0;
     995                 :            : 
     996                 :     111333 :                         rc = pintoTextUpdateValue( (*textToInflate_F), &distance );
     997         [ +  + ]:     111333 :                         ERR_IF_PASSTHROUGH;
     998                 :     111332 :                         rc = pintoTextUpdateValue( (*textToInflate_F), &distance );
     999         [ +  + ]:     111332 :                         ERR_IF_PASSTHROUGH;
    1000                 :            : 
    1001                 :            :                         /* get length */
    1002                 :     111331 :                         rc = pintoTextGetValue( (*textToInflate_F), &length );
    1003         [ +  + ]:     111331 :                         ERR_IF_PASSTHROUGH;
    1004                 :            : 
    1005                 :            :                         /* inflate */
    1006                 :     111330 :                         rc = pintoTextInflateHelper( newText, distance, length );
    1007         [ +  + ]:     111330 :                         ERR_IF_PASSTHROUGH;
    1008                 :            :                 }
    1009                 :            :                 /* no inflate marker, just add char */
    1010                 :            :                 else
    1011                 :            :                 {
    1012                 :    6947264 :                         rc = pintoTextAddChar( newText, ch );
    1013         [ +  + ]:    6947264 :                         ERR_IF_PASSTHROUGH;
    1014                 :            :                 }
    1015                 :    8137686 :         }
    1016                 :            : 
    1017                 :     100443 :         pintoTextFree( textToInflate_F );
    1018                 :            : 
    1019                 :            :         /* give back */
    1020                 :     100443 :         (*text_A) = newText;
    1021                 :     100443 :         newText = NULL;
    1022                 :            : 
    1023                 :            : 
    1024                 :            :         /* CLEANUP */
    1025                 :            :         cleanup:
    1026                 :            : 
    1027                 :     100634 :         pintoTextFree( &newText );
    1028                 :            : 
    1029                 :     100634 :         return rc;
    1030                 :            : }
    1031                 :            : 
    1032                 :            : /******************************************************************************/
    1033                 :            : /*!
    1034                 :            :         \brief Creates a new image half the size.
    1035                 :            :         \param[in] imageIn The original image.
    1036                 :            :         \param[out] imageOut_A On success, a new image half the size of the original
    1037                 :            :                 image.
    1038                 :            :         \return PINTO_RC
    1039                 :            : 
    1040                 :            :         Used to create anti-aliased images.
    1041                 :            : */
    1042                 :      94274 : PINTO_RC pintoImageDownsize( PintoImage *imageIn, PintoImage **imageOut_A )
    1043                 :            : {
    1044                 :            :         /* DATA */
    1045                 :      94274 :         PINTO_RC rc = PINTO_RC_SUCCESS;
    1046                 :            : 
    1047                 :      94274 :         PintoImage *newImage = NULL;
    1048                 :            : 
    1049                 :      94274 :         s32 width = 0;
    1050                 :      94274 :         s32 height = 0;
    1051                 :            : 
    1052                 :      94274 :         s32 x = 0;
    1053                 :      94274 :         s32 y = 0;
    1054                 :      94274 :         s32 newX = 0;
    1055                 :      94274 :         s32 newY = 0;
    1056                 :            : 
    1057                 :      94274 :         s32 avg = 0;
    1058                 :            : 
    1059                 :            : 
    1060                 :            :         /* PRECOND */
    1061         [ +  + ]:      94274 :         ERR_IF( imageIn == NULL, PINTO_RC_ERROR_PRECOND );
    1062         [ +  + ]:      94273 :         ERR_IF( imageOut_A == NULL, PINTO_RC_ERROR_PRECOND );
    1063         [ +  + ]:      94272 :         ERR_IF( (*imageOut_A) != NULL, PINTO_RC_ERROR_PRECOND );
    1064                 :            : 
    1065                 :            : 
    1066                 :            :         /* CODE */
    1067                 :      94271 :         width = imageIn->width;
    1068                 :      94271 :         height = imageIn->height;
    1069                 :            : 
    1070                 :            :         /* if odd, round down */
    1071                 :      94271 :         width = width & (~((s32)1));
    1072                 :      94271 :         height = height & (~((s32)1));
    1073                 :            : 
    1074         [ +  + ]:      94271 :         ERR_IF( width == 0, PINTO_RC_ERROR_IMAGE_TOO_SMALL );
    1075         [ +  + ]:      94270 :         ERR_IF( height == 0, PINTO_RC_ERROR_IMAGE_TOO_SMALL );
    1076                 :            : 
    1077                 :            :         /* create new image at half size */
    1078                 :      94269 :         rc = pintoImageInit( width / 2, height / 2, &newImage );
    1079         [ +  + ]:      94269 :         ERR_IF_PASSTHROUGH;
    1080                 :            : 
    1081                 :            :         /* do the downsize */
    1082                 :      94267 :         x = 0;
    1083                 :      94267 :         newX = 0;
    1084         [ +  + ]:    1072487 :         while ( x < width )
    1085                 :            :         {
    1086                 :     978220 :                 y = 0;
    1087                 :     978220 :                 newY = 0;
    1088         [ +  + ]:  202385154 :                 while ( y < height )
    1089                 :            :                 {
    1090                 :            :                         /* red */
    1091                 :  201406934 :                         avg = 0;
    1092                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 0 ) * 4 ) ];
    1093                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 1 ) * 4 ) ];
    1094                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 0 ) * 4 ) ];
    1095                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 1 ) * 4 ) ];
    1096                 :  201406934 :                         avg /= 4;
    1097                 :  201406934 :                         newImage->rgba[ ( newY * (width / 2) * 4 ) + ( newX * 4 ) ] = avg;
    1098                 :            : 
    1099                 :            :                         /* green */
    1100                 :  201406934 :                         avg = 0;
    1101                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 1 ];
    1102                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 1 ];
    1103                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 1 ];
    1104                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 1 ];
    1105                 :  201406934 :                         avg /= 4;
    1106                 :  201406934 :                         newImage->rgba[ ( newY * (width / 2) * 4 ) + ( newX * 4 ) + 1 ] = avg;
    1107                 :            : 
    1108                 :            :                         /* blue */
    1109                 :  201406934 :                         avg = 0;
    1110                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 2 ];
    1111                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 2 ];
    1112                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 2 ];
    1113                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 2 ];
    1114                 :  201406934 :                         avg /= 4;
    1115                 :  201406934 :                         newImage->rgba[ ( newY * (width / 2) * 4 ) + ( newX * 4 ) + 2 ] = avg;
    1116                 :            : 
    1117                 :            :                         /* alpha */
    1118                 :  201406934 :                         avg = 0;
    1119                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 3 ];
    1120                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 3 ];
    1121                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 3 ];
    1122                 :  201406934 :                         avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 3 ];
    1123                 :  201406934 :                         avg /= 4;
    1124                 :  201406934 :                         newImage->rgba[ ( newY * (width / 2) * 4 ) + ( newX * 4 ) + 3 ] = avg;
    1125                 :            : 
    1126                 :            :                         /* increment */
    1127                 :  201406934 :                         y += 2;
    1128                 :  201406934 :                         newY += 1;
    1129                 :            :                 }
    1130                 :            : 
    1131                 :            :                 /* increment */
    1132                 :     978220 :                 x += 2;
    1133                 :     978220 :                 newX += 1;
    1134                 :            :         }
    1135                 :            : 
    1136                 :            : 
    1137                 :            :         /* give back */
    1138                 :      94267 :         (*imageOut_A) = newImage;
    1139                 :      94267 :         newImage = NULL;
    1140                 :            : 
    1141                 :            : 
    1142                 :            :         /* CLEANUP */
    1143                 :            :         cleanup:
    1144                 :            : 
    1145                 :      94274 :         pintoImageFree( &newImage );
    1146                 :            : 
    1147                 :      94274 :         return rc;
    1148                 :            : }
    1149                 :            : 
    1150                 :            : /******************************************************************************/
    1151                 :            : /*!
    1152                 :            :         \brief Provides a const char string representation for a PINTO_RC
    1153                 :            :         \param[in] rc A PINTO_RC value.
    1154                 :            :         \return A const char representation of the passed in PINTO_RC.
    1155                 :            : */
    1156                 :       2942 : const char *pintoRCToString( PINTO_RC rc )
    1157                 :            : {
    1158                 :            :         static const char *_rcStrings[] =
    1159                 :            :         {
    1160                 :            :                 "Success",
    1161                 :            : 
    1162                 :            :                 "Precondition Error",
    1163                 :            :                 "Memory Allocation Error",
    1164                 :            :                 "Standard Library Error",
    1165                 :            : 
    1166                 :            :                 "Image Bad Size Error",
    1167                 :            :                 "Image Too Many Colors Error",
    1168                 :            :                 "Image Partial Transparency Error",
    1169                 :            :                 "Image Too Small Error",
    1170                 :            :                 "Format Invalid Error",
    1171                 :            :                 "Format Too Long Error"
    1172                 :            :         };
    1173                 :            : 
    1174                 :            :         static const char *_rcUnknown = "Unknown Error";
    1175                 :            : 
    1176 [ +  + ][ +  + ]:       2942 :         if ( rc >= 0 && rc <= PINTO_RC_STANDARD_ERRORS_MAX )
    1177                 :            :         {
    1178                 :       2749 :                 return _rcStrings[ rc ];
    1179                 :            :         }
    1180 [ +  + ][ +  + ]:        193 :         else if ( rc >= PINTO_RC_PINTO_ERRORS_MIN && rc <= PINTO_RC_PINTO_ERRORS_MAX )
    1181                 :            :         {
    1182                 :        188 :                 return _rcStrings[ PINTO_RC_STANDARD_ERRORS_MAX + rc - PINTO_RC_PINTO_ERRORS_MIN + 1 ];
    1183                 :            :         }
    1184                 :            : 
    1185                 :       2942 :         return _rcUnknown;
    1186                 :            : }
    1187                 :            : 

Generated by: LCOV version 1.9