/**
@file uemf_safe.c
@brief Functions for checking EMF records for memory issues.
EMF records come in a variety of sizes, and some types have variable sizes.
These functions check the record types and report if there are any issues
that could cause a memory access problem. All counts and offsets are examined
and the data structure checked so that no referenced byte is outside of the
declared size of the record.
Many variables are initialized to zero even though they will always be set because
some versions of gcc give spurious "may be used uninitialized" warnings otherwise.
*/
/*
File: uemf_safe.c
Version: 0.0.5
Date: 26-JAN-2016
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h> /* for offsetof() macro */
#include "uemf.h"
#include "uemf_endian.h" // for u_emf_record_sizeok
// hide almost everuything in here from Doxygen
//! \cond
/**
\brief Test a U_EXTLOGPEN object.
\param elp PU_EXTLOGPEN object
\param blimit one byte past the end of the record
*/
int extlogpen_safe(
const char *blimit
){
return(1);
}
/**
\brief Test a U_EMRTEXT record
\param pemt Pointer to a U_EMRTEXT record
\param record Pointer to the start of the record which contains this U_EMRTEXT
\param blimit one byte past the end of the record.
*/
int emrtext_safe(
const char *record,
const char *blimit
){
int off;
if(!(fOptions & U_ETO_NO_RECT)){
}
return(1);
}
/**
\return 1 on success, 0 on failure
\brief Test a U_RGNDATA object.
\param rd pointer to a U_RGNDATA object.
\param cbRgnData size of the U_RGNDATA object.
*/
int rgndata_safe(
int cbRgnData
){
return(1);
}
/**
\return 1 on success, 0 on failure
\brief Test a U_BITMAPINFO object.
\param Bmi pointer to a U_BITMAPINFO object.
\param blimit one byte past the end of the record.
*/
int bitmapinfo_safe(
const char *Bmi,
const char *blimit
){
int ClrUsed;
if(IS_MEM_UNSAFE(Bmi, offsetof(U_BITMAPINFO,bmiHeader) + sizeof(U_BITMAPINFOHEADER), blimit))return(0);
if(ClrUsed && IS_MEM_UNSAFE(Bmi, offsetof(U_BITMAPINFO,bmiColors) + ClrUsed*sizeof(U_RGBQUAD), blimit))return(0);
return(1);
}
/**
\brief Check that the bitmap in the specified 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 iUsage DIBcolors Enumeration
\param offBmi offset from the start of the record to the start of the bitmapinfo structure
\param cbBmi declared space for the bitmapinfo structure in the record
\param offBits offset from the start of the record to the start of the bitmap
\param cbBits declared space for the bitmap in the record (amount used may be less than this)
\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.
*/
int DIB_safe(
const char *record,
const char *blimit
){
int bs;
int usedbytes;
if(iUsage == U_DIB_RGB_COLORS){
// next call returns pointers and values, but allocates no memory
// sanity checking
// this is the only DIB type where we can calculate how big it should be when stored in the EMF file
if(bs<1){
}
else {
}
}
}
return(1);
}
/* **********************************************************************************************
These functions contain shared code used by various U_EMR*_safe functions. These should NEVER be called
by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
These all have this form:
void core1_safe(const char *record){
but some do not actually use torev.
*********************************************************************************************** */
// all core*_safe call this, U_EMRSETMARGN_safe and some others all it directly
// numbered as core5 to be consistent with uemf.c, but must appear before the others as there is no prototype
// sizeof(U_ENHMETARECORD) bytes in the record
return(1);
}
// Functions with the same form starting with U_EMRPOLYBEZIER_safe
return(1);
}
// Functions with the same form starting with U_EMRPOLYPOLYLINE_safe
return(1);
}
// Functions with the same form starting with U_EMRSETMAPMODE_safe
return(1);
}
// Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_safe, also U_EMRFILLPATH_safe,
return(1);
}
// Functions with the same form starting with U_EMRPOLYBEZIER16_safe
return(1);
}
// Records with the same form starting with U_EMRSETWINDOWEXTEX_safe, that is, all with two uint32_t values after the emr
return(1);
}
// For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one
return(1);
}
// Functions that take a rect and a pair of points, starting with U_EMRARC_safe
return(1);
}
// Functions with the same form starting with U_EMRPOLYPOLYLINE16_safe
return(1);
}
// Functions with the same form starting with U_EMRINVERTRGN_safe and U_EMRPAINTRGN_safe,
}
// common code for U_EMRCREATEMONOBRUSH_safe and U_EMRCREATEDIBPATTERNBRUSHPT_safe,
}
// common code for U_EMRALPHABLEND_safe and U_EMRTRANSPARENTBLT_safe,
}
/* **********************************************************************************************
These are the core EMR_safe functions, each converts a particular type of record.
All operate in place on the chunk of memory holding that record.
Some of these have offsets or counts which, if corrupt or evil would result in access outside
the record. These cases return a status value of 0 if that happens, 1 on success. Other
records which do not have these issues do not return a status value.
They are listed in order by the corresponding U_EMR_* index number.
*********************************************************************************************** */
/**
All of the record level (hidden) functions have this form:
\brief Convert a pointer to a U_EMR_whatever record which has not been implemented.
\param record pointer to a buffer holding the EMR record
\param torev 1 for native to reversed, 0 for reversed to native
*/
fprintf(stderr,"EMF WARNING: could not safety check record because that type has not been implemented!\n");
}
// U_EMRHEADER 1
// use _MIN form so that it accepts very old EMF files
}
// U_EMRPOLYBEZIER 2
return(core1_safe(record));
}
// U_EMRPOLYGON 3
return(core1_safe(record));
}
// U_EMRPOLYLINE 4
return(core1_safe(record));
}
// U_EMRPOLYBEZIERTO 5
return(core1_safe(record));
}
// U_EMRPOLYLINETO 6
return(core1_safe(record));
}
// U_EMRPOLYPOLYLINE 7
return(core2_safe(record));
}
// U_EMRPOLYPOLYGON 8
return(core2_safe(record));
}
// U_EMRSETWINDOWEXTEX 9
return(core7_safe(record));
}
// U_EMRSETWINDOWORGEX 10
return(core7_safe(record));
}
// U_EMRSETVIEWPORTEXTEX 11
return(core7_safe(record));
}
// U_EMRSETVIEWPORTORGEX 12
return(core7_safe(record));
}
// U_EMRSETBRUSHORGEX 13
return(core7_safe(record));
}
// U_EMREOF 14
if(cbPalEntries){
if(IS_MEM_UNSAFE(record, pEmr->offPalEntries + 2*2, blimit))return(0);// 2 16 bit values in U_LOGPALLETE
}
return(1);
}
// U_EMRSETPIXELV 15
}
// U_EMRSETMAPPERFLAGS 16
}
// U_EMRSETMAPMODE 17
return(core3_safe(record));
}
// U_EMRSETBKMODE 18
return(core3_safe(record));
}
// U_EMRSETPOLYFILLMODE 19
return(core3_safe(record));
}
// U_EMRSETROP2 20
return(core3_safe(record));
}
// U_EMRSETSTRETCHBLTMODE 21
return(core3_safe(record));
}
// U_EMRSETTEXTALIGN 22
return(core3_safe(record));
}
// U_EMRSETCOLORADJUSTMENT 23
}
// U_EMRSETTEXTCOLOR 24
}
// U_EMRSETBKCOLOR 25
}
// U_EMROFFSETCLIPRGN 26
return(core7_safe(record));
}
// U_EMRMOVETOEX 27
return(core7_safe(record));
}
// U_EMRSETMETARGN 28
}
// U_EMREXCLUDECLIPRECT 29
return(core4_safe(record));
}
// U_EMRINTERSECTCLIPRECT 30
return(core4_safe(record));
}
// U_EMRSCALEVIEWPORTEXTEX 31
return(core4_safe(record));
}
// U_EMRSCALEWINDOWEXTEX 32
return(core4_safe(record));
}
// U_EMRSAVEDC 33
}
// U_EMRRESTOREDC 34
return(core3_safe(record));
}
// U_EMRSETWORLDTRANSFORM 35
}
// U_EMRMODIFYWORLDTRANSFORM 36
}
// U_EMRSELECTOBJECT 37
}
// U_EMRCREATEPEN 38
}
// U_EMRCREATEBRUSHINDIRECT 39
}
// U_EMRDELETEOBJECT 40
}
// U_EMRANGLEARC 41
}
// U_EMRELLIPSE 42
return(core4_safe(record));
}
// U_EMRRECTANGLE 43
return(core4_safe(record));
}
// U_EMRROUNDRECT 44
}
// U_EMRARC 45
return(core9_safe(record));
}
// U_EMRCHORD 46
return(core9_safe(record));
}
// U_EMRPIE 47
return(core9_safe(record));
}
// U_EMRSELECTPALETTE 48
return(core3_safe(record));
}
// U_EMRCREATEPALETTE 49
}
// U_EMRSETPALETTEENTRIES 50
}
// U_EMRRESIZEPALETTE 51
return(core7_safe(record));
}
// U_EMRREALIZEPALETTE 52
}
// U_EMREXTFLOODFILL 53
}
// U_EMRLINETO 54
return(core7_safe(record));
}
// U_EMRARCTO 55
return(core9_safe(record));
}
// U_EMRPOLYDRAW 56
return(1);
}
// U_EMRSETARCDIRECTION 57
return(core3_safe(record));
}
// U_EMRSETMITERLIMIT 58
return(core3_safe(record));
}
// U_EMRBEGINPATH 59
}
// U_EMRENDPATH 60
}
// U_EMRCLOSEFIGURE 61
}
// U_EMRFILLPATH 62
return(core4_safe(record));
}
// U_EMRSTROKEANDFILLPATH 63
return(core4_safe(record));
}
// U_EMRSTROKEPATH 64
return(core4_safe(record));
}
// U_EMRFLATTENPATH 65
}
// U_EMRWIDENPATH 66
}
// U_EMRSELECTCLIPPATH 67
return(core3_safe(record));
}
// U_EMRABORTPATH 68
}
// U_EMRUNDEF69 69
// U_EMRCOMMENT 70 Comment (any binary data, interpretation is program specific)
return(1);
}
// U_EMRFILLRGN 71
}
// U_EMRFRAMERGN 72
}
// U_EMRINVERTRGN 73
return(core11_safe(record));
}
// U_EMRPAINTRGN 74
return(core11_safe(record));
}
// U_EMREXTSELECTCLIPRGN 75
/* data size can be 0 with COPY mode, it means clear the clip region. */
}
// U_EMRBITBLT 76
}
// U_EMRSTRETCHBLT 77
}
// U_EMRMASKBLT 78
}
// U_EMRPLGBLT 79
}
// U_EMRSETDIBITSTODEVICE 80
}
// U_EMRSTRETCHDIBITS 81
}
// U_EMREXTCREATEFONTINDIRECTW 82
/* Panose or logfont, LogFontExDv is not supported. Test smallest to largest */
}
// U_EMREXTTEXTOUTA 83
return(core8_safe(record));
}
// U_EMREXTTEXTOUTW 84
return(core8_safe(record));
}
// U_EMRPOLYBEZIER16 85
/**
\brief Convert a pointer to a U_EMR_POLYBEZIER16 record.
\param record pointer to a buffer holding the EMR record
*/
return(core6_safe(record));
}
// U_EMRPOLYGON16 86
return(core6_safe(record));
}
// U_EMRPOLYLINE16 87
return(core6_safe(record));
}
// U_EMRPOLYBEZIERTO16 88
return(core6_safe(record));
}
// U_EMRPOLYLINETO16 89
/**
\brief Convert a pointer to a U_EMR_POLYLINETO16 record.
\param record pointer to a buffer holding the EMR record
*/
return(core6_safe(record));
}
// U_EMRPOLYPOLYLINE16 90
return(core10_safe(record));
}
// U_EMRPOLYPOLYGON16 91
return(core10_safe(record));
}
// U_EMRPOLYDRAW16 92
return(1);
}
// U_EMRCREATEMONOBRUSH 93
return(core12_safe(record));
}
// U_EMRCREATEDIBPATTERNBRUSHPT_safe 94
return(core12_safe(record));
}
// U_EMREXTCREATEPEN 95
}
// U_EMRPOLYTEXTOUTA 96 NOT IMPLEMENTED, denigrated after Windows NT
// U_EMRPOLYTEXTOUTW 97 NOT IMPLEMENTED, denigrated after Windows NT
// U_EMRSETICMMODE 98
return(core3_safe(record));
}
// U_EMRCREATECOLORSPACE 99
}
// U_EMRSETCOLORSPACE 100
return(core3_safe(record));
}
// U_EMRDELETECOLORSPACE 101
return(core3_safe(record));
}
// U_EMRGLSRECORD 102 Not implemented
// U_EMRGLSBOUNDEDRECORD 103 Not implemented
// U_EMRPIXELFORMAT 104
}
// U_EMRDRAWESCAPE 105 Not implemented
// U_EMREXTESCAPE 106 Not implemented
// U_EMRUNDEF107 107 Not implemented
// U_EMRSMALLTEXTOUT 108
if(!(fuOptions & U_ETO_NO_RECT)){
}
return(1);
}
// U_EMRFORCEUFIMAPPING 109 Not implemented
// U_EMRNAMEDESCAPE 110 Not implemented
// U_EMRCOLORCORRECTPALETTE 111 Not implemented
// U_EMRSETICMPROFILEA 112 Not implemented
// U_EMRSETICMPROFILEW 113 Not implemented
// U_EMRALPHABLEND 114
return(core13_safe(record));
}
// U_EMRSETLAYOUT 115
return(core3_safe(record));
}
// U_EMRTRANSPARENTBLT 116
return(core13_safe(record));
}
// U_EMRUNDEF117 117 Not implemented
// U_EMRGRADIENTFILL 118
if(nGradObj){
if( ulMode == U_GRADIENT_FILL_TRIANGLE){
}
}
}
return(1);
}
// U_EMRSETLINKEDUFIS 119 Not implemented
// U_EMRSETTEXTJUSTIFICATION120 Not implemented (denigrated)
// U_EMRCOLORMATCHTOTARGETW 121 Not implemented
// U_EMRCREATECOLORSPACEW 122
}
//! \endcond
/**
\brief Test an EMF record in memory from Big Endian to Little Endian.
\return 0 on failure, 1 on success
\param record pointer to the EMF record in memory
Normally this would be called immediately after reading a record from a file
and having called U_emf_record_sizeok().
It is NOT safe to call this routine without first calling U_emf_record_sizeok)()!
If the file has been converted from one endian to another calling this routine is
not necessary, because those routines also perform these checks.
*/
if(!record)return(0); // programming error
{
} //end of switch
return(rstatus);
}
#ifdef __cplusplus
}
#endif