Browse Source

- renewed grammar, supports now real logical_or()

- renewed grammar, value reference supports any(), number(), range(), regex(), only() and ntupel()
- renewed grammar, only() allows no tupel values anymore
- renewed grammar, added ntupel()
- added some constraints
pull/4/head
Andreas Romeyke 5 years ago
parent
commit
86457d7570
  1. 67
      README.grammar
  2. 188
      src/parser/config_dsl.grammar.peg

67
README.grammar

@ -1,54 +1,63 @@
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.
The checkit-tool validates TIFF-files against a set of rules (see below). The
set of rules works as a whitelist. This means that TIFF tags that are used in
the file but not explicitely checked by a specific rule (not considering if
successful or not) are not allowed. In cases where a rule is executed only
if a predicate is set, the tag is only allowed if the predicate check succeeded.
Developers
==========
to configure the grammar you could use the PEG-extension for gvim from https://github.com/gf3/peg.vim
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
To define your own config-file for checking TIFFs, please use this simplified
syntax:
* each line is either a modeline, a include line, a tagline, a comment or empty
* a modeline uses "mode(MODE)", MODE could be:
* Each line is either a "modeline", an "include" line, a "tag" line, a comment or empty
* TODO: a modeline uses "mode(MODE)", MODE could be:
** "baseline", if no modeline is defined, it defaults to "mode(baseline)", too
** "extended"
* to include a configfile, use this command: "include(FILENAME)" where FILENAME is a correct path
* 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
* To include a configfile, use "include(FILENAME)", where FILENAME is a correct path
* Comments starts with '# '. They are only allowed to start right at the beginning of a new line.
* A tagline is built as "TAG; REQUIREMENTS; VALUES", where
* a TAG is an increasing number similar to TIFF-Tag numbers (see TIFF specification)
* 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 '"'
** 'optional' - a tag may exist in TIFF, if it does, it will be checked
** 'depends(REFERENCE)' - a tag must exist in TIFF if reference exists
** 'optdepends(REFERENCE)' - a tag may exists in TIFF if reference exists. If it exists it will be checked
* The syntax for a REFERENCE is TAGREFERENCE.VALUEREFERENCE
** TAGREFERENCE points to a tag number which must be exist,
** VALUEREFERENCE can be one of:
*** 'any' (which means any match) or
*** a decimal value or
*** 'greater_than(VALUE)', where VALUE is a decimal value or
*** 'less_than(VALUE)', where VALUE is a decimal value or
*** 'regex("REGEX")', where REGEX is a Perl compatible regular expression (PCRE) with escaped '"' and '\'. It only works with tags of type ascii
** 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
** The REQUIREMENTS rule will only be checked if REFERENCE exists in the TIF
file.
* VALUES can be one of:
** 'range(START, END)', where START and END are decimal values
** 'logical_or( VALUELIST)', where VALUELIST are comma-separated decimale values or ntupels
** 'any', which means any match
** 'only(VALUE)', where VALUE is a decimal value
** 'ntupel(VALUE, ..), decimal values as n-tupel enclosed in brackets
** 'regex("REGEX")', where REGEX is a Perl compatible regular expression (PCRE) 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.
If multiple rules are defined per tag, they will be combined.
For examples check the 'example_configs/' - directory.
For examples, please 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
handling easier, it uses only the value/offset part of an IFD entry.

188
src/parser/config_dsl.grammar.peg

