| Title: | Read OLE Compound Files |
|---|---|
| Description: | Reads Microsoft compound files, also known as OLE2 or structured storage files, in pure R. Lists the streams in a file, returns their contents as raw vectors and extracts them to disk. Written from the MS-CFB specification <https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/>. |
| Authors: | Ethan Bass [aut, cre] (ORCID: <https://orcid.org/0000-0002-6175-6739>) |
| Maintainer: | Ethan Bass <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-10-28 23:25:37 UTC |
| Source: | https://github.com/ethanbass/olereader |
Writes each stream to a file under dir, with one folder for each storage
that contains it, so c("storage", "stream") becomes
dir/storage/stream.
ole_extract(ole, dir, streams = NULL, overwrite = FALSE)ole_extract(ole, dir, streams = NULL, overwrite = FALSE)
ole |
An |
dir |
Folder to write to. It is created if it does not exist. |
streams |
The streams to extract, or |
overwrite |
Whether to replace files that already exist. If |
Names are changed where they would not work as file names on every
platform. Control characters and <>:"/\|?* are replaced with _,
trailing dots and spaces are removed, names left empty (including . and
..) become _, and 'Windows' device names such as CON or NUL.txt
get a _ prefix. The names in a file cannot place a file outside dir.
ole_extract() stops before writing anything if a requested stream does
not exist, if two streams would be written to the same file (ignoring
case), or if the streams add up to more bytes than the file holds, which
means it is truncated or has streams sharing sectors. Any other error stops
extraction partway, and the files already written are left in place.
The paths of the files written, invisibly, named by stream.
ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader")) dir <- file.path(tempdir(), "example") ole_extract(ole, dir) list.files(dir, recursive = TRUE) ole_extract(ole, dir, streams = "notes/readme", overwrite = TRUE) unlink(dir, recursive = TRUE)ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader")) dir <- file.path(tempdir(), "example") ole_extract(ole, dir) list.files(dir, recursive = TRUE) ole_extract(ole, dir, streams = "notes/readme", overwrite = TRUE) unlink(dir, recursive = TRUE)
Reads the header, the sector allocation tables and the directory of a
Microsoft compound file (MS-CFB), also called OLE2 or structured storage.
Stream contents are not read until you ask for them with ole_read().
Only reading is supported.
ole_open(path)ole_open(path)
path |
Path to the file. |
The file is not kept open: each call to ole_read() reopens it. There is
nothing to close.
The other functions also take a path in place of an ole_file object and
call ole_open() on it themselves. A path is simpler for a single read, but
the file is parsed again on every call, so open it once to read several
streams.
Damaged files give an error rather than wrong data: a header or allocation table that does not fit the size of the file, a chain of sectors that loops, a directory entry that points past the end of the directory, or storages nested more than 64 levels deep.
An ole_file object: a list holding
path, version (3 or 4) and file_size, in bytes;
sector_size and mini_sector_size, in bytes, and n_sectors, the
number of sectors after the header;
fat and minifat, which give for each sector or mini sector the
0-based number of the next sector in its chain, or a negative number
marking the end of a chain or a free or reserved sector;
mini_chain, the 0-based sectors holding the mini stream, or the error
met while following them;
dir, a data frame with one row per directory entry. Its columns are
name; type (1 for a storage, 2 for a stream, 5 for the root);
left, right and child, the 0-based IDs of the entry's siblings and
first child, or -1 for none; start, its first sector; size, in
bytes; parent, the row of the storage holding it, or 0 for the root
and for entries not reached from it; and key, its name with the letters
A to Z in lower case.
ole_streams(), ole_read(), ole_size(), ole_extract()
ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader")) oleole <- ole_open(system.file("extdata", "example.cfb", package = "olereader")) ole
Read an OLE stream
ole_read(ole, stream)ole_read(ole, stream)
ole |
An |
stream |
Path to the stream: a character vector of names, such as
|
A raw vector, or NULL if the stream does not exist.
ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader")) rawToChar(ole_read(ole, c("notes", "readme")))ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader")) rawToChar(ole_read(ole, c("notes", "readme")))
Size of an OLE stream
ole_size(ole, stream)ole_size(ole, stream)
ole |
An |
stream |
Path to the stream: a character vector of names, such as
|
The size in bytes, or 0 if the stream does not exist. Storages also have size 0.
ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader")) ole_size(ole, "data")ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader")) ole_size(ole, "data")
Streams are listed depth-first, with the entries of each storage sorted by
name, the same order as listdir() in the Python package 'olefile'.
Storages themselves are not listed.
ole_streams(ole)ole_streams(ole)
ole |
An |
A named list of character vectors, each the path to a stream: the
names of the storages that contain it, then its own name. The names of the
list are the same paths joined with /.
ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader")) ole_streams(ole) names(ole_streams(ole))ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader")) ole_streams(ole) names(ole_streams(ole))