anthropics / anthropics/skills

pdf skill: extract_form_field_info.py corrupts/crashes on comboboxes whose /Opt entries are bare strings

Abierto
#1,469 0 comentarios 0 reacciones 0 asignados Ver en GitHub
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.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.