diff options
Diffstat (limited to 'lib/libpbm2.c')
-rw-r--r-- | lib/libpbm2.c | 146 |
1 files changed, 124 insertions, 22 deletions
diff --git a/lib/libpbm2.c b/lib/libpbm2.c index d04328ef..a8e4b0f6 100644 --- a/lib/libpbm2.c +++ b/lib/libpbm2.c @@ -10,9 +10,12 @@ ** implied warranty. */ +#include <limits.h> + #include "pbm.h" #include "libpbm.h" #include "fileio.h" +#include "pam.h" static bit getbit (FILE * const file) { @@ -54,25 +57,65 @@ pbm_readpbminitrest( file, colsP, rowsP ) pm_error("Number of columns in header is too large."); } + + +static void +validateComputableSize(unsigned int const cols, + unsigned int const rows) { +/*---------------------------------------------------------------------------- + Validate that the dimensions of the image are such that it can be + processed in typical ways on this machine without worrying about + overflows. Note that in C, arithmetic is always modulus + arithmetic, so if your values are too big, the result is not what + you expect. That failed expectation can be disastrous if you use + it to allocate memory. + + A common operation is adding 1 or 2 to the highest row or + column number in the image, so we make sure that's possible. +-----------------------------------------------------------------------------*/ + if (cols > INT_MAX - 2) + pm_error("image width (%u) too large to be processed", cols); + if (rows > INT_MAX - 2) + pm_error("image height (%u) too large to be processed", rows); +} + + + void -pbm_readpbminit( file, colsP, rowsP, formatP ) - FILE* file; - int* colsP; - int* rowsP; - int* formatP; - { - /* Check magic number. */ - *formatP = pm_readmagicnumber( file ); - switch ( PBM_FORMAT_TYPE(*formatP) ) - { - case PBM_TYPE: - pbm_readpbminitrest( file, colsP, rowsP ); - break; +pbm_readpbminit(FILE * const ifP, + int * const colsP, + int * const rowsP, + int * const formatP) { + + *formatP = pm_readmagicnumber(ifP); + + switch (PAM_FORMAT_TYPE(*formatP)) { + case PBM_TYPE: + pbm_readpbminitrest(ifP, colsP, rowsP); + break; + + case PGM_TYPE: + pm_error("The input file is a PGM, not a PBM. You may want to " + "convert it to PBM with 'pamditherbw | pamtopnm' or " + "'pamthreshold | pamtopnm'"); + + case PPM_TYPE: + pm_error("The input file is a PPM, not a PBM. You may want to " + "convert it to PBM with 'ppmtopgm', 'pamditherbw', and " + "'pamtopnm'"); + case PAM_TYPE: + pm_error("The input file is a PAM, not a PBM. " + "If it is a black and white image, you can convert it " + "to PBM with 'pamtopnm'"); + break; default: - pm_error( "bad magic number - not a pbm file" ); - } + pm_error("bad magic number - not a Netpbm file"); } + validateComputableSize(*colsP, *rowsP); +} + + void pbm_readpbmrow( file, bitrow, cols, format ) @@ -114,8 +157,8 @@ pbm_readpbmrow( file, bitrow, cols, format ) void -pbm_readpbmrow_packed(FILE * const file, - unsigned char * const packed_bits, +pbm_readpbmrow_packed(FILE * const fileP, + unsigned char * const packedBits, int const cols, int const format) { @@ -126,22 +169,22 @@ pbm_readpbmrow_packed(FILE * const file, /* We first clear the return buffer, then set ones where needed */ for (byteIndex = 0; byteIndex < pbm_packed_bytes(cols); ++byteIndex) - packed_bits[byteIndex] = 0x00; + packedBits[byteIndex] = 0x00; for (col = 0; col < cols; ++col) { unsigned char mask; - mask = getbit(file) << (7 - col % 8); - packed_bits[col / 8] |= mask; + mask = getbit(fileP) << (7 - col % 8); + packedBits[col / 8] |= mask; } } break; case RPBM_FORMAT: { int bytes_read; - bytes_read = fread(packed_bits, 1, pbm_packed_bytes(cols), file); + bytes_read = fread(packedBits, 1, pbm_packed_bytes(cols), fileP); if (bytes_read < pbm_packed_bytes(cols)) { - if (feof(file)) + if (feof(fileP)) if (bytes_read == 0) pm_error("Attempt to read a raw PBM image row, but " "no more rows left in file."); @@ -160,6 +203,65 @@ pbm_readpbmrow_packed(FILE * const file, +void +pbm_readpbmrow_bitoffset(FILE * const ifP, + unsigned char * const packedBits, + int const cols, + int const format, + unsigned int const offset) { +/*---------------------------------------------------------------------------- + Read PBM packed bitrow from file 'ifP' (raster format given by + 'cols' and 'format') and shift right 'offset' bits. + + Read it into packedBits[], preserving surrounding image data. + + Logic not tested for negative offsets. +-----------------------------------------------------------------------------*/ + unsigned int const rsh = offset % 8; + unsigned int const lsh = (8 - rsh) % 8; + unsigned char * const window = &packedBits[offset/8]; + /* Area of packed row buffer into which we read the image data. + Aligned to nearest byte boundary to the left, so the first + few bits might contain original data, not output. + */ + unsigned int const last = pbm_packed_bytes(cols+rsh) - 1; + /* Position within window of rightmost byte after shift */ + + /* The original leftmost and rightmost chars. */ + unsigned char const origHead = window[0]; + unsigned char const origEnd = window[last]; + + pbm_readpbmrow_packed(ifP, window, cols, format); + + if (rsh > 0) { + /* Target slot doesn't start on byte boundary; right-shift. */ + unsigned char carryover; + unsigned int i; + + carryover = (origHead >> lsh) << lsh; + + for (i = 0; i <= last; ++i) { + unsigned char const t = window[i] << lsh; + window[i] = carryover | window[i] >> rsh; + carryover = t; + } + } + + if ((cols + rsh) % 8 > 0) { + /* Adjust rightmost char */ + unsigned int const trs = (cols + rsh) % 8; + unsigned int const tls = 8 - trs; + unsigned char const rightBits = + ((unsigned char)(origEnd << trs) >> trs); + unsigned char const leftBits = + ((unsigned char)(window[last] >> tls) << tls); + + window[last] = leftBits | rightBits; + } +} + + + bit** pbm_readpbm( file, colsP, rowsP ) FILE* file; |