summaryrefslogtreecommitdiffstats
path: root/src/libuemf/uwmf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libuemf/uwmf.c')
-rw-r--r--src/libuemf/uwmf.c100
1 files changed, 86 insertions, 14 deletions
diff --git a/src/libuemf/uwmf.c b/src/libuemf/uwmf.c
index b378e587f..35d38f69a 100644
--- a/src/libuemf/uwmf.c
+++ b/src/libuemf/uwmf.c
@@ -19,8 +19,8 @@
/*
File: uwmf.c
-Version: 0.0.15
-Date: 11-APR-2014
+Version: 0.0.16
+Date: 25-MAR-2015
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
Copyright: 2014 David Mathog and California Institute of Technology (Caltech)
@@ -47,6 +47,7 @@ extern "C" {
#endif
#include "uwmf.h"
#include "uwmf_endian.h"
+#include "uemf_safe.h"
/**
\brief Look up the full numeric type of a WMR record by type.
@@ -671,6 +672,51 @@ const char *U_wmr_escnames(int idx){
/* one prototype from uwmf_endian. Put it here because end user should never need to see it, so
not in uemf.h or uwmf_endian.h */
void U_swap2(void *ul, unsigned int count);
+
+/**
+ \brief Check that the bitmap in the specified packed DIB is compatible with the record size
+
+ \return 1 on success, 0 on failure
+ \param record EMF record that contains a DIB pixel array
+ \param blimit one byte past the end of the record.
+
+ This method can only test DIBs that hold Microsoft's various bitmap types. PNG or JPG is just a bag
+ of bytes, and there is no possible way to derive from the known width and height how big it should be.
+
+ This should not be called directly by end user code.
+*/
+int packed_DIB_safe(
+ const char *record,
+ const char *blimit
+ ){
+ int dibparams = U_BI_UNKNOWN; // type of image not yet determined
+ const char *px = NULL; // DIB pixels
+ const U_RGBQUAD *ct = NULL; // DIB color table
+ int bs;
+ int usedbytes;
+
+ if(!bitmapinfo_safe(record, blimit))return(0); // this DIB has issues with colors fitting into the record
+ uint32_t width, height, colortype, numCt, invert; // these values will be set in get_DIB_params
+ // next call returns pointers and values, but allocates no memory
+ dibparams = wget_DIB_params(record, &px, (const U_RGBQUAD **) &ct, &numCt, &width, &height, &colortype, &invert);
+ // sanity checking
+ if(numCt && colortype >= U_BCBM_COLOR16)return(0); //color tables not used above 16 bit pixels
+ if(!numCt && colortype < U_BCBM_COLOR16)return(0); //color tables mandatory for < 16 bit
+
+ if(dibparams ==U_BI_RGB){
+ // this is the only DIB type where we can calculate how big it should be when stored in the WMF file
+ bs = colortype/8;
+ if(bs<1){
+ usedbytes = (width*colortype + 7)/8; // width of line in fully and partially occupied bytes
+ }
+ else {
+ usedbytes = width*bs;
+ }
+ if(IS_MEM_UNSAFE(px, usedbytes, blimit))return(0);
+ }
+ return(1);
+}
+
//! \endcond
/**
@@ -4439,9 +4485,7 @@ size_t U_WMRRECSAFE_get(
memcpy(&Size16, contents + offsetof(U_METARECORD,Size16_4), 4);
size = 2*Size16;
/* Record is not self consistent - described size past the end of WMF in memory */
- if(size < U_SIZE_METARECORD ||
- contents + size - 1 >= blimit ||
- contents + size - 1 < contents)size=0;
+ if(size < U_SIZE_METARECORD || IS_MEM_UNSAFE(contents, size, blimit))size=0;
return(size);
}
@@ -4826,20 +4870,21 @@ int wmfheader_get(
){
uint32_t Key;
int size=0;
- if(!Placeable || !Header || contents + 4 >= blimit)return(0);
+ if(!contents || !Placeable || !Header || !blimit)return(0);
+ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
memcpy(&Key, contents + offsetof(U_WMRPLACEABLE,Key), 4);
if(Key == 0x9AC6CDD7){
size += U_SIZE_WMRPLACEABLE;
- if(contents + size >= blimit)return(0);
+ if(IS_MEM_UNSAFE(contents, size, blimit))return(0);
memcpy(Placeable, contents, U_SIZE_WMRPLACEABLE);
contents += U_SIZE_WMRPLACEABLE;
}
else {
memset(Placeable, 0, U_SIZE_WMRPLACEABLE);
}
- if(contents + size + U_SIZE_WMRHEADER >= blimit)return(0);
+ if(IS_MEM_UNSAFE(contents, size + U_SIZE_WMRHEADER, blimit))return(0);
size += 2* (*(uint16_t *)(contents + offsetof(U_WMRHEADER,Size16w)));
- if(contents + size >= blimit)return(0);
+ if(IS_MEM_UNSAFE(contents, size, blimit))return(0);
memcpy(Header, contents, U_SIZE_WMRHEADER);
return(size);
}
@@ -5512,7 +5557,11 @@ int U_WMRPOLYGON_get(
uint16_t *Length,
const char **Data
){
- return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data);
+ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data);
+ if(size){
+ if(IS_MEM_UNSAFE(*Data, (*Length)*sizeof(U_POINT16), contents+size))return(0);
+ }
+ return size;
}
/**
@@ -5527,7 +5576,11 @@ int U_WMRPOLYLINE_get(
uint16_t *Length,
const char **Data
){
- return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYLINE), NULL, Length, Data);
+ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data);
+ if(size){
+ if(IS_MEM_UNSAFE(*Data, (*Length)*sizeof(U_POINT16), contents+size))return(0);
+ }
+ return size;
}
/**
@@ -5550,7 +5603,11 @@ int U_WMRESCAPE_get(
uint16_t *Length,
const char **Data
){
- return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRESCAPE), Escape, Length, Data);
+ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRESCAPE), Escape, Length, Data);
+ if(size){
+ if(IS_MEM_UNSAFE(*Data, *Length, contents+size))return(0);
+ }
+ return size;
}
/**
@@ -5787,6 +5844,7 @@ int U_WMRSETDIBTODEV_get(
Dst->y = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, yDst ));
Dst->x = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, xDst ));
*dib = ( contents + offsetof(U_WMRSETDIBTODEV, dib ));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
return(size);
}
@@ -5948,6 +6006,7 @@ int U_WMRDIBBITBLT_get(
Dst->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, yDst ));
Dst->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, xDst ));
*dib = ( contents + offsetof(U_WMRDIBBITBLT_PX, dib ));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
}
return(size);
}
@@ -5999,6 +6058,7 @@ int U_WMRDIBSTRETCHBLT_get(
cDst->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, hDst ));
cDst->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, wDst ));
*dib = ( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, dib ));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
}
return(size);
}
@@ -6040,11 +6100,13 @@ int U_WMRDIBCREATEPATTERNBRUSH_get(
if(TmpBm16.Width <= 0 || TmpBm16.Height <= 0 || TmpBm16.Planes != 1 || TmpBm16.BitsPixel == 0){
*Bm16 = NULL;
*dib = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
}
}
else { /* from DIB */
*Bm16 = NULL;
*dib = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
}
return(size);
}
@@ -6085,6 +6147,7 @@ int U_WMRSTRETCHDIB_get(
Dst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, yDst ));
Dst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, xDst ));
*dib = ( contents + offsetof(U_WMRSTRETCHDIB, dib ));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
return(size);
}
@@ -6914,7 +6977,12 @@ int U_WMRCREATEFONTINDIRECT_get(
const char *contents,
const char **font
){
- return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEFONTINDIRECT), NULL, NULL, font);
+ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEFONTINDIRECT), NULL, NULL, font);
+ if(size){
+ if(IS_MEM_UNSAFE(*font, U_SIZE_FONT_CORE, contents+size))return(0);
+ if(contents + size - *font > U_SIZE_FONT_CORE + 32)return(0); // font name must fit in a 32 bit field
+ }
+ return size;
}
/**
@@ -6927,6 +6995,7 @@ int U_WMRCREATEBRUSHINDIRECT_get(
const char *contents,
const char **brush
){
+ // U_SIZE_WMRCREATEBRUSHINDIRECT is everything, no variable part, so the test below is sufficient
return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEBRUSHINDIRECT), NULL, NULL, brush);
}
@@ -6947,16 +7016,19 @@ int U_WMRCREATEBITMAP_get(void){
\return length of the U_WMRCREATEREGION record in bytes, or 0 on error
\param contents record to extract data from
\param Region pointer to U_REGION structure in memory. Pointer may not be aligned properly for structure.
+
+ Caller must check at the returned Region does not extend outside of the record!
*/
int U_WMRCREATEREGION_get(
const char *contents,
const char **Region
){
- return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEREGION), NULL, NULL, Region);
+ return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEREGION), NULL, NULL, Region);
}
+
#ifdef __cplusplus
}
#endif