diff options
author | Ben Wagner <bungeman@chromium.org> | 2022-06-15 16:07:22 -0400 |
---|---|---|
committer | Ben Wagner <bungeman@chromium.org> | 2022-06-16 14:51:57 +0000 |
commit | 9079521002231862d5202ff7ec8d628e27972673 (patch) | |
tree | 7bc27a6a99f20f1d0a07b576d5a21f809b335d68 | |
parent | d6fc8c6ba02b3c0e4260b5d309e6a6a0fac9541c (diff) | |
download | freetype2-9079521002231862d5202ff7ec8d628e27972673.tar.gz |
[type1] Directly search for eexec in private dict
This code originally just searched for `eexec`. This was later modified
to check that the `eexec` found is valid (not in a string or comment).
This was done by searching for `eexec` as before and then, for each
`eexec` found, searching from the beginning using the correct parsing to
see if the `eexec` was still found. If the private dictionary is large
and contains many copies of `eexec` which are not valid, the initial
part of the private dictionary is scanned once for each, potentially
leading to n^2 parsing time.
Instead of finding an initial `eexec` and then re-parsing to discover if
it is valid, drop the initial search for `eexec` and just parse to find
a valid `eexec`. This is strictly faster since the validation must
happen anyway and avoids restarting from the beginning each time an
`eexec` is found in the data.
* src/type1/t1parse.c (T1_Get_Private_Dict): avoid n^2 parsing
Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1328883
-rw-r--r-- | src/type1/t1parse.c | 55 |
1 files changed, 9 insertions, 46 deletions
diff --git a/src/type1/t1parse.c b/src/type1/t1parse.c index 95dc97d79..af9df3222 100644 --- a/src/type1/t1parse.c +++ b/src/type1/t1parse.c @@ -330,50 +330,25 @@ /* the private dict. Otherwise, simply overwrite into the base */ /* dictionary block in the heap. */ - /* first of all, look at the `eexec' keyword */ + /* First look for the `eexec' keyword. Ensure `eexec' is real -- */ + /* it could be in a comment or string (as e.g. in u003043t.gsf */ + /* from ghostscript). */ FT_Byte* cur = parser->base_dict; FT_Byte* limit = cur + parser->base_len; FT_Pointer pos_lf; FT_Bool test_cr; - Again: - for (;;) - { - if ( cur[0] == 'e' && - cur + 9 < limit ) /* 9 = 5 letters for `eexec' + */ - /* whitespace + 4 chars */ - { - if ( cur[1] == 'e' && - cur[2] == 'x' && - cur[3] == 'e' && - cur[4] == 'c' ) - break; - } - cur++; - if ( cur >= limit ) - { - FT_ERROR(( "T1_Get_Private_Dict:" - " could not find `eexec' keyword\n" )); - error = FT_THROW( Invalid_File_Format ); - goto Exit; - } - } - - /* check whether `eexec' was real -- it could be in a comment */ - /* or string (as e.g. in u003043t.gsf from ghostscript) */ - parser->root.cursor = parser->base_dict; - /* set limit to `eexec' + whitespace + 4 characters */ - parser->root.limit = cur + 10; + parser->root.limit = parser->base_dict + parser->base_len; cur = parser->root.cursor; limit = parser->root.limit; while ( cur < limit ) { - if ( cur[0] == 'e' && - cur + 5 < limit ) + /* 9 = 5 letters for `eexec' + whitespace + 4 chars */ + if ( cur[0] == 'e' && cur + 9 < limit ) { if ( cur[1] == 'e' && cur[2] == 'x' && @@ -389,21 +364,9 @@ cur = parser->root.cursor; } - /* we haven't found the correct `eexec'; go back and continue */ - /* searching */ - - cur = limit; - limit = parser->base_dict + parser->base_len; - - if ( cur >= limit ) - { - FT_ERROR(( "T1_Get_Private_Dict:" - " premature end in private dictionary\n" )); - error = FT_THROW( Invalid_File_Format ); - goto Exit; - } - - goto Again; + FT_ERROR(( "T1_Get_Private_Dict: could not find `eexec' keyword\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; /* now determine where to write the _encrypted_ binary private */ /* dictionary. We overwrite the base dictionary for disk-based */ |