JPEG-XL is a new image format standardized by the same committee as the
original JPEG image format. It has all the nice feature of recent
formats, and great compression ratios. For more details, look at:
https://jpegxl.info/
This decoder is far from being feature-complete, as it features a grand
total of 60 FIXMEs and TODOs but anyway, it's still a good start.
I developed this decoder in the Serenity way, I just try to decode a
specific image while staying as close as possible to the specification.
Considering that the format supports a lot of options, and that we
basically support only one possibility for each of them, I'm pretty sure
that we can only decode the image I've developed this decoder for.
Which is:
0aff 3ffa 9101 0688 0001 004c 384b bc41
5ced 86e5 2a19 0696 03e5 4920 8038 000b
The class was an inner class of `BrotliDecompressionStream`, let's move
it outside the `Stream` object in order to ease the access to user only
interested in this part.
These routines:
- read_prefix_code
- read_simple_prefix_code
- read_complex_prefix_code
were methods of `BrotliDecompressionStream` taking a `CanonicalCode` as
an out parameter. This patch puts them in `CanonicalCode` as static
methods.
These passes have not been shown to actually optimize any JS, and tests
have become very flaky with optimizations enabled. Until some measurable
benefit is shown, remove the optimization passes to reduce overhead of
maintaining bytecode operations and to reduce CI churn. The framework
for optimizations will live on in git history, and can be restored once
proven useful.
The Heap::uproot_cell() API was used to implement markAsGarbage() which
was used in 3 tests to forcibly destroy a value, even if it had
references on the stack or elsewhere.
This patch rewrites the 3 tests that used this mechanism to be
structured in a way that allows garbage collection to collect the values
as intended without hacks. And now that the uprooting mechanism is no
longer needed, it's uprooted as well.
This fixes 3 test-js tests in bytecode mode. :^)
We had an edge case where calls to eval() left the environment untainted
*if* `eval` had also been declared as a local variable in the same
parsing context.
This broke the expected direct eval behavior when the variable `eval`
was still pointing at the global `eval` function.
This patch fixes the issue by simply always tainting the environment
when a call to something named `eval` is encountered. It doesn't seem
worth worrying about optimizing the case where someone is calling their
own function named `eval`..
Fixes 1 test-js test in bytecode mode. :^)
GetByValue now shares code with GetById to elide the synthetic wrapper
objects for primitive values in strict mode.
Fixes 2 test-js tests in bytecode mode. :^)
With this, `pdf` can print info for CIPA_DC-003-2020_E.pdf
(from https://cipa.jp/e/std/std-sec.html), as well as all other
files I've tried.
CIPA_DC-003-2020_E.pdf is special because it quits this loop after
exactly 64 interations, at round_number 63.
While here, also update a comment to use the non-spec-comment style
I'm now using elsewhere in the file.
With this, AESV3 support is complete and CIPA_DC-007-2021_E.pdf
can be opened :^)
(CIPA_DC-003-2020_E.pdf incorrectly cannot be opened yet. This
is due to a minor bug in computing_a_hash_r6_and_later() that
I'll fix a bit later. But except for this minor bug, all AESV3
files I've found so far seem to work.)
try_provide_user_password() calls compute_encryption_key_r6_and_later()
now. This checks both owner and user passwords. (For pre-R6 files,
owner password checking isn't yet implemented, as far as I can tell.)
With this, CIPA_DC-007-2021_E.pdf (or other AESV3-encrypted files)
successfully compute a file encryption key (...and then hit the
TODO() in StandardSecurityHandler::crypt() for AESV3, but it's
still good progress.)
...for handlers of revision 6.
The spec for this algorithm has several quirks:
1. It describes how to authenticate a password as an owner password,
but it redundantly inlines the description of algorithm 12 instead
of referring to it. We just call that algorithm here.
2. It does _not_ describe how to authenticate a password as a user
password before using the password to compute the file encryption
key using an intermediate user key, despite the latter step that
computes the file encryption key refers to the password as
"user password". I added a call to algorithm 11 to check if the
password is the user password that isn't in the spec. Maybe I'm
misunderstanding the spec, but this looks like a spec bug to me.
3. It says "using AES-256 in ECB mode with an initialization vector
of zero". ECB mode has no initialization vector. CBC mode with
initialization vector of zero for message length 16 is the same
as ECB mode though, so maybe that's meant? (In addition to the
spec being a bit wobbly, using EBC in new software isn't
recommended, but too late for that.)
SASLprep / stringprep still aren't implemented. For ASCII passwords
(including the important empty password), this is good enough.
...for handlers of revision 6.
Since this adds U to the hash input, also trim the size of U and O to
48 bytes. The spec requires them to be 48 bytes, but all the newer PDFs
on https://cipa.jp/e/std/std-sec.html have 127 bytes -- 48 real bytes
and 79 nul padding bytes. These files were created by:
Creator: Word 用 Acrobat PDFMaker 17
Producer: Adobe PDF Library 15.0
and
Creator: Word 用 Acrobat PDFMaker 17
Producer: Adobe PDF Library 17.11.238
LibGfx's ScaledFont doesn't do this, but in ScaledFont m_x_scale and
m_y_scale are immutable once the class is created, so it can get away
with not doing it.
In Type1Font, `width` changes in different calls to
Type1Font::draw_glyph(), so we need to make it part of the cache key.
Fixes rendering of the word "Version" on the first page of
pdf_reference_1-7.pdf.
This is just something I spotted looking around the code, previously
the PassPipelineExecutable was passed by value to
generate_cfg_for_block, which generated the CFG then just dropped it on
the floor. Making this a reference results in the CFG actually getting
generated.
We can delete for_each_bound_name() because there is more generic
version of this function called for_each_bound_identifier() that gives
you identifier using which you can get both name and check if it is
local/global.
Bytes will implicitly cast to StringView, but not to ReadonlyBytes. That
means that if you call
`Audio::Loader::create_plugin(mapped_file->bytes())`
it will silently use the `create_plugin(StringView path)` overload.
Reading audio data does not require that data to be writable, so let's
use ReadonlyBytes for it and avoid the footgun.
Similar to the scoped continue and break, the only two differences
between these functions is the scope that is scanned for a matching
label, and the specific handling of a continue/break boundary.
This is a step towards AESV3 support for PDF files.
The straight-forward way of writing this with our APIs is pretty
allocation-heavy, but this code won't run all that often for the
regular "open PDF, check password" flow.