Python API¶
For most use cases, the Configuration Files should suffice. If you need more fine-grained control over your scenarios you can use the Python API. For instance, the API lets you define the exact fragmentation points of your files, exact sizes of filler fragments, and so forth.
Here is a simple script illustrating the basic usage of the API:
#!/usr/bin/env python3
import pathlib
import sys
from woodblock.file import File, draw_files
from woodblock.fragments import RandomDataFragment, ZeroesFragment
from woodblock.image import Image
from woodblock.scenario import Scenario
HERE = pathlib.Path(__file__).absolute().parent
def main():
woodblock.file.corpus(HERE / '..' / 'data' / 'corpus')
files = draw_files(number_of_files=2)
f_a = files[0].fragment_randomly(num_fragments=3)
f_b = files[1].fragment_evenly(num_fragments=2)
s = Scenario('First API Scenario')
s.add(f_a[1])
s.add(ZeroesFragment(1024))
s.add(f_b[0])
s.add(f_a[2])
s.add(RandomDataFragment(512))
s.add(f_a[0])
s.add(f_b[1])
image = Image(block_size=512)
image.add(s)
image.write(HERE / 'api-demo.dd')
if __name__ == '__main__':
sys.exit(main())
This script randomly chooses two files from the file corpus. The first one is split into three fragments at random fragmentation points, the second one is split into two fragments of equal size. After that the scenario with the name “First API Scenario” is created and the file fragments as well as two filler fragments are added to the scenario. Finally, the scenario is added to an image object which is then written to disk.
Let’s go through this example step by step. The first lines are just some imports.
from woodblock.file import File, draw_files
from woodblock.fragments import RandomDataFragment, ZeroesFragment
from woodblock.image import Image
from woodblock.scenario import Scenario
After we define the file corpus and randomly draw two files:
woodblock.file.corpus(HERE / '..' / 'data' / 'corpus')
files = draw_files(number_of_files=2)
These files are then split into fragments. The first file is split into three fragments. The fragmentation points are chosen randomly. The second file is split into two fragments. The fragmentation point is chosen so that both fragments are of equal size:
f_a = files[0].fragment_randomly(num_fragments=3)
f_b = files[1].fragment_evenly(num_fragments=2)
After that, a Scenario object is created. Its argument is the name
of the scenario:
s = Scenario('First API Scenario')
A Scenario object has a method to add fragments to it.
A call to add appends a fragment to any previously added fragments,
so that the order of the add calls defines the order of the
fragments in the scenario:
s.add(f_a[1])
s.add(ZeroesFragment(1024))
s.add(f_b[0])
s.add(f_a[2])
s.add(RandomDataFragment(512))
s.add(f_a[0])
s.add(f_b[1])
We did not only added the fragments of our files but also two filler
fragments: a ZeroesFragment of 1024 bytes of size and a
RandomDataFragment of 512 bytes of size. As you can see, you
can specify the exact size of the filler fragments using the API.
After that, our scenario is complete and we create an Image
object with a block size of 512 bytes. Image objects represent
test image files to be written to disk. Just like we could add fragments
to a scenario, we can add scenarios to an Image. If we added all
of the scenarios, we can finally write the image using the write
method.
Those are already the basic blocks you need to create your own test images using the API: you select files from the test file corpus, fragments them in some way, add the fragments to a scenario, add the scenario to an image, and finally write the image to disk.
The following sections describe the available API functions and objects in a more detailed way.
Files and Fragments¶
Files are always selected from a file corpus. Therefore, you have to specify
the path to your file corpus before you can select any files. This is done
using the woodblock.files.corpus function. This function takes the path
to your file corpus as its only argument. An example call would look like this:
# You can provide the path using a string...
woodblock.file.corpus('path/to/your/corpus/')
# ... or via a pathlib.Path object
path = pathlib.Path('path/to/your/corpus/')
woodblock.file.corpus(path)
Once you have defined your corpus, you can start using its files. If you do
not care which exact files to use from your corpus, you can use the
draw_files function, which randomly chooses the given number of files
from your corpus. The function lets you not only specify the number of files
but also the minimal size of each files. Moreover, you can specify if duplicate
files are allowed or not. Duplicate files are basically two different objects
pointing to the same original file. Finally, you can indicate that you want
the files to be drawn only from a special subdirectory of your corpus. The
following examples show how to use this function:
# This will give you one randomly chosen file:
single_file = woodblock.file.draw_files()
# Here is an example with four randomly chosen files:
files = woodblock.file.draw_files(number_of_files=4)
# Now we want three files, but only from the jpeg/ subdirectory:
files = woodblock.file.draw_files(path='jpeg', number_of_files=3)
# The same but only files with a minimal size of 2 MB:
files = woodblock.file.draw_files(path='jpeg', number_of_files=3, min_size=2*1024**2)
# Finally, choose ten files without duplicates:
files = woodblock.file.draw_files(number_of_files=10, unique=True)
Note that draw_files always returns a list of File objects,
that is, even single_file is a list (with only one item).
File objects represent files from your corpus. If you don’t want to use
draw_files to get your File objects, you can create them manually.
This allows you to choose specific files from your corpus. To create a File
object, simply pass the path of the file you want (relative to the corpus)
to the constructor:
some_file = woodblock.file.File('some/path/relative/to/the/corpus.jpg')
File objects provide some methods returning metadata about the file they
represent. For example, there are the methods size, path,
id, and hash which return just what you would expect from the names.
More interesting are the methods used to split a file into fragments. Here, we
have as_fragment, fragment, fragment_evenly, and
fragment_randomly. The first one simply converts the file into a single
fragment. This is can be used, when you want to add a contiguous file to your
scenario (Scenario objects can only be used with fragments; see below).
fragment can be used to fragment a file at specific fragmentation points.
fragment_evenly and fragment_randomly are convenience methods, which
split a file into a given number of evenly sized fragments or into a given number of
randomly sized fragments. The following snippet provides some usage examples for the
methods to fragment a file:
# some_file as a single fragment:
contiguous = some_file.as_fragment()
# some_file spit at specific fragmentation points. Fragmentation points are
# defined with respect to the block_size, i.e. the following example splits
# the file at bytes 1024, 1536, and 3584:
fragments = some_file.fragment(fragmentation_points=(2, 3, 7), block_size=512)
# Split some_file into three evenly sized fragments:
evenly_fragmented = some_file.fragment_evenly(num_fragments=3, block_size=512)
# or shorter:
evenly_fragmented = some_file.fragment_evenly(3)
# Split some_file into three fragments at random fragmentation points:
randomly_fragmented: some_file.fragment_randomly(num_fragments=3, block_size=512)
# or shorter:
randomly_fragmented: some_file.fragment_randomly(3)
These methods give you a high level of control to create very specific
fragmentation scenarios. However, if you just want some fragmented files,
Woodblock has some convenience functions for you. draw_fragmented_files
basically combines draw_files and File.fragment_randomly
and gives you a list of fragment lists.
from woodblock.file import draw_fragmented_files
# Three fragmented files:
fragments = draw_fragmented_files(number_of_files=3)
# Three fragmented files from the png/large subdirectory:
fragments = draw_fragmented_files(path='png/large', number_of_files=3)
# Three fragmented files each split into at least three and at most six fragments:
fragments = draw_fragmented_files(number_of_files=3, min_fragments=3, max_fragments=6)
Since scenarios with intertwined files (or braided files as they are sometimes
called) are quite common, Woodblock provides a helper function for this, too.
intertwine_randomly chooses a given number of files from your corpus, splits
them into fragments, and orders the fragments for you. Again, there are
various arguments that you can pass to the function:
from woodblock.file import intertwine_randomly
# Intertwine three files:
intertwined = intertwine_randomly(number_of_files=3)
# Intertwine three files from the png/large subdirectory:
intertwined = intertwine_randomly(path='png/large', number_of_files=3)
# Intertwine two files and make sure that each file has
# at least three and at most six fragments:
intertwined = intertwine_randomly(number_of_files=3, min_fragments=3, max_fragments=6)
Note that intertwine_randomly makes sure that fragments of the
same file are never next to each other.
All of the different fragmentation functions and methods described above
create FileFragment objects. A FileFragment represents a
fragment of a file from your corpus. Additionally, Woodblock provides special
fragment types for synthetic data. For instance, you can create a region of
zero bytes using the ZeroesFragment. This is useful, if you want to
simulate unused or wiped disk areas. Here’s how to create a fragment filled
with 0x00 of 4096 bytes of size:
zeroes = woodblock.fragments.ZeroesFragment(size=4096)
Creating a fragment of 4096 bytes of size filled with random data is equally simple:
random_data = woodblock.fragments.RandomDataFragment(size=4096)
ll of the different fragment types have various methods to provide
information about themselves: you can query the size and the
SHA-256 hash as well as a dictionary containing all of the
metadata of the fragment.
Now that we know how to create fragments, let’s find out how to create a carving test scenario out of them.
Scenarios¶
A Scenario object represents a test scenario for a file carver.
That is, it consists of a certain number of file fragments arranged in a
certain order. Moreover, a scenario can contain filler fragments such as
the ones described above (e.g. ZeroesFragment or
RandomDataFragment).
To create such a scenario using the Woodblock API, simply create an instance
of the Scenario class:
scenario = woodblock.scenario.Scenario('A simple scenario')
The parameter provided to Scenario is the name of the scenario. This
name appears in the ground truth files generated and should be as descriptive as
possible. Have a look at the descriptions used in the
DFRWS 2007 File Image Layout page for inspiration.
After you created a Scenario instance, you can add fragments to it:
import woodblock
from woodblock.file import File
from woodblock.fragments import RandomDataFragment, ZeroesFragment
scenario = woodblock.scenario.Scenario('contiguous file with filler before and after')
scenario.add(ZeroesFragment(size=4096))
scenario.add(File('some/path/relative/to/the/corpus.jpg').as_fragment())
scenario.add(RandomDataFragment(size=4096))
The example above creates the scenario “contiguous file with filler before and after” consisting of 4096 zero bytes, then the contiguously stored file “some/path/relative/to/the/corpus.jpg”, and finally 4096 bytes of random data. The order in which fragments are added to the scenario is the order in which these fragments will be written to disk later on.
The add method does not only take single fragments, but also lists of
fragments. This is convenient if you are, well, working with lists of
fragments:
import woodblock
from woodblock.file import File
scenario = woodblock.scenario.Scenario('single file with reversed fragments')
fragments = File('some/file.txt').fragment_randomly(5)
fragments.reverse()
scenario.add(fragments)
This is already everything you need to create a scenario. The next step is to add your scenario to an image file which is written to disk.
Images¶
Image objects represent actual test files that you can provide as input
to the carvers you want to evaluate. An image contains one or more scenarios and
can be written to disk as an actual file. Moreover, when being written an
additional log file is written containing the ground truth about this image.
That is, it specifies which files are contained in the image and at which
offsets their fragments are.
Creating an Image instance is as easy as:
import woodblock
# By default an image has a block size of 512 bytes:
image = woodblock.image.Image()
# But you can change the block size:
image4k = woodblock.image.Image(block_size=4096)
As you can see from the examples above, an image has a fixed block size. This means that any fragment in this image is padded to this block size. Consider for instance the image and the fragments shown below. The image has a fixed block size but the size of the fragments B and A.2 are no multiples of this block size.
The padding introduced by the Image instance will align the fragments
to the block size specified in the constructor. That is, padding data will be
appended to B and A.2. This is indicated by the dark gray areas labeled with
“p”.
By default, random data is used where padding is required. However, you can
provide your own data generator when creating your Image instance.
For example you can use 0x00 as padding like this:
zeroes_padding = woodblock.datagen.Zeroes()
image = woodblock.image.Image(padding_generator=zeroes_padding)
The object that you provide as padding_generator has to fulfill the
data generator interface described in section “Data Generators”.
After creating an Image instance, you can add scenarios to it.
This works in the same way as you added fragments to a scenario:
s1 = woodblock.scenario.Scenario("first scenario")
s2 = woodblock.scenario.Scenario("second scenario")
# add some fragments to the scenarios
image = woodblock.image.Image()
image.add(s1)
image.add(s2)
The order of the scenarios in the resulting image corresponds to the order in which you added them. Just as before with fragments and scenarios.
The last step to do is to write the image to disk:
image.write(pathlib.Path('test-image.dd'))
This will not only write all of the scenarios to the image file
test-image.dd, but it will also write a JSON file containing the ground
truth of the image. This file will be placed next to the image and will have the
same same with .json appended. In the example above, you would find your
ground truth in the file test-image.dd.json.
Data Generators¶
Data generators are objects implementing a certain interface. They are used in
Woodblock to generate the block padding that is used in an image or within
some FillerFragments for example. The interface is quite simple, so it’s
easy to write your own data generators. Here is the Zeroes data generator
class that is already included in Woodblock:
# You can find this in the module woodblock.datagen
class Zeroes:
"""Generates zero bytes."""
def __call__(self, size):
return b'\x00' * size
def __str__(self):
return 'zeroes'
As you can see, a data generator has to be callable. For classes this means
that you have to implement the __call__ magic method. While this would
be sufficient to make your data generator work, we highly recommend to implement
the __str__ magic method, too. When your data generator is used within
one of the fragment classes for example, its string representation will be written
to the ground truth file. So, returning something meaningful from __str__
helps you and others reading and understanding what is within your image.
When data is needed from your data generator, it will be called with a
size argument indicating how many bytes to return. Of course, your data
generator should return the correct number here. Woodblock expects the data
generators to always return as many bytes as requested and doesn’t do any checking
on the returned bytes. If your data generator fails to generate the expected
number of bytes for some reason, you should raise an exception and not return
any bytes.
You might have noticed, that the interface would also allow you to use a “normal” function as data generator. While technically this would work, we argue against doing so because your data generator function would not have a descriptive string representation. While there are ways to implement a custom string representation for your functions, using a class is just simpler.
Here is one more simple implementation of a data generator which generates a repeated sequence of bytes:
class Pattern:
"""Generate a repeated sequence of bytes."""
def __init__(self, pattern=b'AB'):
self._pattern = pattern
# a data generator has to be callable => implement the __call__ method
def __call__(self, size):
it = itertools.cycle(self._pattern)
return b''.join(bytes([next(it)]) for _ in range(size))
# a data generator should have a descriptive __str__ implementation
def __str__(self):
return 'pattern'
# this is how you would use the Pattern data generator to pad an image
image = woodblock.image.Image(padding_generator=Pattern(b'XO'))
API Reference¶
The following sections provide a brief documentation of the API.
woodblock.file¶
-
woodblock.file.corpus(path)¶ Specifies the path to the test file corpus to use.
- Parameters
path – The path to the corpus
pathcan either be a string or apathlib.Pathobject. In any way, it has to be an existing directory. All paths used forFileobjects are relative to the file corpus path.
-
woodblock.file.get_corpus()¶ Return the specified file corpus path.
- Returns
The corpus path
- Return type
pathlib.Path
-
woodblock.file.draw_files(path=None, number_of_files=1, unique=False, min_size=0)¶ Chooses random files from the file corpus.
- Parameters
path – Subdirectory of the corpus
number_of_files (int) – Number of files to draw
unique (bool) – Forbid a file to be drawn multiple times
min_size (int) – Minimal file size
- Returns
a list of
Fileobjects- Return type
list
If
pathisNone, the complete corpus will be considered. If it set to a path relative to the corpus, then only files in this directory (and its subdirectories) are considered.If
uniqueis set toTrue, then the resulting list will not contain file objects pointing to the same path in the corpus.min_sizecan be set to define a minimal file size of the files to be chosen.
-
woodblock.files.draw_fragmented_files(path=None, number_of_files=1, block_size=512, min_fragments=1, max_fragments=4)¶ Choose
number_of_filesrandom files frompathand fragment them randomly.- Parameters
path – Subdirectory of the corpus
number_of_files (int) – Number of files to draw
block_size (int) – Block size to be used when splitting files
min_fragments (int) – Min. number of fragments per file
max_fragments (int) – Max. number of fragments per file
- Returns
a list of fragment lists
- Return type
list
This function chooses
number_of_filesfiles from the givenpath(relative to the corpus) and fragments them at random fragmentation points. The number of fragments per file will be betweenmin_fragmentsandmax_fragments(both numbers included, i.e.min_fragments≤ number of fragments ≤max_fragments).The result is a list of fragment lists, e.g.
[ [f1.1, f1.2, f1.3], [f2.1, ], [f3.1, f3.2] ].If
pathisNone, the complete corpus will be considered. If it set to a path relative to the corpus, then only files in this directory (and its subdirectories) are considered.Note that there is no guarantee that a file is not chosen more than once.
-
woodblock.files.intertwine_randomly(path=None, number_of_files=2, block_size=512, min_fragments=1, max_fragments=4)¶ Choose
number_of_filesrandom files frompathand intertwine them randomly.- Parameters
path – Subdirectory of the corpus
number_of_files (int) – Number of files to intertwine
block_size (int) – Block size to used when splitting files
min_fragments (int) – Min. number of fragments per file
max_fragments (int) – Max. number of fragments per file
- Returns
a list of intertwined fragments
- Return type
list
This function chooses
number_of_filesfiles from the givenpath(relative to the corpus), fragments them at random fragmentation points, and intertwines them randomly. The number of fragments per file will be betweenmin_fragmentsandmax_fragments(both numbers included, i.e.min_fragments≤ number of fragments ≤ :code`max_fragments`).The result is a list of fragments, e.g.
[f3.1, f1.1, f3.2, f2.1, f1.2, f2.2, f1.3].The function ensures that there will in fact be unique
number_of_filesfiles. Moreover, the function guarantees that two fragments of the same file will not be at consecutive list positions. The fragments of each file will be stored in order.
-
class
woodblock.file.File(path)¶ This class represents an actual file of the test file corpus.
- Parameters
path (pathlib.Path) – a path relative to the specified corpus
-
property
woodblock.file.File.hash¶ Return the SHA-256 hash of the file contents as hexadecimal string.
- Return type
str
-
property
woodblock.file.File.id¶ Returns the ID of the file.
- Return type
str
The ID is a UUID generated when the
Fileobject is instantiated. EachFileobject has a unique ID—even if it references the same file of the corpus. This is useful, if you want to add the same file twice to the same scenario.
-
property
woodblock.file.File.path¶ Returns the path of the file relative to the corpus path.
- Return type
pathlib.Path
-
property
woodblock.file.File.size¶ Returns the size of the file.
- Return type
int
-
woodblock.file.File.as_fragment()¶ Convert the
Fileto a singleFileFragment. This is useful, if you want to add a contiguous, non-fragmented file to a scenario.- Return type
-
woodblock.file.File.max_fragments(block_size)¶ Returns the maximal number of fragments which can be created for a given
block_size.- Return type
int
-
woodblock.file.File.fragment(fragmentation_points, block_size=512)¶ Fragments the file at the given
fragmentation_pointswith respect to the givenblock_size.- Parameters
fragmentation_points (typing.Sequence) – a sequence of fragmentation points relative to the block size
block_size (int) – block size to use when splitting the file
- Returns
a list of
woodblock.fragments.FileFragmentobjects- Return type
list
This method fragments the current file at the specified
fragmentation_points. The fragmentation points are multiplied with the givenblock_sizein order to compute the actual fragmentation offsets.fragmentation_pointshas to be a sequence of integers,block_sizehas to be an integer and defaults to 512 if it is not specified.
-
woodblock.file.File.fragment_evenly(num_fragments, block_size=512)¶ This method fragments the current file into
num_fragmentsfragments.- Parameters
num_fragments (int) – number of fragments to create
block_size (int) – block size to use when splitting the file
- Returns
a list of
wwodblock.fragments.FileFragmentobjects- Return type
list
The fragmentation points are chosen so that each fragment will be of the same size (if possible). If the file cannot be fragmented evenly, then all but the last fragment will have the same size and the last one will be smaller than the other ones.
The block size to be used when splitting the file can be specified using the
block_sizeargument, which defaults to 512.
-
woodblock.file.File.fragment_randomly(num_fragments, block_size=512)¶ This method fragments the current file into
num_fragmentsfragments. The- Parameters
num_fragments (int) – number of fragments to create
block_size (int) – block size to use when splitting the file
- Returns
a list of
woodblock.fragments.FileFragmentobjects- Return type
list
The fragmentation points are chosen randomly. If
num_fragmentsisNone, then the number of fragments is chosen randomly between 1 and the maximum number of fragments for the givenblock_size.
woodblock.fragments¶
-
class
woodblock.fragments.FileFragment(file, fragment_number, start_offset, end_offset, chunk_size=8192)¶ This class represents a fragments of an actual file from the file corpus.
- Parameters
file (woodblock.file.File) – the file the fragment is part of
fragment_number (int) – the fragment number of this fragment
start_offset (int) – start offset of the fragment within the original file
end_offset (int) – end offset of the fragment within the original file
fileis theFileobject representing the original file andfragment_numberis the number of the fragment (i.e. is it the first fragment, is the second one and so on).start_offsetandend_offsetdefine the offsets where the fragment starts and ends (relative to the original file).
-
property
woodblock.fragments.FileFragment.hash¶ Return the SHA-256 digest as hexadecimal string.
- Return type
str
-
property
woodblock.fragments.FileFragment.metadata¶ Return the fragment metadata.
- Return type
dict
The fragment metadata is a
dictcontaining information about the file the fragments originates from (e.g. the hash, the size, and the path) as well as information about the current fragment (e.g. the hash, the size, and the fragment number with respect to the original file).
-
property
woodblock.fragments.FileFragment.size¶ Return the size of the fragment.
- Return type
int
-
class
woodblock.fragments.FillerFragment(size, data_generator=None, chunk_size=8192)¶ A filler fragment is a fragment containing synthetic data. It can be used to simulate wiped areas or areas with random data.
- Parameters
size (int) – size of the fragment
data_generator – data generator producing the fragment data
data_generatorhas to be an object compatible with the data generator interface.
-
property
woodblock.fragments.FillerFragment.hash¶ Return the SHA-256 digest as hexadecimal string.
- Return type
str
-
property
woodblock.fragments.FillerFragment.metadata¶ Return the fragment metadata.
- Return type
dict
The fragment metadata is a
dictcontaining information about the file the fragments originates from (e.g. the hash, the size, and the type) as well as information about the current fragment (e.g. the hash, the size, and the fragment number with respect to the original file).Note that
FillerFragmentsdo not point to any “real” files. Therefore, the values of the original file and the fragment will be mostly identical. The file metadata is included only for consistency with theFileFragment.
-
property
woodblock.fragments.FillerFragment.size¶ Return the size of the fragment.
- Return type
int
-
class
woodblock.fragments.RandomDataFragment(size, chunk_size=8192)¶ A fragment filled with random bytes.
- Parameters
size (int) – the size of the fragment
-
property
woodblock.fragments.RandomDataFragment.hash¶ Return the SHA-256 digest as hexadecimal string.
- Return type
str
-
property
woodblock.fragments.FileFragment.metadata Return the fragment metadata.
- Return type
dict
The fragment metadata is a
dictcontaining information about the file the fragments originates from (e.g. the hash, the size, and the type) as well as information about the current fragment (e.g. the hash, the size, and the fragment number with respect to the original file).Note that
FillerFragmentsdo not point to any “real” files. Therefore, the values of the original file and the fragment will be mostly identical. The file metadata is included only for consistency with theFileFragment.
-
property
woodblock.fragments.RandomDataFragment.size¶ Return the size of the fragment.
- Return type
int
-
class
woodblock.fragments.ZeroesFragment(size, chunk_size=8192)¶ A fragment filled with random bytes.
- Parameters
size (int) – the size of the fragment
-
property
woodblock.fragments.ZeroesFragment.hash¶ Return the SHA-256 digest as hexadecimal string.
- Return type
str
-
property
woodblock.fragments.FileFragment.metadata Return the fragment metadata.
- Return type
dict
The fragment metadata is a
dictcontaining information about the file the fragments originates from (e.g. the hash, the size, and the type) as well as information about the current fragment (e.g. the hash, the size, and the fragment number with respect to the original file).Note that
FillerFragmentsdo not point to any “real” files. Therefore, the values of the original file and the fragment will be mostly identical. The file metadata is included only for consistency with theFileFragment.
-
property
woodblock.fragments.ZeroesFragment.size¶ Return the size of the fragment.
- Return type
int
woodblock.scenario¶
-
class
woodblock.scenario.Scenario(name)¶ This class represents a file carving scenario.
- Parameters
name (str) – the name of the scenario
A scenario contains fragments in a certain order.
namedefines the name of the scenario which identifies the scenario in the ground truth files.
-
woodblock.scenario.Scenario.add(fragment)¶ Add a fragment to the scenario.
- Parameters
fragment – the fragment to add to the scenario
-
woodblock.scenario.Scenario.add(fragments) The same as
add(scenario)but this timescenariosis a list or tuple of fragments to be added to the scenario.- Parameters
fragments – a list fragments to add to the scenario
-
property
woodblock.scenario.Scenario.metadata¶ Return a dict containing metadata about the scenario.
- Return type
dict
woodblock.image¶
-
class
woodblock.image.Image(block_size=512, padding_generator=woodblock.datagen.Random())¶ The
Imageclass represents a carving test image.- Parameters
block_size (int) – The block size to be used in the image
padding_generator – The data generator to use
An image contains a sequence of
Scenarioinstances. An image has a fixed block size and all blocks smaller than the block size will be padded with data generated by a configurable data generator. If nopadding_generatoris specified, random data will be used as padding.
-
woodblock.scenario.Image.add(scenario)¶ Add a
Scenarioto the image.- Parameters
scenario (woodblock.scenario.Scenario) – The scenario to add
-
static
woodblock.scenario.Image.from_config(path)¶ Create an
Imageinstance based on a configuration file.- Parameters
path (pathlib.Path) – Path to the configuration file
-
woodblock.scenario.Image.write(path)¶ Write the image to disk.
- Parameters
path (pathlib.Path) – The image output path
This method write the image to the specified
path. Moreover, it also writes the image metadata to disk. The metadata file will bepathwith the “.json” extension. E.g. ifpathis “test-image.dd” then the actual image will be in “test-image.dd” and the metadata will be in “test-image.dd.json”.