@ -5,113 +5,133 @@
# (see http://libtiff.maptools.org/misc.html)
#
start <- ( Line )+ EndOfFile
Line <- CommentLine EndOfLine
/ SpaceLine EndOfLine
/ ModeLine EndOfLine
/ IncludeLine EndOfLine
/ TagLine EndOfLine
/ < MiscUntilEOL > { set_parse_error("wrong line entry",yytext); }
CommentLine <- '#' ( !EndOfLine . )* { commentline(); }
start <- ( Line )+ EndOfFile
Line <- CommentLine EndOfLine
/ SpaceLine EndOfLine
/ ModeLine EndOfLine
/ IncludeLine EndOfLine
/ TagLine EndOfLine
/ < MiscUntilEOL > { set_parse_error("wrong line entry",yytext); }
CommentLine <- '#' ( !EndOfLine . )* { commentline(); }
IncludeLine <- 'include' OpenBracket < ( [A-Za-z0-9_./\-]+ ) > ClosingBracket { set_include ( yytext ); }
ModeLine <- 'mode' OpenBracket < Mode > ClosingBracket { set_mode( yytext ); }
/ 'mode' OpenBracket Mode { set_parse_error( "modeline expects a closing bracket", yytext); }
/ 'mode' OpenBracket { set_parse_error( "modeline requires a mode", yytext); }
/ 'mode' { set_parse_error( "modeline requires an open bracket", yytext); }
ModeLine <- 'mode' OpenBracket < Mode > ClosingBracket { set_mode( yytext ); }
/ 'mode' OpenBracket Mode { set_parse_error( "modeline expects a closing bracket", yytext); }
/ 'mode' OpenBracket { set_parse_error( "modeline requires a mode", yytext); }
/ 'mode' { set_parse_error( "modeline requires an open bracket", yytext); }
LogicalOr <- 'logical_or' OpenBracket LogicalOrList ClosingBracket { rule_add_logical_config(); reset_logical_list();}
Mode <- 'baseline'
/ 'enhanced'
/ MiscUntilEOL { set_parse_error("mode expects either 'baseline' or 'enhanced'", yytext); }
TagLine <- Tag Semicolon Requirements Semicolon Values { rule_addtag_config(); }
/ 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);
LogicalOrListElement <- Any { v_push( any );incr_logical_elements(); }
/ Range { v_push( range);incr_logical_elements(); }
/ Only { v_push( only );incr_logical_elements(); }
/ Number { v_push( only );incr_logical_elements(); }
/ NTupel { v_push( ntupel); reset_valuelist(); incr_logical_elements(); }
/ RegEx { v_push( regex );incr_logical_elements(); }
/ < MiscUntilEOL > { set_parse_error("wrong values-keyword", yytext);}
LogicalOrList <- LogicalOrListElement (Colon LogicalOrListElement)*
Mode <- 'baseline'
/ 'enhanced'
/ MiscUntilEOL { set_parse_error("mode expects either 'baseline' or 'enhanced'", yytext); }
TagLine <- Tag Semicolon Requirements Semicolon Content { rule_addtag_config(); }
/ Tag Semicolon Requirements Semicolon { set_parse_error("tagline requires content", 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 <- < Number > {
int tag = i_pop();
/* rule_tagorder_in_dsl( tag ); */
settag( tag );
if (tag < 254) set_parse_error("wrong tag (should be >253)", yytext);
else if (tag > 65535) set_parse_error("wrong tag (should be <65536)", yytext);
else settag( tag );
}
TagReference <- < Number > {
int tag = i_pop();
if (tag < 254) set_parse_error("wrong tagreference (should be >253)", yytext);
else if (tag > 65535) set_parse_error("wrong tagreference (should be <65536)", yytext);
else settagref( tag );
}
/ < MiscUntilEOL > { set_parse_error("wrong tag", yytext);}
TagReference <- Number
/ < MiscUntilEOL > { set_parse_error("wrong tagreference", yytext); }
/ < 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);}
/ < 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); }
/ 'depends' OpenBracket TagReference Dot ValueReference { set_parse_error("'depends' expects a closing bracket", yytext); }
/ 'depends' OpenBracket TagReference Dot { set_parse_error("'depends' expects a value reference", yytext); }
/ 'depends' OpenBracket TagReference { set_parse_error("'depends' expects a dot", yytext); }
/ 'depends' OpenBracket { set_parse_error("'depends' expects a tagreference", yytext); }
/ 'depends' { set_parse_error("'depends' 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); }
/ 'optdepends' OpenBracket TagReference Dot ValueReference { set_parse_error("'optdepends' expects a closing bracket", yytext); }
/ 'optdepends' OpenBracket TagReference Dot { set_parse_error("'optdepends' expects a value reference", yytext); }
/ 'optdepends' OpenBracket TagReference { set_parse_error("'optdepends' expects a dot", yytext); }
/ 'optdepends' OpenBracket { set_parse_error("'optdepends' expects a tagreference", yytext); }
/ 'optdepends' { set_parse_error("'optdepends' 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);}
Content <- Any { v_push( any ); }
/ Range { v_push( range); }
/ LogicalOr
/ Only { v_push( only ); }
/ NTupel { v_push( ntupel ); reset_valuelist() }
/ RegEx { v_push( regex ); }
/ < MiscUntilEOL > { set_parse_error("wrong values-keyword", yytext);}
Range <- 'range' OpenBracket Number Colon Number ClosingBracket
/ 'range' OpenBracket Number Colon Number { set_parse_error("'range' expects a closing bracket", yytext); }
/ 'range' OpenBracket Number Colon { set_parse_error("'range' expects a number", yytext); }
/ 'range' OpenBracket Number { set_parse_error("'range' expects a colon", yytext); }
/ 'range' OpenBracket { set_parse_error("'range' expects a number", yytext); }
/ 'range' { set_parse_error("'range' expects an open bracket", yytext); }
Number <- < '0x' ( [0-9a-f]+ ) > { i_push(strtol(yytext, NULL, 0) ); }
/ '2^' < ( Digit )+ > { i_push(2<<atol(yytext) ); }
/ < ( Digit )+ > { i_push(atol(yytext) );}
Colon <- ',' (Space )*
/ < MiscUntilEOL > { set_parse_error("missed colon", yytext);}
Dot <- '.' (Space )*
/ < MiscUntilEOL > { set_parse_error("missed dot", yytext)}
/ < 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); }
Value <- Number { incr_values(); }
NTupel <- 'ntupel' OpenBracket ValueList ClosingBracket {int v=parser_state.valuelist; i_push(v); reset_valuelist(); }
/ 'ntupel' OpenBracket ValueList { set_parse_error("'ntupel' expects a closing bracket", yytext);}
/ 'ntupel' OpenBracket { set_parse_error("'ntupel' expects a value list", yytext);}
/ 'ntupel' { set_parse_error("'ntupel' expects an open bracket", yytext);}
ValueReference <- Any { parser_state.any_reference = any_ref; }
/ Number { parser_state.any_reference = only_ref; i_push(atol(yytext) );}
/ RegEx { parser_state.any_reference = regex_ref; }
/ Range { parser_state.any_reference = range_ref; }
/ NTupel { parser_state.any_reference = ntupel_ref; }
/ Only { parser_state.any_reference = only_ref; }
/ < MiscUntilEOL > { set_parse_error("value reference error: '%s'", yytext);}
Only <- 'only' OpenBracket Number ClosingBracket { }
/ 'only' OpenBracket Number { set_parse_error("'only' expects a closing bracket", yytext);}
/ 'only' OpenBracket { set_parse_error("'only' expects a value list", yytext);}
/ 'only' { set_parse_error("'only' expects an open bracket", yytext);}
RegEx <- 'regex' OpenBracket '"' < ( PCRE )* > '"' ClosingBracket { regex_push ( yytext ); }
/ 'regex' OpenBracket '"' < ( PCRE )* > '"' { set_parse_error("'regex' expects a closing bracket", yytext); }
/ 'regex' OpenBracket '"' < ( PCRE )* > { set_parse_error("'regex' expects a closing '\"'", yytext); }
/ 'regex' OpenBracket '"' { set_parse_error("'regex' expects a PCRE-regex", yytext); }
/ 'regex' OpenBracket { set_parse_error("'regex' expects an open '\"'", yytext); }
/ 'regex' { set_parse_error("'regex' expects an open bracket", yytext); }
SpaceLine <- ( Space )*
Space <- ' ' / '\t'
Any <- 'any' { set_any(); }
Any <- 'any'
Digit <- [0-9]
EndOfLine <- [\r\n] {incrlineno(); }
EndOfLine <- [\r\n] {incrlineno(); }
EndOfFile <- !.
MiscUntilEOL <- [^\r\n]+
PCRE <- EscapedPCRE
/ [^"\\]
/ [^"\\]
# FIXME: unescape char in yybuffer
EscapedPCRE <- '\\' '\\'
/ '\\' '"'
/ '\\' '"'
Loading…
Cancel
Save