Browse Source

- renamed checkit/ checkit_tiff/ to prepare repos split

tags/v0.1.0-beta
Andreas Romeyke 3 years ago
commit
a97a47d0f1
33 changed files with 5977 additions and 0 deletions
  1. +2
    -0
      BUGS
  2. +39
    -0
      FAQ
  3. +81
    -0
      Makefile
  4. +62
    -0
      README.1st
  5. +14
    -0
      README.TIFFspecification
  6. +50
    -0
      README.grammar
  7. +13
    -0
      README.regex
  8. +7
    -0
      TODO
  9. +77
    -0
      check.h
  10. +718
    -0
      check_helper.c
  11. +31
    -0
      check_helper.h
  12. +156
    -0
      check_ifd.c
  13. +202
    -0
      checkit_tiff.c
  14. +1817
    -0
      config_dsl.grammar.c
  15. +107
    -0
      config_dsl.grammar.peg
  16. +905
    -0
      config_parser.c
  17. +123
    -0
      config_parser.h
  18. +185
    -0
      example_configs/cit_tiff-a_whitepaper.cfg
  19. +200
    -0
      example_configs/cit_tiff6_baseline_SLUB.cfg
  20. +200
    -0
      example_configs/cit_tiff6_baseline_SLUBrelaxed.cfg
  21. +200
    -0
      example_configs/cit_tiff6_legacy_SLUB.cfg
  22. +54
    -0
      example_configs/cit_tiff_baseline_minimal.cfg
  23. +99
    -0
      tagrules/check_datetime.c
  24. +59
    -0
      tagrules/check_tag.c
  25. +80
    -0
      tagrules/check_tag_has_some_of_these_values.c
  26. +48
    -0
      tagrules/check_tag_has_valid_asciivalue.c
  27. +97
    -0
      tagrules/check_tag_has_valid_type.c
  28. +210
    -0
      tagrules/check_tag_has_value.c
  29. +83
    -0
      tagrules/check_tag_has_value_in_range.c
  30. +36
    -0
      test.c
  31. BIN
      tiffs_should_fail/wrong_subfile_type__wrong_xresolution_alignment.tif
  32. BIN
      tiffs_should_pass/minimal_valid.tiff
  33. +22
    -0
      version.mk

+ 2
- 0
BUGS View File

@@ -0,0 +1,2 @@
* parser could not handle valuedata yet (use ANY as workaround)


+ 39
- 0
FAQ View File

@@ -0,0 +1,39 @@
Q: I got "fatal error: tiff.h: No such file or directory"
A: You need an installed libtiff (Debian Jessie: libtiff5-dev)

Q: "make" reports "usage: git rev-list [OPTION] …"
A: the Makefile uses version.mk to build a version information for the tool.
In that case you should comment out the lines in version.mk and set
REPO_REVISION manually

Q: I did not have "peg" and my config_dsl.grammar.c has zero size and there are
compile errors.
A: remove that file and use "git checkout config_dsl.grammar.c" to restore it
from repository. Try to avoid "make distclean", because it erases the file.

Q: My C-compiler reports error-messages like "cc: error: unrecognized command
line option '-fsanitze=undefined'"
A: You use an older GCC variant. Try 'SANITIZE="" make'

Q: The compiler reports, that the function TIFFFiledName does not exists. What
is the reason?
A: You use an older version of the libtiff. If you cannot update, try this:
'CFLAGS="-DOLDTIFF" make', this enables an alternative in check_helper.c

Q: How can I compile a windows version of your program?
A: I have only tested creating Windows executables using the crosscompiler
minGW under Debian Jessie, please see the instructions in
the ../README.windows file.

Q: I tried to compile with 'SANITIZE="-DOLDTIFF" make' under Debian Wheezy,
but I got the message "error: expected specifier-qualifier-list before
'uint64'", why?
A: You are using the Debian-package libtiff4-dev, but at least libtiff5-dev is
expected. The reason for the error was that the uint64 type is only defined
in newer tiff.h files.

Q: Where are older TIFF specs?
A: take a look to:
TIFF 4: https://web.archive.org/web/20050323073243/http://palimpsest.stanford.edu/bytopic/imaging/std/tiff4.html
TIFF 5: https://web.archive.org/web/20050323073243/http://palimpsest.stanford.edu/bytopic/imaging/std/tiff5.html


+ 81
- 0
Makefile View File

@@ -0,0 +1,81 @@
# rule based checks if given TIFF is a specific baseline TIFF
# author: Andreas Romeyke, 2015
# licensed under conditions of libtiff
# (see http://libtiff.maptools.org/misc.html)

### needs libtiff (>= v4)
### libpcre (>=v3)

