1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
/* Copyright (c) 2008-2022 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Covered Software is provided under this License on an "as is"
* basis, without warranty of any kind, either expressed, implied, or
* statutory, including, without limitation, warranties that the
* Covered Software is free of defects, merchantable, fit for a
* particular purpose or non-infringing.
* See the Mozilla Public License v. 2.0 for more details.
*
* For more details, see http://www.mrtrix.org/.
*/
#ifndef __image_io_sparse_legacy_h__
#define __image_io_sparse_legacy_h__
#include <cassert>
#include <cstring>
#include <fstream>
#include <typeinfo>
#include "debug.h"
#include "memory.h"
#include "file/config.h"
#include "file/mmap.h"
#include "file/utils.h"
#include "image_io/default.h"
namespace MR
{
namespace ImageIO
{
// A quick description of how the sparse image data are currently stored:
// * The data are either after the image data within the same file if extension is .msf, or
// in a separate file with the .sdat extension if the image extension if .msh
// * The image header must store the fields defined in lib/image/fixel/key.h
// These are currently verified on construction of the BufferSparse class. This proved to
// be simpler than trying to verify class matching on every interaction with the handler
// using templated functions.
// * The raw image data consists of unsigned 64-bit integer values. These values correspond to
// an offset from the start of the sparse data (wherever that may be) to the sparse data
// stored for that particular voxel.
// * Wherever sparse data for a voxel is stored, the data begins with a single unsigned 32-bit
// integer, which encodes the number of elements in that voxel. The following data is then
// a raw memory dump of that many instances of the relevant class type.
// * When a sparse image is created for writing, a single unsigned 32-bit integer value of 0
// is written at the start of the sparse data. This is done so that uninitialised voxels
// can have their raw image value set to 0, and if they are dereferenced, the handler will
// indicate that there are zero elements for that voxel.
// * The handler does not attempt any type of endianness conversion of the sparse data, so the
// systems that read/write the image files must have the same endianness. Since this can't
// be determined from the sparse data alone, the relevant Image::Format instead enforces
// the endianness of the image data to be native, and assumes that the sparse data has
// the same endianness. If the endianness does not match, the file won't open.
class SparseLegacy : public Default
{ MEMALIGN (SparseLegacy)
public:
SparseLegacy (const Header& header, const std::string& sparse_class_name, const size_t sparse_class_size, const File::Entry& entry) :
Default (header),
class_name (sparse_class_name),
class_size (sparse_class_size),
file (entry),
data_end (0) { }
//! Find the number of elements in a particular voxel based on its file offset
uint32_t get_numel (const uint64_t offset) const {
return *(reinterpret_cast<uint32_t*>(off2mem(offset)));
}
//! Request memory location for new sparse data to be written
/*!
* This also ensures that the sparse data buffer is sufficiently large
* to contain the new information. It takes current offset value for
* that voxel, and the desired number of elements. The return value is
* the offset from the start of the sparse data */
uint64_t set_numel (const uint64_t old_offset, const uint32_t numel);
//! Return a pointer to an element in a voxel
uint8_t* get (const uint64_t voxel_offset, const size_t index) const {
assert (index < get_numel (voxel_offset));
const uint64_t offset = sizeof(uint32_t) + (index * class_size);
assert (voxel_offset + offset + class_size <= data_end);
uint8_t* const ptr = off2mem(voxel_offset) + offset;
return ptr;
}
const std::string& get_class_name() const { return class_name; }
size_t get_class_size() const { return class_size; }
protected:
virtual void load (const Header&, size_t);
virtual void unload (const Header&);
const std::string class_name;
const size_t class_size;
const File::Entry file;
uint64_t data_end;
std::unique_ptr<File::MMap> mmap;
uint64_t size() const { return mmap ? mmap->size() : 0; }
// Convert a file position offset (as read from the image data) to a pointer to the relevant sparsely-stored data
uint8_t* off2mem (const uint64_t offset) const { assert (mmap); return mmap->address() + offset; }
};
}
}
#endif
|