Repository navigation
ROB: Tolerate extra operands before Tm/cm in layout mode - #4284
Conversation
A matrix operator consumes the 6 operands nearest to it; values left on the operand stack before those (malformed content streams) overflowed TextStateManager.new_transform() and raised TypeError in layout mode text extraction. Complete the matrix with only the last 6 operands in _complete_matrix and add_cm, mirroring the tolerance already in place for missing/non-numeric TD and Tz operands (py-pdf#4232, py-pdf#4233). Fixes py-pdf#4283 Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4284 +/- ##
==========================================
+ Coverage 98.41% 98.55% +0.14%
==========================================
Files 59 59
Lines 11995 11992 -3
Branches 2270 2268 -2
==========================================
+ Hits 11805 11819 +14
+ Misses 103 93 -10
+ Partials 87 80 -7 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
stefan6419846
left a comment
There was a problem hiding this comment.
Please add tests. Why are these changes part of #4286 as well?
Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
|
Thanks for the review! Tests added in 62df42e — two layout-mode cases covering extra operands before both On your question — why these changes are part of #4286 as well: the |
|
Thanks for merging #4284 (ROB: Tolerate extra operands before Tm/cm in layout mode)! 🎉 By the way, I'm currently open to new opportunities (Full Stack (PHP, NodeJs, Python) / Data Science / Applied AI / Devtools, based in India). If you or anyone around is hiring, I'd love to connect: |
Fixes #4283
Bug
Layout mode text extraction crashed with an internal
TypeErrorwhen a content stream contained aTm(orcm) operator with extra operands on the operand stack:Root cause
TextStateManager.add_tm/add_trmpass operands through_complete_matrix, which pads a 2-operandTd-style set but does not trim operand sets longer than 6, sonew_transform()receives more than its 6 matrix parameters.TextStateManager.add_cmsplats*argsstraight intonew_transform().Per the PDF operand-stack model, a matrix operator consumes the 6 operands nearest to it; the extras are malformed-stream noise and should not overflow the transform API. This is the same class of operand hardening as #4232 (
Tzwithout operand) and #4233 (TDwith a missing/non-numericty).Fix
_complete_matrixnow returns only the last 6 operands, andadd_cmsplats onlyargs[-6:], soTm/cmconsume the 6 operands nearest to the operator. Valid operand counts are unaffected.Verification (stdlib-only harness on the Pi, Python 3.13.5, main @ c7d391c)
Hand-built one-page PDF (correct xref) with the following content streams, layout mode, before → after:
BT /F1 12 Tf 72 720 1 0 0 1 100 600 Tm (TmText) Tj ET(8 operands): TypeError crash →'TmText'✓ (matrix taken from the nearest 6 operands:1 0 0 1 100 600)BT /F1 12 Tf 9 1 0 0 1 100 600 Tm (TmText) Tj ET(7 operands): crash →'TmText'✓BT /F1 12 Tf 5 5 1 0 0 1 50 50 cm 72 720 Td (CmText) Tj ET(cm with 7 operands): crash →'CmText'✓Tm:'TmText'before and after (unchanged) ✓Tdtranslation:'Second'before and after (unchanged) ✓Tests:
pytest tests/text_extraction/ -q→ 6 passed.pytest tests/test_text_extraction.py -q→ 108 passed, 1 xpassed, 2 pre-existing failures (test_multi_language,FileNotFoundError: sample-files/015-arabic/habibi-rotated.pdf— thesample-filessubmodule is absent in a shallow clone, unrelated to this change).