Package 'olereader'

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

Help Index


Extract OLE streams to files

Description

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.

Usage

ole_extract(ole, dir, streams = NULL, overwrite = FALSE)

Arguments

ole

An ole_file object from ole_open(), or the path to a compound file, which is opened and parsed again on every call.

dir

Folder to write to. It is created if it does not exist.

streams

The streams to extract, or NULL (the default) for all of them. Either a character vector with one /-separated path per stream, such as c("data", "notes/readme"), or a list of paths like the one returned by ole_streams(). In a list, each path is a vector of names, such as list("data", c("notes", "readme")), and strings are not split at /, so list("notes/readme") looks for a stream named notes/readme outside any storage.

overwrite

Whether to replace files that already exist. If FALSE (the default), extraction stops at the first file that already exists, including one written by an earlier stream in the same call.

Details

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.

Value

The paths of the files written, invisibly, named by stream.

Examples

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)

Open an OLE compound file

Description

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.

Usage

ole_open(path)

Arguments

path

Path to the file.

Details

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.

Value

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.

See Also

ole_streams(), ole_read(), ole_size(), ole_extract()

Examples

ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader"))
ole

Read an OLE stream

Description

Read an OLE stream

Usage

ole_read(ole, stream)

Arguments

ole

An ole_file object from ole_open(), or the path to a compound file, which is opened and parsed again on every call.

stream

Path to the stream: a character vector of names, such as c("storage", "stream"), a single string separating them with /, or a list holding one such path, such as ole_streams(ole)[1]. A string in a list is not split at /, so a list also reaches streams whose names contain /. Names are matched ignoring the case of the letters A to Z. ole_extract() reads a character vector differently: each element is a separate stream.

Value

A raw vector, or NULL if the stream does not exist.

Examples

ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader"))
rawToChar(ole_read(ole, c("notes", "readme")))

Size of an OLE stream

Description

Size of an OLE stream

Usage

ole_size(ole, stream)

Arguments

ole

An ole_file object from ole_open(), or the path to a compound file, which is opened and parsed again on every call.

stream

Path to the stream: a character vector of names, such as c("storage", "stream"), a single string separating them with /, or a list holding one such path, such as ole_streams(ole)[1]. A string in a list is not split at /, so a list also reaches streams whose names contain /. Names are matched ignoring the case of the letters A to Z. ole_extract() reads a character vector differently: each element is a separate stream.

Value

The size in bytes, or 0 if the stream does not exist. Storages also have size 0.

Examples

ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader"))
ole_size(ole, "data")

List the streams in an OLE file

Description

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.

Usage

ole_streams(ole)

Arguments

ole

An ole_file object from ole_open(), or the path to a compound file, which is opened and parsed again on every call.

Value

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 /.

Examples

ole <- ole_open(system.file("extdata", "example.cfb", package = "olereader"))
ole_streams(ole)
names(ole_streams(ole))