LIB+=-lpcre -ltiff -lm
SANITIZE?=-fsanitize=undefined -fsanitize=shift \
-fsanitize=integer-divide-by-zero -fsanitize=unreachable \
-fsanitize=vla-bound -fsanitize=null -fsanitize=return \
-fsanitize=signed-integer-overflow
#-fsanitize=leak
CFLAGS?= -g -Wall $(SANITIZE)
GRAMMAR=config_dsl.grammar.c
SRCS=$(wildcard tagrules/*.c) check_helper.c check_ifd.c config_parser.c
OBJS=$(patsubst %.c,%.o, $(SRCS))

# default target
all: checkit_tiff test

# remove debugging symbols (smaller size)
strip: all
strip --strip-all checkit_tiff

config_parser.c: config_dsl.grammar.c

config_dsl.grammar.c: config_dsl.grammar.peg

%.o: %.c
$(CC) $(CFLAGS) $(INC) -c $< -o $@

# produce parser via PEG
%.c: %.peg
peg $< > $@

-include version.mk

checkit_tiff.o: checkit_tiff.c
$(CC) -DVERSION="\"0.$(REPO_REVISION)\"" $(CFLAGS) $(INC) -c $< -o $@

# default executable
checkit_tiff: $(OBJS) checkit_tiff.o
$(CC) -o $@ $(CFLAGS) $(INC) $^ $(LIB)

test: $(OBJS) test.o
$(CC) -o $@ $(CFLAGS) $(INC) $^ $(LIB)

test.c: $(GRAMMAR)

# doc
doc: ../common/doxygen.conf
@doxygen ../common/doxygen.conf

# clean workdir
clean:
@rm -f *.o tagrules/*.o
@rm -f checkit_tiff test

# mrproper clean
distclean: clean
@rm -f *~ tagrules/*~
@rm -f core
@rm -Rf doc/
@rm -f .depend
@rm -f *.d
@rm -f .depend


depend: .depend

.depend: $(SRCS)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^>>./.depend;

-include .depend

.PHONY: all clean distclean strip depend



+ 62
- 0
README.1st View File

@@ -0,0 +1,62 @@
HINT
====

* The program could already used to check TIFF-files now
* Remember, it is in alpha-state and needs additional rules to validate tiff files completely.
* Please, if you find errors or do you have test files like
** https://github.com/EasyinnovaSL/DPFManager/tree/develop/src/test/resources/
** or https://github.com/openpreserve/jhove/tree/junit_tests/examples/tiff/badfiles
* please do not hesitate to contact me.

== Compile ==

$> make

If you want to compile the programm with an older linux distribution, pE,
Debian Wheezy, use this line instead:

$> SANITIZE="-DOLDTIFF" make


== Run ==

./checkit_tiff ../examples/invalid_date.tiff example_configs/cit_tiff6_baseline_SLUB.cfg
'./checkit_tiff' version: 0.223_g74e9931, licensed under conditions of libtiff (see http://libtiff.maptools.org/misc.html)
tiff file=../examples/invalid_date.tiff
cfg_file=example_configs/cit_tiff6_baseline_SLUB.cfg
TIFFFetchNormalTag: Warning, Incorrect value for "Photoshop"; tag ignored.
check if all IFDs are word aligned
check if only one IFD exists
check if tags are in ascending order
check if all offsets are used once only
check if all offsets are word aligned
check if tag 306 (DateTime) is correct
tag 306 (DateTime) value of datetime should be "yyyy:MM:DD hh:mm:ss", but was "04.03.2010 09:59:17"
check if tag 256 (ImageWidth) has value in range 1 - 4294967295
check if tag 257 (ImageLength) has value in range 1 - 4294967295
check if tag 258 (BitsPerSample) has these 3-values, 8, 8, 8
check if tag 259 (Compression) has value 1
check if tag 262 (PhotometricInterpretation) has value in range 0 - 2
check if tag 273 (StripOffsets) exists
check if tag 273 (StripOffsets) has valid type
check if tag 273 (StripOffsets) has valid asciivalue
check if tag 277 (SamplesPerPixel) has value 3
check if tag 278 (RowsPerStrip) has value in range 1 - 4294967295
check if tag 279 (StripByteCounts) has value in range 1 - 4294967295
check if tag 282 (XResolution) has value in range 300 - 1200
check if tag 283 (YResolution) has value in range 300 - 1200
check if tag 296 (ResolutionUnit) has value 2
check if tag 254 (SubfileType) has value 0
check if tag 266 (FillOrder) has value 1
check if tag 274 (Orientation) has value 1
check if tag 284 (PlanarConfiguration) has value 1
check if tag 305 (Software) has value matching regex '^[[:print:]]*$'
check if tag 306 (DateTime) has value matching regex '^[12][901][0-9][0-9]:[01][0-9]:[0-3][0-9] [012][0-9]:[0-5][0-9]:[0-6][0-9]$'
tag 306 with value '04.03.2010 09:59:17' no match to given regex '^[12][901][0-9][0-9]:[01][0-9]:[0-3][0-9] [012][0-9]:[0-5][0-9]:[0-6][0-9]$'
check if forbidden tags are still existing
found tag 269 (DocumentName) which is not whitelisted
found tag 297 (PageNumber) which is not whitelisted
found tag 315 (Artist) which is not whitelisted
found tag 34377 (Photoshop) which is not whitelisted
found 6 errors
$>

+ 14
- 0
README.TIFFspecification View File

@@ -0,0 +1,14 @@
== EXIF IFD (and other private IFDs) ==
Because Adobe registers the private TIFF-tags, we know little about these tags in the wild. In the specification it would be suggested to use a special IFD if you need more than small amount of private TIFF tags.

This affects also the tags used for EXIF data. Our interpretation is, if you have an IFD for private tags, they should only be referenced from this IFD and not from base IFD directly.

== offsets on word boundary ==

The specification is very clear. Offsets should only point to odd adresses. We think this is important for longterm preservation, because it makes the TIFF format more robust and repairable if some bit flipping occurs.

== tags in ascending order ==

see offset and word boundary, same reason



+ 50
- 0
README.grammar View File

@@ -0,0 +1,50 @@
About general function
======================

The checkit-tool validates a TIFF-file against a set of rules (see below). The
set of rules works as a whitelist. This means that if a tag in the TIFF file is
not explicitely checked by rules (independently if successfully or not) the tag
is not allowed. In cases where a rule is executed only if a predicate is set,
the tag is only allowed if the predicate succeeded.


Developers
==========
to configure the grammar you could use the PEG-extension for gvim from https://github.com/gf3/peg.vim

Users
=====
to define your own config-file to check TIFFs, please use this simplified
syntax:

* each line is either a tagline, a comment or empty
* a comment starts with # first
* a tagline is built via "TAG ; REQUIREMENTS ; VALUES", where
* a TAG is a increasing number similar to TIFF-Tag numbers (see TIFF
definition)
* REQUIREMENTS could be
** "mandatory" - a tag must exist in TIFF
** "optional" - a tag could exist in TIFF, if so it will be checked
** "depends(REFERENCE)" - a tag must exist in TIFF if reference exists
** "optdepends(REFERENCE)" - a tag could exists in TIFF if reference exists. If it exists it will be checked
* REFERENCE will be TAGREFERENCE.VALUEREFERENCE
** TAGREFERENCE points to a tag number which must be exists,
** VALUEREFERENCE could be 'any' or a decimal value or a string enclosed in '"'
** only if REFERENCE exists in TIFF the REQUIREMENTS rule will be checked
* VALUES could be one of these:
** "range(START, END)" where START and END are decimal values
** "logical_or( VALUELIST)" where VALUELIST are comma-separated decimale values
** "any" which means any match
** "only(VALUE) where VALUE is a decimal value or a string enclosed in ""
** "regex("REGEX") where REGEX is a PCRE-regular expression with escaped '"' and '\', it only works with tags of type ascii
* each tagline or comment must be closed with a new line

If multiple rules defined per tag, they will be combined alternatively.

For examples check the example_configs/ - directory.

Values
======

At the moment, the parser only supports a limited type of values. To make
handling easier, it uses only the value/offset part of an IFD entry

+ 13
- 0
README.regex View File

@@ -0,0 +1,13 @@
= RegEx =

the program uses the pcre-library for regular expressions in ascii mathcing
rules (in config file).

If you use a regex similar to "^[:print:]*$" it does not match on
* all strings containing characters outside of printable ascii range (see 'man
pcre2pattern' for details)
* an empty string "" will not matched, because we defined PCRE_NOTEMPTY.
An empty string is not a valid match, this behaviour is a design choice.
* Unicode is not set, because TIFF specification is in general ASCII based
(PCRE_UTF8 not set)


+ 7
- 0
TODO View File

@@ -0,0 +1,7 @@
- add checks for XMP specification
http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMP%20SDK%20Release%20cc-2014-12/XMPSpecificationPart1.pdf
- add checks for IPTC specification
http://www.iptc.org/download/download.php?fn=IIMV4.1.pdf
- add more testfiles



+ 77
- 0
check.h View File

@@ -0,0 +1,77 @@
/* rule based checks if given TIFF is a specific baseline TIFF
*
* author: Andreas Romeyke, 2015
* licensed under conditions of libtiff
* (see http://libtiff.maptools.org/misc.html)
*
*/

#ifndef _FIXIT_TIFF_CHECK
#define _FIXIT_TIFF_CHECK
#include <stdlib.h>
#include <tiff.h>
#include <tiffio.h>

typedef struct ret_s {
int returncode;
char * returnmsg;
} ret_t;

typedef struct ifd_entry_s {
uint16 count;
TIFFDataType datatype;
enum{ is_offset, is_value, is_error } value_or_offset;
union {
uint32 data32;
uint16 data16[2];
uint8 data8[4];
uint32 data32offset;
};
} ifd_entry_t;

typedef struct offset_s {
uint16 count;
TIFFDataType datatype;
union {
uint8 *data8p;
uint16 *data16p;
uint32 *data32p;
char *datacharp;
int8 *datas8p;
int16 *datas16p;
int32 *datas32p;
float *datafloatp;
double *datadoublep;
uint64 *data64p;
int64 *datas64p;
};
} offset_t;

typedef uint16 tag_t;

#define MAXSTRLEN 160

#define tif_fails(args...) {ret_t res; char * str =malloc( sizeof(char) *MAXSTRLEN ); if (NULL==str) { fprintf(stderr, "could not allocate memory for tif_fails\n"); exit(EXIT_FAILURE); }; snprintf (str, MAXSTRLEN-1, args); printf("\t%s", str); res.returnmsg = str; res.returncode=1; return res;}

#define tifp_check( tif ) {if (NULL == tif) { tif_fails("TIFF pointer is empty\n"); } }

#define tif_returns(args...) {ret_t res; char * str =malloc( sizeof(char) *MAXSTRLEN ); if (NULL==str) { fprintf(stderr, "could not allocate memory for tif_fails\n"); exit(EXIT_FAILURE); }; snprintf (str, MAXSTRLEN-1, args); res.returnmsg = str; res.returncode=1; return res;}
ret_t check_tag_has_some_of_these_values( TIFF* tif, tag_t tag, int count, unsigned int * values);
ret_t check_tag_has_valuelist( TIFF* tif, tag_t tag, int count, unsigned int * values);
ret_t check_tag_has_value_in_range(TIFF* tif, tag_t tag, unsigned int a, unsigned int b);
ret_t check_tag_has_value(TIFF* tif, tag_t tag, unsigned int value);
ret_t check_tag_has_value_quiet(TIFF* tif, tag_t tag, unsigned int value);
ret_t check_tag(TIFF* tif, tag_t tag);
ret_t check_tag_quiet(TIFF* tif, tag_t tag);
ret_t check_notag(TIFF* tif, tag_t tag);
ret_t check_tag_has_valid_type(TIFF* tiff, tag_t tag);
ret_t check_datetime(TIFF* tif);
ret_t check_has_only_one_ifd(TIFF* tif);
ret_t check_tagorder(TIFF* tif);
ret_t check_tag_has_valid_asciivalue(TIFF* tif, tag_t tag);
ret_t check_tag_has_value_matching_regex(TIFF* tif, tag_t tag, const char* value);
ret_t check_all_offsets_are_word_aligned(TIFF * tif);
ret_t check_all_offsets_are_used_once_only(TIFF * tif);
ret_t check_all_IFDs_are_word_aligned(TIFF * tif);
#endif
/* _FIXIT_TIFF_CHECK */

+ 718
- 0
check_helper.c View File

@@ -0,0 +1,718 @@
/* rule based checks if given TIFF is a specific baseline TIFF
*
* author: Andreas Romeyke, 2015
* licensed under conditions of libtiff
* (see http://libtiff.maptools.org/misc.html)
*
*/

#define _GNU_SOURCE
#include <math.h>
#include "check.h"
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <string.h>
/*
#define DEBUG
*/



static int enabled_cache = 0;

void clear_cache () {
enabled_cache = 0;
}


//------------------------------------------------------------------------------
ret_t check_tag_has_fvalue(TIFF* tif, tag_t tag, float value)
{
float val;
int found=TIFFGetField(tif, tag, &val);
if (1 == found) {
if ( fabs(val - value) < 0.01 ) {
ret_t res;
res.returnmsg=NULL;
res.returncode=0;
return res;
} else {
tif_returns("tag %u should have value %f, but have count/value=%f\n", tag, value, val);
}

} else {
tif_returns("tag %u should exist, because defined\n", tag);
}
}

//------------------------------------------------------------------------------
ret_t check_tag_has_u16value(TIFF* tif, tag_t tag, uint16 value)
{
uint16 val;
int found=TIFFGetField(tif, tag, &val);
if (1 == found) {
if ( val == value ) {
ret_t res;
res.returnmsg=NULL;
res.returncode=0;
return res;
} else {
tif_returns("tag %u should have value %u, but have count/value=%u\n", tag, value, val);
}

} else {
tif_returns("tag %u should exist, because defined\n", tag);
}
}


//------------------------------------------------------------------------------
ret_t check_tag_has_u32value(TIFF* tif, tag_t tag, uint32 value)
{
uint32 val;
int found=TIFFGetField(tif, tag, &val);
if (1 == found) {
if ( val == value ) {
ret_t res;
res.returnmsg=NULL;
res.returncode=0;
return res;
} else {
tif_returns("tag %u should have value %u, but have count/value=%u\n", tag, value, val);
}

} else {
tif_returns("tag %u should exist, because defined\n", tag);
}
}

const char * TIFFTagName( TIFF * tif, tag_t tag ) {
const TIFFField* fieldp = TIFFFieldWithTag(tif, tag);
if (NULL != fieldp) {
#ifndef OLDTIFF
return TIFFFieldName(fieldp);
#else
char * tagstring;
tagstring =malloc( sizeof(char) *MAXSTRLEN );
if (NULL==tagstring) {
fprintf(stderr, "could not allocate memory for tagstring\n");
exit(EXIT_FAILURE);
};
snprintf (tagstring, MAXSTRLEN-1, "tag %u", tag);
char * ret = strdupa( tagstring );
free (tagstring);
return ret;
#endif
} else {
switch (tag) {
case 32932: return ("TIFF annotation data"); /* http://web.archive.org/web/20050309141348/http://www.kofile.com/support%20pro/faqs/annospec.htm */
case 33445: return ("MD_Filetag"); /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */
case 33446: return ("MD_ScalePixel"); /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */
case 33447: return ("MD_Colortable"); /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */
case 33448: return ("MD_LabName"); /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */
case 33449: return ("MD_SampleInfo"); /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */
case 33450: return ("MD_PrepDate"); /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */
case 33451: return ("MD_PrepTime"); /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */
case 33452: return ("MD_FileUnits"); /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */
case 33918: return ("INGR Packet Data Tag"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 33919: return ("INGR Flag Registers"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 33920: return ("IrasB Transormation Matrix"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 33922: return ("ModelTiepointTag"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 34264: return ("ModelTransformationTag"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 34732: return ("ImageLayer"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag, see RFC2301*/
case 34820: return ("EMC/PixTool SpecificTag"); /* thgere is more informatioon about meaning needed. If tag exists, there was string "Untitled" encoded (as binary) */
case 34908: return ("HylaFax FaxRecvParams"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 34909: return ("HylaFax FaxSubAdress"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 34910: return ("HylaFax FaxRecvTime"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 37724: return ("ImageSourceData"); /* http://justsolve.archiveteam.org/wiki/PSD, http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */
case 42112: return ("GDAL_Metadata"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 42113: return ("GDAL_nodata"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 50215: return ("Oce Scanjob Description"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 50216: return ("Oce Application Selector"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 50217: return ("Oce Identification Number"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 50218: return ("Oce ImageLogic Characteristics"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 50784: return ("Alias Layer Metadata"); /* see http://www.rastermaster.com/RasterMaster%20DLL%20manual/WebHelp/Content/aptifftagswide.htm for explanation of tag*/
case 50933: return ("ExtraCameraProfiles"); /* http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf */
default: return ("undefined tag");
}
}
}

int parse_header_and_endianess(TIFF * tif) {
thandle_t client = TIFFClientdata(tif);
TIFFReadWriteProc readproc = TIFFGetReadProc(tif);
TIFFSeekProc seekproc = TIFFGetSeekProc(tif);
if (! seekproc) {
perror ("could not get TIFFGetSeekProc");
}
if (! readproc) {
perror ("could not get TIFFGetReadProc");
}

/* seek the image file directory (bytes 4-7) */

//lseek(fd, (off_t) 0, SEEK_SET);
seekproc(client, 0, SEEK_SET);
uint16 header;
uint16 magic;
int ret;
/*
if (read(fd, &header, 2) != 2) {
perror ("TIFF Header read error");
exit( EXIT_FAILURE );
}
*/
if ( readproc( client, &header, 2) != 2 ) {
perror ("TIFF Header read error");
exit( EXIT_FAILURE );
}
if (header == 0x4949) ret = 0; /* little endian */
else if (header == 0x4d4d) ret = 1; /* big endian */
else {
fprintf (stderr, "TIFF Header error, not Byte Order Bytes for TIFF: 0x%04x\n", header);
if (header == 0x4550) fprintf( stderr, "could be a Microsoft Document Image file (little endian), if header begins with by 0x45 0x50 0x2a 0x00\n");
exit(EXIT_FAILURE);
}
/*
if (read(fd, &magic, 2) != 2) {
perror ("TIFF Header read error");
exit( EXIT_FAILURE );
}
*/
if ( readproc( client, &magic, 2) != 2 ) {
perror ("TIFF Header read error");
exit( EXIT_FAILURE );
}

uint16 magic2 = magic;
if (ret) TIFFSwabShort( &magic2 ); /* big endian */
if (magic2 == 42) { return ret; }
else {
fprintf (stderr, "TIFF Header error, not a MAGIC BYTE for TIFF: 0x%04x\n", magic);
if (magic2==0x2b00) fprintf (stderr, "\tbut could be a BigTIFF, see http://www.awaresystems.be/imaging/tiff/bigtiff.html\n");
if (magic2==0x5500) fprintf (stderr, "\tbut could be a Panasonic Raw/RW2, see http://libopenraw.freedesktop.org/wiki/Panasonic_RAW/\n");
if (magic2==0xbc01) fprintf (stderr, "\tbut could be a JPEG XR, see http://www.itu.int/rec/T-REC-T.832\n");
if (magic2==0x4e31) fprintf (stderr, "\tbut could be a Navy Image FileFormat, see http://www.navsea.navy.mil/nswc/carderock/tecinfsys/cal-std/doc/28002c.pdf\n");
if (magic2==0x5243) fprintf (stderr, "\tbut could be a DNG camera profile, see http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf\n");
if (magic2==0x524f) fprintf (stderr, "\tbut could be an Olympus ORF, see http://libopenraw.freedesktop.org/wiki/Olympus_ORF/\n");
if (magic2==0x5253) fprintf (stderr, "\tbut could be an Olympus ORF, see http://libopenraw.freedesktop.org/wiki/Olympus_ORF/\n");
exit(EXIT_FAILURE);
}
}

uint32 get_first_IFD(TIFF * tif) {
/* memoize it */
static uint32 memoized_offset = 0;
static int is_memoized = 0;
static TIFF * memoized_tif = NULL;
//printf("get_first_IFD is memoized? %s\n", is_memoized ? "true" : "false");
if (! is_memoized || (memoized_tif != tif) || (!enabled_cache)) {
int isByteSwapped = parse_header_and_endianess(tif);
/* seek the image file directory (bytes 4-7) */
thandle_t client = TIFFClientdata(tif);
TIFFSeekProc seekproc = TIFFGetSeekProc(tif);
TIFFReadWriteProc readproc = TIFFGetReadProc(tif);
if (! seekproc) {
perror ("could not get TIFFGetSeekProc");
}
if (! readproc) {
perror ("could not get TIFFGetReadProc");
}
/*lseek(fd, (off_t) 4, SEEK_SET); */
seekproc(client, 4, SEEK_SET);
uint32 offset;
/*if (read(fd, &offset, 4) != 4) {
perror ("TIFF Header read error");
exit( EXIT_FAILURE );
}
*/
if ( readproc( client, &offset, 4) != 4 ) {
perror ("TIFF Header read error");
exit( EXIT_FAILURE );
}
if (isByteSwapped) {
TIFFSwabLong (&offset);
}
memoized_offset = offset;
memoized_tif = tif;
is_memoized = 1;
enabled_cache = 1;

}
return memoized_offset;
}

/* scans first IDF and returns count of tags
* Hint: sideeffect, if succeed the seek points to beginning of the first
* IFD-entry */
int TIFFGetRawTagListCount (TIFF * tif) {
thandle_t client = TIFFClientdata(tif);
TIFFReadWriteProc readproc = TIFFGetReadProc(tif);
TIFFSeekProc seekproc = TIFFGetSeekProc(tif);
if (! seekproc) {
perror ("could not get TIFFGetSeekProc");
}
if (! readproc) {
perror ("could not get TIFFGetReadProc");
}

//int fd = TIFFFileno( tif);
/* seek the image file directory (bytes 4-7) */
uint32 offset = get_first_IFD( tif );

// printf("diroffset to %i (0x%04lx)\n", offset, offset);
//printf("byte swapped? %s\n", (TIFFIsByteSwapped(tif)?"true":"false"));
/* read and seek to IFD address */
//lseek(fd, (off_t) offset, SEEK_SET);
seekproc(client, offset, SEEK_SET);

uint16 count;
/*if (read(fd, &count, 2) != 2) {
perror ("TIFF Header read error2");
exit(EXIT_FAILURE);
}
*/
if ( readproc( client, &count, 2) != 2 ) {
perror ("TIFF Header read error2");
exit( EXIT_FAILURE );
}

if (TIFFIsByteSwapped(tif))
TIFFSwabShort(&count);
return count;
}

/* scans first IDF and returns the n-th tag */
tag_t TIFFGetRawTagListEntry( TIFF * tif, int tagidx ) {
int count = TIFFGetRawTagListCount( tif);
thandle_t client = TIFFClientdata(tif);
TIFFReadWriteProc readproc = TIFFGetReadProc(tif);
TIFFSeekProc seekproc = TIFFGetSeekProc(tif);
if (! seekproc) {
perror ("could not get TIFFGetSeekProc");
}
if (! readproc) {
perror ("could not get TIFFGetReadProc");
}
//int fd = TIFFFileno( tif);
//printf("count %i\n", count);
/* read count of tags (2 Bytes) */
int i;
/* replace i/o operatrions with in-memory-operations */
uint8 * ifdentries = NULL;
ifdentries = malloc ( sizeof(uint8) * 12 * count);
/*
if (read(fd, ifdentries, 12 * count) != 12*count) {
perror ("TIFF Header read error3");
exit(EXIT_FAILURE);
}
*/
if ( readproc( client, ifdentries, 12 * count) != 12*count ) {
perror ("TIFF Header read error3");
exit( EXIT_FAILURE );
}

uint8 * e = ifdentries;
uint16 ret = 0;
for (i = 0; i<count; i++) {
uint8 lo = *e;
e++;
uint8 hi = *e;
uint16 tagid = (hi << 8) + lo;
e++;
if (TIFFIsByteSwapped(tif))
TIFFSwabShort(&tagid);
if (i == tagidx) {
// printf("tag idx=%i, tag=%u (0x%04x) (0x%02x) (0x%02x)\n", i, tagid, tagid, hi, lo);
ret = tagid;
goto LABEL1;
}
e+=10;
}
LABEL1:
/* loop each tag until end or given tag found */
free( ifdentries );
return ret;
}

/*
#define offset_malloc(fd, of, os, count ) {\
of = NULL; of = malloc ( sizeof(os) * count);\
if (read(fd, of, sizeof(os) * count) != sizeof(os) *count)\
perror ("TIFF Offset read error2") ;\
}
*/
#define offset_malloc(fd, of, os, count ) {\
of = NULL; of = malloc ( sizeof(os) * count);\
if ( readproc( client, of, sizeof(os) * count) != sizeof(os) *count ) {\
perror ("TIFF Offset read error2");\
exit( EXIT_FAILURE );\
}\
}


/* get count-data datastream from offset-address */
offset_t read_offsetdata( TIFF * tif, uint32 address, uint16 count, uint16 datatype) {
//int fd = TIFFFileno( tif);
thandle_t client = TIFFClientdata(tif);
TIFFReadWriteProc readproc = TIFFGetReadProc(tif);
TIFFSeekProc seekproc = TIFFGetSeekProc(tif);
if (! seekproc) {
perror ("could not get TIFFGetSeekProc");
}
if (! readproc) {
perror ("could not get TIFFGetReadProc");
}
/* read and seek to IFD address */
//lseek(fd, (off_t) address, SEEK_SET);
seekproc(client, address, SEEK_SET);



#ifdef DEBUG
printf("read_offsetdata(tif, adress=%u, count=%u, datatype=%u)\n", address, count, datatype);
#endif

offset_t offset;
offset.count = count;
offset.datatype = datatype;
switch (datatype) {
case 1: /* 8-bit unsigned integer */
case 7: /* !8-bit untyped data */
/*
offset.data8p = NULL;
offset.data8p = malloc ( sizeof(uint8) * count);
if (read(fd, offset.data8p, sizeof(uint8) * count) != sizeof(uint8) *count)
perror ("TIFF Offset read error");
*/
offset_malloc(fd, offset.data8p, uint8, count)
break;
case 2: /* 8-bit bytes w/ last byte null */
assert( sizeof(char) == sizeof(uint8));
offset_malloc(fd, offset.datacharp, char, count)
break;
case 6: /* !8-bit signed integer */
offset_malloc(fd, offset.datas8p, int8, count)
break;
case 3: /* 16-bit unsigned integer */
offset_malloc(fd, offset.data16p, uint16, count)
break;
case 8: /* !16-bit signed integer */
offset_malloc(fd, offset.datas16p, int16, count)
break;
case 4: /* 32-bit unsigned integer */
case 13: /* %32-bit unsigned integer (offset) */
offset_malloc(fd, offset.data32p, uint32, count)
break;
case 9: /* !32-bit signed integer */
offset_malloc(fd, offset.datas32p, uint32, count)
break;
case 5: /* 64-bit unsigned fraction */
fprintf(stderr, "offsetdata datatype=%i not supported yet", datatype);
exit(EXIT_FAILURE);
case 10: /* !64-bit signed fraction */
fprintf(stderr, "offsetdata datatype=%i not supported yet", datatype);
exit(EXIT_FAILURE);
case 11: /* !32-bit IEEE floating point */
assert( sizeof(float) == 4);
offset_malloc(fd, offset.datafloatp, float, count)
break;
case 12: /* !64-bit IEEE floating point */
assert( sizeof(double) == 8);
offset_malloc(fd, offset.datadoublep, double, count)
break;
case 16: /* BigTIFF 64-bit unsigned integer */
case 18: /* BigTIFF 64-bit unsigned integer (offset) */
assert( sizeof(double) == 8);
offset_malloc(fd, offset.data64p, uint64, count)
break;
case 17: /* BigTIFF 64-bit signed integer */
assert( sizeof(double) == 8);
offset_malloc(fd, offset.datas64p, int64, count)
break;
default: /* should not occure */
fprintf(stderr, "offsetdata datatype=%i not supported yet", datatype);
exit(EXIT_FAILURE);
};
return offset;
}

/* scans first IDF and returns the type of the n-th tag */
ifd_entry_t TIFFGetRawTagIFDListEntry( TIFF * tif, int tagidx ) {
int count = TIFFGetRawTagListCount( tif);
#ifdef DEBUG
printf(" count of tags = %i\n", count);
#endif
// int fd = TIFFFileno( tif);
thandle_t client = TIFFClientdata(tif);
TIFFReadWriteProc readproc = TIFFGetReadProc(tif);
TIFFSeekProc seekproc = TIFFGetSeekProc(tif);
if (! seekproc) {
perror ("could not get TIFFGetSeekProc");
}
if (! readproc) {
perror ("could not get TIFFGetReadProc");
}


//printf("count %i\n", count);
/* read count of tags (2 Bytes) */
int i;
ifd_entry_t ifd_entry;
ifd_entry.value_or_offset = is_error;
/* replace i/o operatrions with in-memory-operations */
uint8 * ifdentries = NULL;
ifdentries = malloc ( sizeof(uint8) * 12 * count);
/*
if (read(fd, ifdentries, 12 * count) != 12*count) {
perror ("TIFF Header read error4");
exit(EXIT_FAILURE);
}
*/
if ( readproc( client, ifdentries, 12 * count) != 12*count ) {
perror ("TIFF Header read error4");
exit( EXIT_FAILURE );
}
uint8 * e = ifdentries;
for (i = 0; i<count; i++) {
uint8 lo = *e;
e++;
uint8 hi = *e;
uint16 tagid = (hi << 8) + lo;
e++;
if (TIFFIsByteSwapped(tif))
TIFFSwabShort(&tagid);
if (i == tagidx) {
// tag type check
lo = *e; e++;
hi = *e; e++;
uint16 tagtype = (hi << 8) + lo;
if (TIFFIsByteSwapped(tif))
TIFFSwabShort(&tagtype);
uint32 count = (*(e++));
count += (*(e++) << 8);
count += (*(e++) << 16);
count += (*(e++) << 24);
if (TIFFIsByteSwapped(tif))
TIFFSwabLong( &count);
#ifdef DEBUG
printf("\ncount=%0x\n\n", count);
#endif
/* is value or offset? */
/* TODO */
ifd_entry.count=count;
ifd_entry.datatype=tagtype;
uint8 data[4];
data[0] = *(e++);
data[1] = *(e++);
data[2] = *(e++);
data[3] = *(e++);
uint32 value_or_offset = (data[0]);
value_or_offset += (data[1] << 8);
value_or_offset += (data[2] << 16);
value_or_offset += (data[3] << 24);
if (TIFFIsByteSwapped(tif))
TIFFSwabLong( &value_or_offset);
switch( tagtype) {
case 1: /* 8-bit unsigned integer */
case 2: /* 8-bit bytes w/ last byte null */
case 6: /* !8-bit signed integer */
case 7: /* !8-bit untyped data */
if (count > 4) { /* offset */
ifd_entry.value_or_offset=is_offset;
ifd_entry.data32offset=value_or_offset;
} else { /* values */
ifd_entry.value_or_offset=is_value;
ifd_entry.data8[0] = data[0];
ifd_entry.data8[1] = data[1];
ifd_entry.data8[2] = data[2];
ifd_entry.data8[3] = data[3];
#ifdef DEBUG
printf("data8[0]=%u\n", data[0]);
printf("data8[1]=%u\n", data[1]);
printf("data8[2]=%u\n", data[2]);
printf("data8[3]=%u\n", data[3]);
#endif
}; break;
case 3: /* 16-bit unsigned integer */
case 8: /* !16-bit signed integer */
if (count > 2) { /* offset */
ifd_entry.value_or_offset=is_offset;
ifd_entry.data32offset=value_or_offset;
} else { /* values */
ifd_entry.value_or_offset=is_value;
uint16 w0 = (data[0]) + (data[1]<<8);
uint16 w1 = (data[2]) + (data[3]<<8);
if (TIFFIsByteSwapped(tif)) {
TIFFSwabShort( &w0 );
TIFFSwabShort( &w1 );
}
ifd_entry.data16[0] = w0;
ifd_entry.data16[1] = w1;
#ifdef DEBUG
printf("data16[0]=%u\n", w0);
printf("data16[1]=%u\n", w1);
#endif
}; break;
case 4: /* 32-bit unsigned integer */
case 9: /* !32-bit signed integer */
if (count > 1) { /* offset */
ifd_entry.value_or_offset=is_offset;
ifd_entry.data32offset=value_or_offset;
} else { /* values */
ifd_entry.value_or_offset=is_value;
ifd_entry.data32=value_or_offset;
#ifdef DEBUG
printf("data32[0]=%u\n", value_or_offset);
#endif
}; break;
case 5: /* 64-bit unsigned fraction */
case 10: /* !64-bit signed fraction */
case 11: /* !32-bit IEEE floating point */
case 12: /* !64-bit IEEE floating point */
case 13: /* %32-bit unsigned integer (offset) */
case 16: /* BigTIFF 64-bit unsigned integer */
case 17: /* BigTIFF 64-bit signed integer */
case 18: /* BigTIFF 64-bit unsigned integer (offset) */
ifd_entry.value_or_offset=is_offset;
ifd_entry.data32offset=value_or_offset;

}
free( ifdentries );
#ifdef DEBUG
printf("tag idx=%i, tag=%u (0x%04x) tagtype=0x%04x is_offset=%s count=%d value_or_offset=0x%08x\n", i, tagid, tagid, tagtype, (ifd_entry.value_or_offset==is_offset ? "true" : "false"), count, value_or_offset);
#endif
return ifd_entry;
}
e+=10;
}
/* loop each tag until end or given tag found */
free( ifdentries );
return ifd_entry;
}

/* TODO */
ifd_entry_t TIFFGetRawIFDEntry( TIFF * tif, tag_t tag) {
int tagidx = -1;
int i;
for (i= 0; i < TIFFGetRawTagListCount( tif ); i++) {
if (tag == TIFFGetRawTagListEntry( tif, i ) && tag > 253) {
tagidx= i;
break;
};
};
ifd_entry_t ifd_entry;
if (tagidx >= 0) {
ifd_entry = TIFFGetRawTagIFDListEntry( tif, tagidx );
} else { /* tag not defined */
printf("\ttag %u (%s) was not found, but requested because defined\n", tag, TIFFTagName(tif, tag));
ifd_entry.value_or_offset = is_error;
ifd_entry.count = 0;
}
return ifd_entry;
}
/* scans first IDF and returns the type of the n-th tag */
uint32 TIFFGetRawTagTypeListEntry( TIFF * tif, int tagidx ) {
if (tagidx >= 0) {
ifd_entry_t ifd_entry;
ifd_entry = TIFFGetRawTagIFDListEntry( tif, tagidx );
return ifd_entry.datatype;
} else { /* tag not defined */
fprintf(stderr, "tagidx should be greater equal 0");
exit(EXIT_FAILURE);
}
}

/* reads the datatype of given tag on specified TIFF,
* because FieldType of libtiff does not return the true value (because it maps
* its own datastructure), we need to use this function instead
* @param tif pointer to TIFF structure
* @param tag tag
* @return datatype of given tag
* if tag does not exists the function aborts with an error
*/
TIFFDataType TIFFGetRawTagType(TIFF * tif, tag_t tag) {
int tagidx = -1;
int i;
for (i= 0; i < TIFFGetRawTagListCount( tif ); i++) {
if (tag == TIFFGetRawTagListEntry( tif, i ) && tag > 253) {
tagidx= i;
break;
};
};
if (tagidx >= 0) {
TIFFDataType datatype = TIFFGetRawTagTypeListEntry( tif, tagidx );
#ifdef DEBUG
printf("### datatype=%i \n", datatype);
#endif
return datatype;
} else { /* tag not defined */
printf("\ttag %u (%s) was not found, but requested because defined\n", tag, TIFFTagName(tif, tag));
return -1;
}
}


ret_t check_tagorder(TIFF* tif) {
printf("check if tags are in ascending order\n");
int count = TIFFGetRawTagListCount( tif);
//int fd = TIFFFileno( tif);
thandle_t client = TIFFClientdata(tif);
TIFFReadWriteProc readproc = TIFFGetReadProc(tif);
TIFFSeekProc seekproc = TIFFGetSeekProc(tif);
if (! seekproc) {
perror ("could not get TIFFGetSeekProc");
}
if (! readproc) {
perror ("could not get TIFFGetReadProc");
}


//printf("count %i\n", count);
/* read count of tags (2 Bytes) */
int i;
/* replace i/o operatrions with in-memory-operations */
uint8 * ifdentries = NULL;
ifdentries = malloc ( sizeof(uint8) * 12 * count);
/*
if (read(fd, ifdentries, 12 * count) != 12*count) {
perror ("TIFF Header read error5");
exit(EXIT_FAILURE);
}
*/
if ( readproc( client, ifdentries, 12 * count) != 12*count ) {
perror ("TIFF Header read error5");
exit( EXIT_FAILURE );
}

uint8 * e = ifdentries;
uint16 lasttag = 0;
for (i = 0; i<count; i++) {
uint8 lo = *e;
e++;
uint8 hi = *e;
uint16 tag = (hi << 8) + lo;
e++;
if (TIFFIsByteSwapped(tif))
TIFFSwabShort(&tag);
if (i>0 && lasttag >= tag) {
// printf("tag idx=%i, tag=%u (0x%04x) (0x%02x) (0x%02x)\n", i, tag, tag, hi, lo);
free( ifdentries );
tif_fails("Invalid TIFF directory; tags are not sorted in ascending order, previous tag:%u (%s) , actual tag:%u (%s) at pos %i of %i\n", lasttag, TIFFTagName(tif, lasttag), tag, TIFFTagName(tif, tag), i, count);
}
lasttag = tag;
e+=10;
}
/* loop each tag until end or given tag found */
free( ifdentries );
ret_t res;
res.returnmsg=NULL;
res.returncode=0;
return res;
}




+ 31
- 0
check_helper.h View File

@@ -0,0 +1,31 @@
/* rule based checks if given TIFF is a specific baseline TIFF
*
* author: Andreas Romeyke, 2015
* licensed under conditions of libtiff
* (see http://libtiff.maptools.org/misc.html)
*
*/

#ifndef _FIXIT_TIFF_CHECK_HELPER
#define _FIXIT_TIFF_CHECK_HELPER
#include <stdlib.h>
#include <tiff.h>
#include <tiffio.h>

/* helper */
ret_t check_tag_has_fvalue(TIFF* tif, tag_t tag, float value);
ret_t check_tag_has_u16value(TIFF* tif, tag_t tag, uint16 value);
ret_t check_tag_has_u32value(TIFF* tif, tag_t tag, uint32 value);
const char * TIFFTagName ( TIFF * tif, tag_t tag );
uint32 TIFFGetRawTagTypeListEntry( TIFF * tif, int tagidx );
tag_t TIFFGetRawTagListEntry( TIFF * tif, int tagidx ) ;
int TIFFGetRawTagListCount (TIFF * tif) ;
TIFFDataType TIFFGetRawTagType(TIFF * tif, tag_t tag);
ifd_entry_t TIFFGetRawIFDEntry( TIFF * tif, tag_t tag);
ifd_entry_t TIFFGetRawTagIFDListEntry( TIFF * tif, int tagidx );
offset_t read_offsetdata( TIFF * tif, uint32 address, uint16 count, uint16 datatype);
uint32 get_first_IFD(TIFF * tif);
//int TIFFIsByteSwapped(TIFF * tif);
void clear_cache();

#endif

+ 156
- 0
check_ifd.c View File

@@ -0,0 +1,156 @@
/* rule based checks if given TIFF is a specific baseline TIFF
*
* author: Andreas Romeyke, 2015
* licensed under conditions of libtiff
* (see http://libtiff.maptools.org/misc.html)
*
*/

#include "check.h"
#include "check_helper.h"
#include <unistd.h>

/* check if only one IFD exists */
ret_t check_has_only_one_ifd(TIFF* tif) {
printf("check if only one IFD exists\n");
/* next commented lines, because TIFFNumberOfDirectories are in endless loop,
* if the TIFF file from https://github.com/EasyinnovaSL/DPFManager/blob/develop/src/test/resources/IFD%20struct/Circular%20E.tif
* is read:
if (1 == TIFFNumberOfDirectories( tif )) {
ret_t res;
res.returnmsg=NULL;
res.returncode=0;
return res;
}*/
//int fd = TIFFFileno( tif);
/* seek the image file directory (bytes 4-7) */
uint32 offset = get_first_IFD( tif );
// printf("diroffset to %i (0x%04lx)\n", offset, offset);
//printf("byte swapped? %s\n", (TIFFIsByteSwapped(tif)?"true":"false"));
thandle_t client = TIFFClientdata(tif);
TIFFReadWriteProc readproc = TIFFGetReadProc(tif);
TIFFSeekProc seekproc = TIFFGetSeekProc(tif);
if (! seekproc) {
perror ("could not get TIFFGetSeekProc");
}
if (! readproc) {
perror ("could not get TIFFGetReadProc");
}


/* read and seek to IFD address */
// lseek(fd, (off_t) offset, SEEK_SET);
seekproc(client, offset, SEEK_SET);

uint16 count;
/*
if (read(fd, &count, 2) != 2) {
perror ("TIFF Header read error2");
exit(EXIT_FAILURE);
}
*/
if ( readproc( client, &count, 2) != 2 ) {
perror ("TIFF Header read error2");
exit( EXIT_FAILURE );
}

if (TIFFIsByteSwapped(tif))
TIFFSwabShort(&count);

//lseek(fd, 12 * count, SEEK_CUR);
seekproc(client, 12*count, SEEK_CUR);

/* next 4 bytes are the new IFDn entry, should be empty */
uint32 IFDn;
/*
if (read(fd, &IFDn, 4) != 4) {
perror ("TIFF Header read error3");
exit(EXIT_FAILURE);
}
*/
if ( readproc( client, &IFDn, 4) != 4 ) {
perror ("TIFF Header read error3");
exit( EXIT_FAILURE );
}

if (TIFFIsByteSwapped(tif))
TIFFSwabLong(&IFDn);
if (0 == IFDn) {
ret_t res;
res.returnmsg=NULL;
res.returncode=0;
return res;
} else {
tif_fails("baseline TIFF should have only one IFD, but IFD0 at 0x%08x has pointer to IFDn 0x%08x\n", offset, IFDn );
}
}

/* check if offsets are word aligned */
ret_t check_all_offsets_are_word_aligned(TIFF * tif) {
printf("check if all offsets are word aligned\n");
int count = TIFFGetRawTagListCount( tif);
int tagidx;
for (tagidx = 0; tagidx< count; tagidx++) {
ifd_entry_t ifd_entry = TIFFGetRawTagIFDListEntry( tif, tagidx );
if (ifd_entry.value_or_offset==is_offset) {
uint32 offset = ifd_entry.data32offset;
if ( 0 != (offset & 1)) {
uint32 tag = TIFFGetRawTagListEntry( tif, tagidx);
tif_fails("offset of tag %u (%s) points to 0x%08x and is not word-aligned\n", tag, TIFFTagName(tif, tag), offset);
}
}
}
ret_t res;
res.returnmsg=NULL;
res.returncode=0;
return res;
}

/* check if IFDs are word aligned */
ret_t check_all_IFDs_are_word_aligned(TIFF * tif) {
printf("check if all IFDs are word aligned\n");
uint32 ifd = get_first_IFD( tif ); /* TODO: check all other IFDs, too */
if ( 0 != (ifd & 1)) {
tif_fails("offset of first IFD points to 0x%08x and is not word-aligned\n", ifd);
}
ret_t res;
res.returnmsg=NULL;
res.returncode=0;
return res;
}

/* check if offsets are used only once */
ret_t check_all_offsets_are_used_once_only(TIFF * tif) {
printf("check if all offsets are used once only\n");
int count = TIFFGetRawTagListCount( tif);
int tagidx;
uint32 offsets[ count ];
uint32 tags[ count ];
int count_of_offsets = 0;
int i;

for (tagidx = 0; tagidx< count; tagidx++) {
offsets[ tagidx ] = 0;
tags[ tagidx ] = 0;
}
for (tagidx = 0; tagidx< count; tagidx++) {
ifd_entry_t ifd_entry = TIFFGetRawTagIFDListEntry( tif, tagidx );
if (ifd_entry.value_or_offset==is_offset) {
uint32 offset = ifd_entry.data32offset;
uint32 tag = TIFFGetRawTagListEntry( tif, tagidx);
for (i=0; i< count_of_offsets; i++) {
if (offsets[ i ] == offset) {
tif_fails("offset of tag %u (%s) points to %08x, which address is used previously by tag %u (%s)\n", tag, TIFFTagName(tif, tag), offset, tags[i], TIFFTagName(tif, tags[i]) );
}
}
offsets[ ++count_of_offsets ] = offset;
tags[ count_of_offsets ] = tag;
}
}
ret_t res;
res.returnmsg=NULL;
res.returncode=0;
return res;
}


+ 202
- 0
checkit_tiff.c View File

@@ -0,0 +1,202 @@
/* rule based checks if given TIFF is a specific baseline TIFF
*
* author: Andreas Romeyke, 2015
* licensed under conditions of libtiff
* (see http://libtiff.maptools.org/misc.html)
*
*/


#include "config_parser.h"
#include <unistd.h>
#include <assert.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __unix__
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#else
#include <sys\stat.h>
#endif

#define FLAGGED 1
#define UNFLAGGED 0

/** help function */
void help () {
printf ("checkit_tiff\n");
printf ("\tversion: %s\n", VERSION);
printf("licensed under conditions of libtiff (see http://libtiff.maptools.org/misc.html)\n\n");
printf ("\tuses libtiff version %s\n\n", TIFFGetVersion());
printf ("call it with:\n");
printf ("\tcheckit_tiff [-h|-m|-d] <tifffile> <configfile>\n");
printf ("\nwhere <tifffile> is the tiff file (or directory) to be validated\n");
printf ("and <configfile> is the file name of the validation profile\n");
printf ("\t-h this help\n");
printf ("\t-m uses memmapped I/O (faster validation, but needs more RAM)\n");
printf ("\t-d check all files in that directory\n");
printf ("example:\n\tcheckit_tiff tiffs_should_pass/minimal_valid.tiff example_configs/baseline_minimal.cfg\n");
printf ("\n");
}

int check_specific_tiff_file( const char * tiff_file, int use_memmapped) {
printf("tiff file=%s\n", tiff_file);
/* load tiff file */
TIFF* tif = NULL;
if (use_memmapped == FLAGGED) {
tif = TIFFOpen(tiff_file, "rM");
} else { /* slow */
tif = TIFFOpen( tiff_file, "rm");
}
if (NULL == tif) {
fprintf( stderr, "file '%s' could not be opened\n", tiff_file);
return (EXIT_FAILURE);
};
int is_valid = 0;
ret_t res;
/* special checks */
res = check_all_IFDs_are_word_aligned( tif); if (0 != res.returncode) {is_valid++;}
free (res.returnmsg);
res = check_has_only_one_ifd( tif); if (0 != res.returncode) {is_valid++;}
free (res.returnmsg);
res = check_tagorder( tif); if (0 != res.returncode) {is_valid++;}
free (res.returnmsg);
res = check_all_offsets_are_used_once_only( tif ); if (0 != res.returncode) {is_valid++;}
free (res.returnmsg);
res = check_all_offsets_are_word_aligned( tif ); if (0 != res.returncode) {is_valid++;}
free (res.returnmsg);
res = check_tag_quiet( tif, TIFFTAG_DATETIME);
free (res.returnmsg);
if (res.returncode == 0) {
res = check_datetime( tif );
free (res.returnmsg);
if (0 != res.returncode) {is_valid++;}
}
is_valid += execute_plan(tif);
if (is_valid > 0) {
printf("found %i errors\n", is_valid);
} else {
printf("the given tif is valid\n");
}
//print_plan_results();
TIFFClose(tif);
return is_valid;
}


/** main */
int main (int argc, char * argv[]) {
printf("'%s' version: %s\n", argv[0], VERSION);
printf("licensed under conditions of libtiff (see http://libtiff.maptools.org/misc.html)\n");
int c;
int flag_check_directory=UNFLAGGED;
int flag_use_memorymapped_io=UNFLAGGED;
const char * reportfilename = NULL;
while ((c = getopt (argc, argv, "hmd")) != -1) {
switch (c)
{
case 'h': /* help */
help();
exit (0);
case 'd': /* check directory */
flag_check_directory = FLAGGED;
printf("\nCheck all files in given directory\n");
break;
case 'm': /* use memory mapped I/O */
flag_use_memorymapped_io=FLAGGED;
break;
case '?': /* something goes wrong */
/*
if (optopt == 'r') {
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
return (-1);
}
else*/ if (isprint (optopt)) {
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
return (-1);
}
else if (0 !=optopt) {
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
return (-1);
}
break;
default:
abort();
}


}
if (argc - optind != 2) {
help();
fprintf( stderr, "%s needs at least two arguments, first should be the tiff-filename, second the config-file, example:\n\t %s tiffs_should_pass/minimal_valid.tiff example_configs/baseline_minimal.cfg\n", argv[0], argv[0]);
exit (EXIT_FAILURE);
}
const char *tiff_file_or_dir=argv[optind];
const char *cfg_file=argv[optind+1];

printf("cfg_file=%s\n", cfg_file);
int is_valid = 0;

if (flag_check_directory == FLAGGED) {
/* iterate through all files */
size_t len = strlen( tiff_file_or_dir);
char tiff_dir [ len ];
strncpy(tiff_dir, tiff_file_or_dir, len);
tiff_dir[ len ] = 0;
/* printf ("tiffdir='%s'\n\n", tiff_dir);*/
DIR *dir;
struct dirent *ent;
/* remove trailing / */
char *dirsuffix = strrchr(tiff_dir, '/');
if (dirsuffix != NULL) { /* found a / */
/* printf ("len = %i dir = '%s' dirsuffix = '%s'\n", len, tiff_dir, dirsuffix);*/
if ( 0 == strcmp( dirsuffix, "/" ) ) { /* ok, ends with / */
/* remove last / */
assert(len >= 1); // or whatever you want to do with short strings
tiff_dir[len-1] = 0;
/* printf("tiffdir2 = '%s'\n", tiff_dir); */
}
}

/* iterate through all files in given dir */
if ((dir = opendir (tiff_file_or_dir)) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
struct stat attribute;
int len = strlen( tiff_dir ) + strlen( ent->d_name ) + 2;
char fqname [ len ];
snprintf( fqname, len, "%s/%s", tiff_dir, ent->d_name);
if (stat( fqname, &attribute) == -1) {
fprintf (stderr, "could not stat on file '%s' in directory '%s' (%s)\n", ent->d_name, tiff_dir, fqname);
exit(EXIT_FAILURE);
}
if(attribute.st_mode & S_IFREG) {
/* printf ("%s\n", fqname); */
parse_plan_via_file(cfg_file);
is_valid += check_specific_tiff_file( fqname, flag_use_memorymapped_io);
clean_plan();
printf("\n");

}
}
closedir (dir);
} else {
/* could not open directory */
fprintf( stderr, "directory '%s' could not be opened\n", tiff_file_or_dir);
exit(EXIT_FAILURE);
}
} else {
/* use tiff_file_or_dir */
parse_plan_via_file(cfg_file);
is_valid = check_specific_tiff_file( tiff_file_or_dir, flag_use_memorymapped_io);
clean_plan();
}
if (0 == is_valid) {
exit(EXIT_SUCCESS);
} else {
exit(EXIT_FAILURE);
}
}

+ 1817
- 0
config_dsl.grammar.c
File diff suppressed because it is too large
View File


+ 107
- 0
config_dsl.grammar.peg View File

@@ -0,0 +1,107 @@
# rule based checks if given TIFF is a specific baseline TIFF
#
# author: Andreas Romeyke, 2015
# licensed under conditions of libtiff
# (see http://libtiff.maptools.org/misc.html)
#

start <- ( Line )+ EndOfFile
Line <- Comment { incrlineno(); commentline(); }
/ SpaceLine { incrlineno(); }
/ Tagline { incrlineno(); tagline(); }
/ < MiscUntilEOL > { set_parse_error("wrong line entry",yytext); }
Comment <- '#' ( !EndOfLine . )* EndOfLine
Tagline <- Tag Semicolon Requirements Semicolon Values EndOfLine { rule_addtag_config(); }
/ Tag Semicolon Requirements Semicolon Values { set_parse_error( "tagline requires EOL", yytext); }
/ Tag Semicolon Requirements Semicolon { set_parse_error("tagline requires values", yytext); }
/ Tag Semicolon Requirements { set_parse_error("tagline expects missed semicolon here", yytext); }
/ Tag Semicolon { set_parse_error("tagline requires a requiemrent-keyword (mandatory, etc.)",yytext); }
/ Tag { set_parse_error("tagline expects missed semicolon here", yytext); }
Tag <- < ( Digit )+ > {
int tag = atoi(yytext);
/* rule_tagorder_in_dsl( tag ); */
settag( tag );
}
/ < MiscUntilEOL > { set_parse_error("wrong tag", yytext);}
TagReference <- Number
/ < MiscUntilEOL > { set_parse_error("wrong tagreference", yytext); }
Semicolon <- ';' ( Space )*
/ < MiscUntilEOL > { set_parse_error("missed semicolon", yytext);}
Requirements <- 'mandatory' { set_mandatory(); }
/ IfDepends { set_ifdepends(); }
/ OptDepends { set_optdepends(); }
/ 'optional' { set_optional(); }
/ < MiscUntilEOL > { set_parse_error("wrong requirements-keyword", yytext);}
IfDepends <- 'depends' OpenBracket TagReference Dot ValueReference ClosingBracket
/ 'depends' OpenBracket TagReference Dot ValueReference { set_parse_error("requirement expects a closing bracket", yytext); }
/ 'depends' OpenBracket TagReference Dot { set_parse_error("requirement expects a value reference", yytext); }
/ 'depends' OpenBracket TagReference { set_parse_error("requirement expects a dot", yytext); }
/ 'depends' OpenBracket { set_parse_error("requirement expects a tagreference", yytext); }
/ 'depends' { set_parse_error("requirement expects an open bracket", yytext); }

OptDepends <- 'optdepends' OpenBracket TagReference Dot ValueReference ClosingBracket
/ 'optdepends' OpenBracket TagReference Dot ValueReference { set_parse_error("requirement expects a closing bracket", yytext); }
/ 'optdepends' OpenBracket TagReference Dot { set_parse_error("requirement expects a value reference", yytext); }
/ 'optdepends' OpenBracket TagReference { set_parse_error("requirement expects a dot", yytext); }
/ 'optdepends' OpenBracket { set_parse_error("requirement expects a tagreference", yytext); }
/ 'optdepends' { set_parse_error("requirement expects an open bracket", yytext); }


Values <- Any
/ Range
/ LogicalOr
/ Only
/ RegEx
/ < MiscUntilEOL > { set_parse_error("wrong values-keyword", yytext);}
Range <- 'range' OpenBracket Number Colon Number ClosingBracket {set_range(); }
/ 'range' OpenBracket Number Colon Number { set_parse_error("values expects a closing bracket", yytext); }
/ 'range' OpenBracket Number Colon { set_parse_error("values expects a number", yytext); }
/ 'range' OpenBracket Number { set_parse_error("values expects a colon", yytext); }
/ 'range' OpenBracket { set_parse_error("values expects a number", yytext); }
/ 'range' { set_parse_error("values expects an open bracket", yytext); }
Number <- < ( Digit )+ > { i_push(atol(yytext) );}
/ < MiscUntilEOL > { set_parse_error("number expected", yytext);}
Colon <- ',' (Space )*
/ < MiscUntilEOL > { set_parse_error("missed colon", yytext);}
Dot <- '.' (Space )*
/ < MiscUntilEOL > { set_parse_error("missed dot", yytext)}
OpenBracket <- '('
/ < MiscUntilEOL > { set_parse_error("missed open bracket", yytext); }
ClosingBracket <- ')'
/ < MiscUntilEOL > { set_parse_error("missed closing bracket", yytext); }

LogicalOr <- 'logical_or' OpenBracket ValueList ClosingBracket { set_logical_or(); }
/ 'logical_or' OpenBracket ValueList { set_parse_error("values expects a closing bracket", yytext);}
/ 'logical_or' OpenBracket { set_parse_error("values expects a value list", yytext);}
/ 'logical_or' { set_parse_error("values expects an open bracket", yytext);}
ValueList <- Value (Colon Value)*
Value <- Number { incr_values(); }
ValueReference <- 'any' { set_any_reference(); }
/ Number
# / String
/ < MiscUntilEOL > { set_parse_error("value reference error: '%s'", yytext);}
Only <- 'only' OpenBracket ValueList ClosingBracket { set_only(); }
/ 'only' OpenBracket ValueList { set_parse_error("values expects a closing bracket", yytext);}
/ 'only' OpenBracket { set_parse_error("values expects a value list", yytext);}
/ 'only' { set_parse_error("values expects an open bracket", yytext);}
RegEx <- 'regex' OpenBracket '"' < ( PCRE )* > '"' ClosingBracket { set_regex( yytext ); }
/ 'regex' OpenBracket '"' < ( PCRE )* > '"' { set_parse_error("expects a closing bracket", yytext); }
/ 'regex' OpenBracket '"' < ( PCRE )* > { set_parse_error("expects a closing '\"'", yytext); }
/ 'regex' OpenBracket '"' { set_parse_error("expects a PCRE-regex", yytext); }
/ 'regex' OpenBracket { set_parse_error("expects an open '\"'", yytext); }
/ 'regex' { set_parse_error("expects an open bracket", yytext); }
SpaceLine <- Space? EndOfLine
Space <- ' ' / '\t'
Any <- 'any' { set_any(); }
Digit <- [0-9]
#String <- '"' < ( [A-Za-z0-9- :] )* > '"' { s_push ( yytext ); }
EndOfLine <- '\r\n' / '\n' / '\r'
EndOfFile <- !.
MiscUntilEOL <- ( [^\r\n]+ )
PCRE <- EscapedPCRE
/ [^"\\]
# FIXME: unescape char in yybuffer
EscapedPCRE <- '\\' '\\'
/ '\\' '"'



+ 905
- 0
config_parser.c View File

@@ -0,0 +1,905 @@
/* rule based checks if given TIFF is a specific baseline TIFF
*
* author: Andreas Romeyke, 2015
* licensed under conditions of libtiff
* (see http://libtiff.maptools.org/misc.html)
*
*/

// #define YY_DEBUG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "config_parser.h"
#include "check.h"
#include "check_helper.h"
#include <pcre.h>

/*
#define DEBUG
*/

#define YY_CTX_LOCAL

/* global vars */
parser_state_t parser_state;
executionplan_t plan;

/* redefined YY_INPUT to read from stream */
#define YY_INPUT(yyctx, buf, result, max_size) \
{ \
int yyc= fgetc(parser_state.stream); \
result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \
yyprintf((stderr, "<%c>", yyc)); \
}


/* type specific calls of function pointers
* @param tif pointer to libtiff TIIFF structure
* @param fp pointer to funcu structure to hold function and its parameters
* @return ret_t structure for results of called function
*/
ret_t call_fp(TIFF* tif, funcp fp) {
ret_t ret;
ret.returncode=1;
ret.returnmsg=NULL; /*@null@*/
if (NULL != fp) {
switch (fp->ftype) {
case f_dummy: break;
case f_tifp:
{
f_tifp_t * function = NULL;
function = fp->fu.ftifp;
assert(NULL != function);
assert(NULL != function->functionp);
ret = (function->functionp)(tif);
break;
}
case f_tifp_tag:
{
f_tifp_tag_t * function = NULL;
function = fp->fu.ftifp_tag;
assert(NULL != function);
assert(NULL != function->functionp);
ret = (function->functionp)(tif, function->a);
break;
}
case f_tifp_tag_uint:
{
f_tifp_tag_uint_t * function = NULL;
function = fp->fu.ftifp_tag_uint;
assert(NULL != function);
assert(NULL != function->functionp);
#ifdef DEBUG
printf("debug: found a=%i b=%u\n", function->a, function->b);
#endif
ret = (function->functionp)(tif, function->a, function->b);
break;
}
case f_tifp_tag_uint_uint:
{
f_tifp_tag_uint_uint_t * function = NULL;
function = fp->fu.ftifp_tag_uint_uint;
assert(NULL != function);
assert(NULL != function->functionp);
#ifdef DEBUG
printf("debug: found a=%i b=%u c=%u\n", function->a, function->b, function->c);
#endif
ret = (function->functionp)(tif, function->a, function->b, function->c);
break;
}
case f_tifp_tag_int_uintp:
{
f_tifp_tag_int_uintp_t * function = NULL;
function = fp->fu.ftifp_tag_int_uintp;
assert(NULL != function);
assert(NULL != function->functionp);
#ifdef DEBUG
printf("debug: found a=%i b=%i c=%p\n", function->a, function->b, function->c);
#endif
ret = (function->functionp)(tif, function->a, function->b, function->c);
break;
}
case f_tifp_tag_charp:
{
f_tifp_tag_charp_t * function = NULL;
function = fp->fu.ftifp_tag_charp;
assert(NULL != function);
assert(NULL != function->functionp);
#ifdef DEBUG
printf("debug: found a=%i b=%s\n", function->a, function->b);
#endif
ret = (function->functionp)(tif, function->a, function->b);
break;
}

default:
fprintf(stderr, "call_fp() error, should not occure!\n");
exit(EXIT_FAILURE);
}
}
return ret;
}

/* executes a plan (list) of functions, checks if predicate-function calls are
* needed, too. The plan is a global variable.
* @param tif pointer to TIFF structure
* @return return-code is 0 if all called functions are succeed
*/
int execute_plan (TIFF * tif) {
executionentry_t * this_exe_p = plan.start;
int is_valid = 0; /* 0 means valid, >0 invalid */
while (NULL != this_exe_p) {
#ifdef DEBUG
printf("\n\nexecute: %s\n", this_exe_p->name);
#endif
funcp fp;
fp = this_exe_p->fu_p;
ret_t res;
if (NULL != fp) {
#ifdef DEBUG
printf("execute: fp not null\n");
#endif
if (NULL != fp->pred) { /* we have a predicate function, call it and
decide if we continue or not */
#ifdef DEBUG
printf("execute: we have a predicate... ");
#endif
/* has the predicate a predicate? */
if (NULL != fp->pred->pred) { /* yes */
#ifdef DEBUG
printf("execute: we have a predicate predicate... ");
#endif
res = call_fp(tif, fp->pred->pred);
if (0 != res.returncode ) {
#ifdef DEBUG
printf("execute: predicate predicate was not successfull\n");
#endif
this_exe_p->result.returncode=0;
this_exe_p->result.returnmsg=strdup("predicate predicate was not successfull, skipped check");
goto exitcall;
/* the predicate was not successfull, skip check */
} else { /* predicate predicate successfull*/
#ifdef DEBUG
printf("execute: predicate predicate was successfull\n");
#endif
}
};
/* no predicate predicate or predicate predicate successfull*/
res = call_fp(tif, fp->pred);
if (0 != res.returncode ) {
#ifdef DEBUG
printf("execute: predicate was not successfull\n");
#endif
this_exe_p->result.returncode=0;
this_exe_p->result.returnmsg=strdup("predicate was not successfull, skipped check");
/* the predicate was not successfull, skip check */
goto exitcall;
} else {
/* predicate was successful */
#ifdef DEBUG
printf("execute: predicate was successfull\n");
#endif
}
}
/* no predicate or predicate successfull*/
parser_state.called_tags[fp->tag]++;
this_exe_p->result= call_fp (tif, fp );
if (0 != this_exe_p->result.returncode) { is_valid++; }
}
exitcall: this_exe_p = this_exe_p->next;
}
/* now we know which tags are already checked, we need add a rule to
* forbidden all other tags */
printf("check if forbidden tags are still existing\n");
int tag;
for (tag=MINTAGS; tag<MAXTAGS; tag++) {
if (0 == parser_state.called_tags[tag]) { /* only unchecked tags */
ret_t res = check_notag( tif, tag);
if (0 != res.returncode) { /* check if tag is not part of tif */
/* tag does not exist */
is_valid++;
}
}
}
return (is_valid);
}

/* prints a plan (list) of functions */
/*
void print_plan () {
printf("print plan:\n");
executionentry_t * this_exe_p = plan.start;
while (NULL != this_exe_p) {
printf("next action is: %s\n", this_exe_p->name);
this_exe_p = this_exe_p->next;
}
}
*/

/* prints a plan (list) of functions and their results*/
void print_plan_results() {
printf("print plan results:\n");
executionentry_t * this_exe_p = plan.start;
while (NULL != this_exe_p) {
const char * msg;
if (0 == this_exe_p->result.returncode) {
msg = strdup("passed");
} else {
msg=strdup(this_exe_p->result.returnmsg);
}
printf("action was: %s, result=%s\n", this_exe_p->name, msg);
this_exe_p = this_exe_p->next;
}
}



/* adds a function to an execution plan
*
* the plan is a global variable
* @param fp is a pointer to function
* @param name is a string of fname
* @return retirn 0 if succeed
*/
int append_function_to_plan (funcp fp, const char * name ) {
assert(NULL != fp);
assert(NULL != name);
executionentry_t * entry = NULL;
entry = malloc ( sizeof(executionentry_t) );
if (NULL == entry) {
fprintf(stderr, "could not alloc memory for execution plan");
exit(EXIT_FAILURE);
}
entry->next = NULL;
entry->fu_p = fp;
entry->result.returncode = 0;
entry->result.returnmsg = NULL;
entry->name = malloc ( MAXSTRLEN*sizeof(char) );
if (NULL == entry->name) {
fprintf(stderr, "could not alloc memory for execution plan");
exit(EXIT_FAILURE);
}
assert(NULL != name);
strncpy(entry->name, name, MAXSTRLEN-1);
#ifdef DEBUG
printf("entry has name:%s\n", entry->name);
#endif
entry->result.returncode = 0;
entry->result.returnmsg = NULL;

assert(NULL != entry);
if (NULL == plan.start) {
#ifdef DEBUG
printf(" add first to plan\n");
#endif
plan.start = entry;
plan.last = entry;
assert(NULL != plan.last);
assert(NULL == plan.last->next);
} else {
#ifdef DEBUG
printf(" add n-th to plan\n");
#endif
assert(NULL != plan.last);
assert(NULL == plan.last->next);
executionentry_t * last = NULL;
last = plan.last;
assert(NULL != last);
assert(NULL == last->next);
last->next = entry;
plan.last = entry;
}
return 0;
}

/* adds a function to struct funcu * f
* @param f already allocated struct funcu * pointer
* @param function adress of function
* @param fname name of function as combined message (already allocated)
*/
void _helper_add_fsp_tifp(struct funcu * f, ret_t (* function)(TIFF *), char * fname) {
/* create datastruct for fp */
struct f_tifp_s * fsp = NULL;
fsp = malloc( sizeof( struct f_tifp_s ));
if (NULL == fsp) {
fprintf (stderr, "could not alloc mem for fsp\n");
exit(EXIT_FAILURE);
};
fsp->functionp = function;
f->ftype = f_tifp;
f->fu.ftifp = fsp;

}


/* adds a function to struct funcu * f
* @param f already allocated struct funcu * pointer
* @param function adress of function
* @param fname name of function as combined message (already allocated)
* @param tag tag
*/
void _helper_add_fsp_tifp_tag(struct funcu * f, ret_t (* function)(TIFF *, tag_t), char * fname, tag_t tag) {
struct f_tifp_tag_s * fsp = NULL;
fsp = malloc( sizeof( struct f_tifp_tag_s ));
if (NULL == fsp) {
fprintf (stderr, "could not alloc mem for fsp\n");
exit(EXIT_FAILURE);
};
fsp->a = tag;
fsp->functionp = function;
f->ftype = f_tifp_tag;
f->fu.ftifp_tag = fsp;
}


/* adds a function to struct funcu * f
* @param f already allocated struct funcu * pointer
* @param function adress of function
* @param fname name of function as combined message (already allocated)
* @param tag tag
* @param v param a for function
*/
void _helper_add_fsp_tifp_tag_uint(struct funcu * f, ret_t (* function)(TIFF *, tag_t, unsigned int), char * fname, tag_t tag, unsigned int v) {
/* create datastruct for fp */
struct f_tifp_tag_uint_s * fsp = NULL;
fsp = malloc( sizeof( struct f_tifp_tag_uint_s ));
if (NULL == fsp) {
fprintf (stderr, "could not alloc mem for fsp\n");
exit(EXIT_FAILURE);
};
fsp->a = tag;
fsp->b = v;
fsp->functionp = function;
f->ftype = f_tifp_tag_uint;
f->fu.ftifp_tag_uint = fsp;
}

/* adds a function to struct funcu * f
* @param f already allocated struct funcu * pointer
* @param function adress of function
* @param fname name of function as combined message (already allocated)
* @param tag tag
* @param v param a for function
*/
void _helper_add_fsp_tifp_tag_charp(struct funcu * f, ret_t (* function)(TIFF *, tag_t, const char *), char * fname, tag_t tag, const char * v) {
/* create datastruct for fp */
struct f_tifp_tag_charp_s * fsp = NULL;
fsp = malloc( sizeof( struct f_tifp_tag_charp_s ));
if (NULL == fsp) {
fprintf (stderr, "could not alloc mem for fsp\n");
exit(EXIT_FAILURE);
};
fsp->a = tag;
fsp->b = strdup(v);
fsp->functionp = function;
f->ftype = f_tifp_tag_charp;
f->fu.ftifp_tag_charp = fsp;
}


/* adds a function to struct funcu * f
* @param f already allocated struct funcu * pointer
* @param function adress of function
* @param fname name of function as combined message (already allocated)
* @param tag tag
* @param count_of_values count of parameters for function
* @param rp pointer to parameter values
*/
void _helper_add_fsp_tifp_tag_uint_uintp(struct funcu * f, ret_t (* function)(TIFF *, tag_t, int, unsigned int *), char * fname, tag_t tag, int count_of_values, unsigned int * rp) {
/* create datastruct for fp */
#ifdef DEBUG
printf("count of values = %i\n", count_of_values);
#endif
struct f_tifp_tag_int_uintp_s * fsp = NULL;
fsp = malloc( sizeof( struct f_tifp_tag_int_uintp_s ));
if (NULL == fsp) {
fprintf (stderr, "could not alloc mem for fsp\n");
exit(EXIT_FAILURE);
};
fsp->a = tag;
fsp->b = count_of_values;
fsp->c = rp;
fsp->functionp = function;
f->ftype = f_tifp_tag_int_uintp;
f->fu.ftifp_tag_int_uintp = fsp;
}

/* adds a function to struct funcu * f
* @param f already allocated struct funcu * pointer
* @param function adress of function
* @param fname name of function as combined message (already allocated)
* @param tag tag
* @param l param a for function
* @param r param b for function
*/
void _helper_add_fsp_tifp_tag_uint_uint(struct funcu * f, ret_t (* function)(TIFF *, tag_t, unsigned int, unsigned int), char * fname, tag_t tag, unsigned int l, unsigned int r) {
/* create datastruct for fp */
struct f_tifp_tag_uint_uint_s * fsp = NULL;
fsp = malloc( sizeof( struct f_tifp_tag_uint_uint_s ));
if (NULL == fsp) {
fprintf (stderr, "could not alloc mem for fsp\n");
exit(EXIT_FAILURE);
};
fsp->a = tag;
fsp->b = l;
fsp->c = r;
fsp->functionp = function;
f->ftype = f_tifp_tag_uint_uint;
f->fu.ftifp_tag_uint_uint = fsp;
}



/* stack function for parser */
void i_push (unsigned int i) {
if (parser_state.i_stackp >= 40) {
fprintf(stderr, "stackoverflow in i_stack\n");
exit(EXIT_FAILURE);
}
parser_state.i_stack[parser_state.i_stackp++] = i;
}
/* stack function for parser */
unsigned int i_pop () {
if (parser_state.i_stackp <= 0) {
fprintf(stderr, "stackunderflow in i_stack\n");
exit(EXIT_FAILURE);
}
return parser_state.i_stack[--parser_state.i_stackp];
}

void clean_funcp (funcp p) {
if (NULL != p) {
if (NULL != p->pred) {
clean_funcp( p->pred);
p->pred=NULL;
}
switch( p->ftype ) {
case f_tifp_tag_int_uintp:
if (NULL != p->fu.ftifp_tag_int_uintp->c) {
free(p->fu.ftifp_tag_int_uintp->c);
p->fu.ftifp_tag_int_uintp->c = NULL;
}
if (NULL != p->fu.ftifp_tag_int_uintp) {
free(p->fu.ftifp_tag_int_uintp);
p->fu.ftifp_tag_int_uintp=NULL;
}
break;
/* f_tifp, f_tifp_tag, f_tifp_tag_uint, f_tifp_tag_uint_uint, */
case f_tifp:
if (NULL != p->fu.ftifp) {
free(p->fu.ftifp);
p->fu.ftifp=NULL;
}
break;
case f_tifp_tag:
if (NULL != p->fu.ftifp_tag) {
free(p->fu.ftifp_tag);
p->fu.ftifp_tag=NULL;
}
break;
case f_tifp_tag_uint:
if (NULL != p->fu.ftifp_tag_uint) {
free(p->fu.ftifp_tag_uint);
p->fu.ftifp_tag_uint=NULL;
}
break;
case f_tifp_tag_uint_uint:
if (NULL != p->fu.ftifp_tag_uint_uint) {
free(p->fu.ftifp_tag_uint_uint);
p->fu.ftifp_tag_uint_uint=NULL;
}
break;
default: ;
}
free (p);
p=NULL;
}
}


/* function to clean an execution plan */
void clean_plan () {
/*executionentry_t * last = plan.last; */
executionentry_t * entry = plan.start;
if (NULL != entry) {
while (entry->next) {
executionentry_t * next = entry->next;
if (NULL != entry->name) {
free (entry->name);
entry->name=NULL;
}
if (
(NULL != entry->result.returnmsg) &&
(0 != entry->result.returncode)
) {
free(entry->result.returnmsg);
entry->result.returnmsg = NULL;
}
clean_funcp(entry->fu_p);
free (entry);
entry = next;
}
}
plan.last = NULL;
plan.start = NULL;
}



/* helper function for parser */
tag_t settag( tag_t tag) { parser_state.tag=tag; return tag; }
/* helper function for parser */
tag_t gettag( ) { return parser_state.tag;}
int incrlineno() {
parser_state.lineno++;
#ifdef DEBUG
printf("##lineno=%i\n", parser_state.lineno);
#endif
return parser_state.lineno;
}
/* helper function for parser */
int getlineno() { return parser_state.lineno;}

/*
int rule_tagorder_in_dsl( int tag ) {
int prevtag = gettag();