Safe Haskell | None |
---|---|
Language | Haskell2010 |
Readingwriting bundles of embedded files and other data fromto executables.
A bundle has three parts: the static header, which identifies a string of bytes as a bundle using a particular version of the format and gives the size of the dynamic header; the dynamic header which describes all files and directories contained in the bundle; and the data part, where the data for all files is located. All words are stored in little endian format.
The static header comprises the last bundleHeaderStaticSize
bytes of the
file, with the dynamic header coming immediately before, and the data
section coming immediately before the dynamic header.
The dynamic header is stored as a tuple of the number of files in the bundle (Word32), and the . Each file is stored as a triple of the file's UTF-8 encoded path, its offset from the start of the data section, and its size. The path is prepended with a Word32 giving its length in bytes; the offset is given as a Word32 and the size is given as a Word32.
The layout of the bundle format is given in the following table:
[file data] [files] * hdrNumFiles pathLen : Word32 path : pathLen * Word8 offset : Word64 size : Word32 [static header] hdrDataOffset : Word64 hdrNumFiles : Word32 hdrDynSize : Word32 hdrVersion : Word8 "BNDLLDNB" : Word64
The included embedtool
program offers a command line interface
for manipulating and inspecting bundles.
- data Bundle
- hasBundle :: FilePath -> IO Bool
- openBundle :: FilePath -> IO (Either String Bundle)
- withBundle :: FilePath -> (Bundle -> IO a) -> IO (Either String a)
- closeBundle :: Bundle -> IO ()
- readBundleFile :: Bundle -> FilePath -> IO (Either String ByteString)
- readBundle :: Serialize a => Bundle -> FilePath -> IO (Either String a)
- listBundleFiles :: Bundle -> [FilePath]
- data File
- appendBundle :: FilePath -> [File] -> IO ()
- eraseBundle :: FilePath -> IO ()
- replaceBundle :: FilePath -> [File] -> IO ()
Documentation
A handle to a file bundle. Bundle handles are obtained using openBundle
or withBundle
and start out as open. That is, files may be read from
them. An open bundle contains an open file handle to the bundle's backing
file, ensuring that the file data will not disappear from under it.
When a bundle becomes unreachable, its corresponding file handle is
closed by the bundle's associated finalizer.
However, as finalizers are not guaranteed to run promptly - or even
at all - bundles may also be closed before becoming unreachable using
closeBundle
. If you expect to perform other operations on a bundle's
backing file, you should always close the bundle manually first.
Reading bundles
openBundle :: FilePath -> IO (Either String Bundle) Source
Open a file bundle. The bundle will keep an open handle to its backing
file. The handle will be closed when the bundle is garbage collected.
Use closeBundle
to close the handle before the
withBundle :: FilePath -> (Bundle -> IO a) -> IO (Either String a) Source
Perform a computation over a bundle, returning an error if either the computation failed or the bundle could not be loaded. The bundle is always closed before this function returns, regardless of whether an error occurred.
closeBundle :: Bundle -> IO () Source
Close a bundle before it becomes unreachable. After a bundle is closed, any read operations performed on it will fail as though the requested file could not be found. Subsequent close operations on it will have no effect.
readBundleFile :: Bundle -> FilePath -> IO (Either String ByteString) Source
Read a file from a previously opened bundle. Will fail of the given path
is not found within the bundle, or if the bundle is no longer alive, i.e.
it has been closed using closeBundle
.
readBundle :: Serialize a => Bundle -> FilePath -> IO (Either String a) Source
Like readBundleFile
, but attempts to decode the file's contents into an
appropriate Haskell value.
listBundleFiles :: Bundle -> [FilePath] Source
List all files in the given bundle. Will succeed even on closed bundles.
Creating bundles
A file to be included in a bundle. May be either the path to a file on disk or an actual (path, data) pair.
If a file path refers to a directory, all non-dotfile files and
subdirectories of that directory will be included in the bundle.
File paths also have a strip number: the number of leading directories
to strip from file names when adding them to a bundle.
For instance, adding File 1 "foo/bar"
to a bundle will add the file
foo/bar
, under the name bar
within the bundle.
If a file name would "disappear" entirely due to stripping, for instance
when stripping two directories from foo/bar
, bar
will "disappear"
entirely and so will be silently ignored.
appendBundle :: FilePath -> [File] -> IO () Source
Write a bundle to a file. If the given file already has a bundle, the new
bundle will be written *after* the old one. The old bundle will thus still
be present in the file, but only the new one will be recognized by
openBundle
and friends.
eraseBundle :: FilePath -> IO () Source
Remove a bundle from an existing file. Does nothing if the given file does not have a bundle. The given file is *not* removed, even if it only contains the bundle.
replaceBundle :: FilePath -> [File] -> IO () Source
Replace the bundle currently attached to the given file. Equivalent to
appendBundle
if the given file does not already have a bundle attached.