anthropics / anthropics/skills
pdf skill: extract_form_field_info.py corrupts/crashes on comboboxes whose /Opt entries are bare strings
- Lenguaje dominante
- Python
- Estrellas
- 176k
- Forks
- 20.8k
- Merge medio
- 7 h 21 min
- PR fusionados (30 d)
- 5
Descripción
## Summary
`skills/pdf/scripts/extract_form_field_info.py` assumes every choice-field option (`/Opt`) is a `[export_value, display_text]` pair. Per ISO 32000-1 §12.7.4.4, an `/Opt` array entry may instead be a **single text string** (used as both the export value and the display text). On such fields the script silently produces corrupted output, and crashes outright when any option is a single character.
## Buggy code (`skills/pdf/scripts/extract_form_field_info.py`, lines 35-41)
```python
elif ft == "/Ch":
field_dict["type"] = "choice"
states = field.get("/_States_", [])
field_dict["choice_options"] = [{
"value": state[0],
"text": state[1],
} for state in states]
```
`states` comes from pypdf's `/_States_`, which for `/Ch` fields is the raw `/Opt` array verbatim (`pypdf/_doc_common.py`: `retval[key]["/_States_"] = obj["/Opt"]`). When `/Opt` holds bare strings, `state[0]`/`state[1]` index into the string instead of a pair.
## Reproduction
Create a combobox whose `/Opt` is bare strings, then run the script (pypdf 6.13.1):
```python
from pypdf import PdfWriter
from pypdf.generic import (DictionaryObject, ArrayObject, NameObject,
TextStringObject, NumberObject)
w = PdfWriter(); page = w.add_blank_page(width=300, height=300)
f = DictionaryObject()
f[NameObject("/FT")] = NameObject("/Ch")
f[NameObject("/T")] = TextStringObject("colors")
f[NameObject("/Ff")] = NumberObject(1 << 17) # Combo
f[NameObject("/Opt")] = ArrayObject([TextStringObject(s) for s in ("Red","Green","Blue")])
f[NameObject("/Subtype")] = NameObject("/Widget")
f[NameObject("/Rect")] = ArrayObject([NumberObject(x) for x in (50,50,250,80)])
f[NameObject("/P")] = page.indirect_reference
ref = w._add_object(f); page[NameObject("/Annots")] = ArrayObject([ref])
acro = DictionaryObject(); acro[NameObject("/Fields")] = ArrayObject([ref])
w._root_object[NameObject("/AcroForm")] = w._add_object(acro)
w.write(open("bare_opt.pdf","wb"))
```
```
$ python extract_form_field_info.py bare_opt.pdf out.json
```
**Result — silent corruption:**
```json
"choice_options": [
{"value": "R", "text": "e"},
{"value": "G", "text": "r"},
{"value": "B", "text": "l"}
]
```
`"Red"` becomes `value="R", text="e"` (chars 0 and 1 of the string).
**Result with a single-character option (e.g. `/Opt = ["A","B"]`) — hard crash:**
```
File "extract_form_field_info.py", line 40, in make_field_dict
"text": state[1],
IndexError: string index out of range
```
## Impact
Any real-world PDF using string-form `/Opt` (common for simple dropdowns) either gets its choice values/labels garbled one character at a time — with no error — or crashes the whole extraction on a single-letter option. Because the output feeds downstream form-filling, the corruption is silent and misleading.
## Suggested fix
Normalize each entry, treating a bare string as its own value and text:
```python
field_dict["choice_options"] = [
{"value": s, "text": s} if isinstance(s, str) else {"value": s[0], "text": s[1]}
for s in states
]
```
Environment: pypdf 6.13.1, Python 3.13; upstream file fetched from `anthropics/skills@main`.
Guía de contribución
No hay ninguna guía de contribución indexada para este repositorio
Evaluación
Este issue todavía no se ha evaluado.