Skip to content

Open the document by what it is called when its bytes only say text - #611

Merged
andiwand merged 1 commit into
mainfrom
open-what-the-file-is-called
Aug 21, 2026
Merged

Open the document by what it is called when its bytes only say text#611
andiwand merged 1 commit into
mainfrom
open-what-the-file-is-called

Conversation

@andiwand

@andiwand andiwand commented Aug 21, 2026

Copy link
Copy Markdown
Member

odrcore builds its open candidates from the content alone - list_file_types is
magic::file_type, and the name is never consulted. A document whose signature
does not sit at the front of the file therefore never opens as itself. The case
that turned this up is a pdf saved straight out of a browser, with the http
response that delivered it still attached, so %PDF-1.4 starts at byte 178.

What the user got depended on the file. odr-public-shaped ones read as text
with a charset the core could name, and the reader was shown pages of pdf source
with a bar offering to open it elsewhere. The file in #552 has binary enough
content that no charset could be named, so the guard in host refused it and the
app reported an unsupported format - for a pdf the core parses perfectly well
once told what it is.

Neither knob in DecodePreference fixes this on its own. fileTypePriority only
stable-sorts the candidates detection already found, so it is inert when
detection found the wrong one or none. asFileType replaces detection outright
and has no fallback, which would hand a file misnamed by its extension to a
parser that cannot read it. So it is a second attempt rather than the first:
CoreLoader.openFile opens as detection reads the bytes, and only where that
reading is the residual answer does it open again as the type the name states.

Two things keep it narrow. The name has to be one the core files as a DOCUMENT

  • csv and plain text are both text by category, so whether comma separated
    values are a table or prose stays the core's question, which Take odrcore 6.4.0, and let it render csv #576 and 6.8.0 tuned
    deliberately. And the name is taken from IdentifiedFile.filename, not from its
    mimeType: FileIdentifier takes that from Odr.mimetype wherever it answered,
    so feeding it back would only repeat the reading this is here to back up.

CoreTest pins both halves against a fixture it builds at run time from
dummy.pdf, so no binary asset joins the repo: without a declared type the
served html carries the http preamble as text, with one it does not, and an odt
declared a pdf still opens as an odt.

Checked on API 31 (full suite, 84 tests) and API 36, plus a sweep of the corpus'
txt and csv files, which are what this could have disturbed and did not - the
5000 row csv still comes out a table. The private pdf #552 names renders as the
document it is.

Closes #552

🤖 Generated with Claude Code

@andiwand andiwand mentioned this pull request Aug 21, 2026
odrcore builds its open candidates from the content alone - `list_file_types` is
`magic::file_type`, and the name is never consulted. A document whose signature
does not sit at the front of the file therefore never opens as itself. The case
that turned this up is a pdf saved straight out of a browser, with the http
response that delivered it still attached, so `%PDF-1.4` starts at byte 178.

What the user got depended on the file. `odr-public`-shaped ones read as text
with a charset the core could name, and the reader was shown pages of pdf source
with a bar offering to open it elsewhere. The file in #552 has binary enough
content that no charset could be named, so the guard in `host` refused it and the
app reported an unsupported format - for a pdf the core parses perfectly well
once told what it is.

Neither knob in `DecodePreference` fixes this on its own. `fileTypePriority` only
stable-sorts the candidates detection already found, so it is inert when
detection found the wrong one or none. `asFileType` replaces detection outright
and has no fallback, which would hand a file misnamed by its extension to a
parser that cannot read it. So it is a second attempt rather than the first:
`CoreLoader.openFile` opens as detection reads the bytes, and only where that
reading is the residual answer does it open again as the type the name states.

Two things keep it narrow. The name has to be one the core files as a `DOCUMENT`
- csv and plain text are both `text` by category, so whether comma separated
values are a table or prose stays the core's question, which #576 and 6.8.0 tuned
deliberately. And the name is taken from `IdentifiedFile.filename`, not from its
`mimeType`: `FileIdentifier` takes that from `Odr.mimetype` wherever it answered,
so feeding it back would only repeat the reading this is here to back up.

`CoreTest` pins both halves against a fixture it builds at run time from
`dummy.pdf`, so no binary asset joins the repo: without a declared type the
served html carries the http preamble as text, with one it does not, and an odt
declared a pdf still opens as an odt.

Checked on API 31 (full suite, 84 tests) and API 36, plus a sweep of the corpus'
txt and csv files, which are what this could have disturbed and did not - the
5000 row csv still comes out a table. The private pdf #552 names renders as the
document it is.

Closes #552
@andiwand
andiwand force-pushed the open-what-the-file-is-called branch from 4ddcb84 to 8524ed3 Compare August 21, 2026 09:00
@andiwand
andiwand enabled auto-merge (squash) August 21, 2026 09:10
@andiwand
andiwand merged commit 59f1724 into main Aug 21, 2026
7 checks passed
@andiwand
andiwand deleted the open-what-the-file-is-called branch August 21, 2026 09:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CoreLoader opens files by content detection only, so it rejects files the core can open

1 participant