34enum class ENameCycleError {
43struct RNameCycleResult {
45 std::optional<std::int16_t> fCycle;
52 static const char *
const kErrorStr[] = {
"",
"",
"invalid syntax",
"cycle is too large",
"name is empty"};
53 static_assert(std::size(kErrorStr) ==
static_cast<std::size_t
>(ENameCycleError::kCOUNT));
54 return kErrorStr[
static_cast<std::size_t
>(
err)];
62 return ENameCycleError::kInvalidSyntax;
63 if (res * 10 > std::numeric_limits<std::int16_t>::max())
64 return ENameCycleError::kCycleTooLarge;
69 assert(res < std::numeric_limits<std::int16_t>::max());
70 out =
static_cast<std::int16_t
>(res);
72 return ENameCycleError::kNoError;
77 RNameCycleResult result{};
79 if (nameCycleRaw.empty())
83 std::size_t semicolonIdx = nameCycleRaw.find_first_of(
';');
85 if (semicolonIdx == 0) {
86 result.fError = ENameCycleError::kNameEmpty;
91 if (nameCycleRaw.substr(semicolonIdx + 1).find_first_of(
';') != std::string_view::npos) {
92 result.fError = ENameCycleError::kInvalidSyntax;
96 result.fName = nameCycleRaw.substr(0, semicolonIdx);
97 if (semicolonIdx < std::string_view::npos) {
98 if (semicolonIdx == nameCycleRaw.length() - 1 && nameCycleRaw[semicolonIdx] ==
'*')
99 result.fError = ENameCycleError::kAnyCycle;
101 result.fError =
DecodeNumericCycle(nameCycleRaw.substr(semicolonIdx + 1).data(), result.fCycle);
133 return "path cannot be empty";
135 if (path.back() ==
'/')
136 return "path cannot end with a '/'";
139 for (
char ch : path) {
142 valid &= !(ch < 33 || ch ==
'.');
145 return "path cannot contain control characters, whitespaces or dots";
152 const auto len = path.length();
153 while (nToStrip < len && path[nToStrip] ==
'/')
157 path.erase(0, nToStrip);
161 const auto it = std::unique(path.begin(), path.end(), [](
char a,
char b) { return (a ==
'/' && b ==
'/'); });
162 path.erase(it, path.end());
165 const auto nesting = std::count(path.begin(), path.end(),
'/');
166 if (nesting > RFile::kMaxPathNesting)
167 return "pathView contains too many levels of nesting";
183 std::string path = key.
GetName();
186 path = std::string(parent->
GetName()) +
"/" + path;
195 auto lastSlashIdx = path.rfind(
'/');
196 if (lastSlashIdx == std::string_view::npos)
199 auto dirName = path.substr(0, lastSlashIdx + 1);
200 auto pathName = path.substr(lastSlashIdx + 1);
201 return {dirName, pathName};
207 auto tfile = std::unique_ptr<TFile>(
TFile::Open(std::string(path).c_str(),
"READ_WITHOUT_GLOBALREGISTRATION"));
210 auto rfile = std::unique_ptr<RFile>(
new RFile(std::move(tfile)));
217 auto tfile = std::unique_ptr<TFile>(
TFile::Open(std::string(path).c_str(),
"UPDATE_WITHOUT_GLOBALREGISTRATION"));
220 auto rfile = std::unique_ptr<RFile>(
new RFile(std::move(tfile)));
227 auto tfile = std::unique_ptr<TFile>(
231 auto rfile = std::unique_ptr<RFile>(
new RFile(std::move(tfile)));
244 std::string fullPath = std::string(path);
245 char *dirName = fullPath.data();
246 char *restOfPath = strchr(dirName,
'/');
260 dirName = restOfPath;
261 restOfPath = strchr(restOfPath,
'/');
272 if (res.fError != ENameCycleError::kAnyCycle) {
273 if (res.fError != ENameCycleError::kNoError) {
276 }
else if (res.fCycle && *res.fCycle != key->
GetCycle()) {
285 std::variant<
const char *, std::reference_wrapper<const std::type_info>>
type)
const
290 std::string pathStr{path};
296 const TClass *cls = std::visit(std::move(typeVisitor),
type);
312 autoAddFunc(obj,
fFile.get());
318 autoAddFunc(obj,
nullptr);
323 <<
" but that path contains an object of type " << key->
GetClassName();
335 std::string path{pathSV};
339 if (path.find_first_of(
';') != std::string_view::npos) {
341 R__FAIL(
"Invalid object path '" + path +
342 "': character ';' is used to specify an object cycle, which only makes sense when reading."));
348 if (!
fFile->IsWritable())
358 const auto FullPathUntil = [&tokens](
auto idx) {
359 return ROOT::Join(
"/", std::span<const std::string>{tokens.data(), idx + 1});
362 for (
auto tokIdx = 0u; tokIdx < tokens.size() - 1; ++tokIdx) {
367 const TKey *existing = dir->
GetKey(tokens[tokIdx].c_str());
368 if (existing && strcmp(existing->
GetClassName(),
"TDirectory") != 0 &&
369 strcmp(existing->
GetClassName(),
"TDirectoryFile") != 0) {
371 FullPathUntil(tokIdx) +
"': name already taken by an object of type '" +
374 dir = dir->
mkdir(tokens[tokIdx].c_str(),
"",
true);
383 if (!allowOverwrite) {
384 const TKey *existing = dir->
GetKey(tokens[tokens.size() - 1].c_str());
389 }
else if (!backupCycle) {
390 writeOpts =
"WriteDelete";
393 int success = dir->
WriteObjectAny(obj, cls, tokens[tokens.size() - 1].c_str(), writeOpts);
413 if (!pattern.empty()) {
449 TObject *keyObj = iter->Next();
457 auto key =
static_cast<TKey *
>(keyObj);
459 const std::string dirSep = (dirPath.empty() ?
"" :
"/");
469 }
else if (!includeObj) {
474 const std::string &fullPath = dirPath + dirSep + key->GetName();
476 const std::size_t nesting =
fIterStack.size() - 1;
489 assert(!fullPath.empty());
506 const auto &dirPath =
fIterStack.back().fDirPath;
510 keyInfo.
fPath = dirPath;
512 keyInfo.
fPath += std::string(dirPath.empty() ?
"" :
"/") + key->
GetName();
521 std::vector<RKeyInfo> keys;
523 for (
const auto &key : keysIter) {
524 keys.emplace_back(key);
527 std::sort(keys.begin(), keys.end(), [](
const auto &
a,
const auto &
b) { return a.GetPath() < b.GetPath(); });
528 for (
const auto &key : keys) {
529 out << key.GetClassName() <<
" " << key.GetPath() <<
";" << key.GetCycle() <<
": \"" << key.GetTitle() <<
"\"\n";
535 return fFile->Write();
550 fNBytesObj(key.GetNbytes() - key.GetKeylen()),
575 return file.
fFile.get();
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
static const char * ToString(ENameCycleError err)
static ENameCycleError DecodeNumericCycle(const char *str, std::optional< std::int16_t > &out)
ROOT::RLogChannel & RFileLog()
static void EnsureFileOpenAndBinary(const TFile *tfile, std::string_view path)
static std::string ReconstructFullKeyPath(const TKey &key)
static RNameCycleResult DecodeNameCycle(std::string_view nameCycleRaw)
static std::string ValidateAndNormalizePath(std::string &path)
This function first validates, then normalizes the given path in place.
#define R__LOG_ERROR(...)
const char Option_t
Option string (const char).
TRObject operator()(const T1 &t1) const
std::uint16_t fRootDirNesting
std::deque< RIterStackElem > fIterStack
RIterator(TIterator *iter, Pattern_t pattern, std::uint32_t flags)
An interface to read from, or write to, a ROOT file, as well as performing other common operations.
void Close()
Flushes the RFile if needed and closes it, disallowing any further reading or writing.
std::unique_ptr< TFile > fFile
size_t Flush()
Writes all objects and the file structure to disk.
static std::unique_ptr< RFile > Update(std::string_view path)
Opens the file for updating, creating a new one if it doesn't exist.
void Print(std::ostream &out=std::cout) const
Prints the internal structure of this RFile to the given stream.
TKey * GetTKey(std::string_view path) const
Given path, returns the TKey corresponding to the object at that path (assuming the path is fully spl...
std::optional< RKeyInfo > GetKeyInfo(std::string_view path) const
Retrieves information about the key of object at path, if one exists.
static std::unique_ptr< RFile > Open(std::string_view path)
Opens the file for reading.
void * GetUntyped(std::string_view path, std::variant< const char *, std::reference_wrapper< const std::type_info > > type) const
Gets object path from the file and returns an owning pointer to it.
static std::unique_ptr< RFile > Recreate(std::string_view path, const RRecreateOptions &opts=RRecreateOptions())
Opens the file for reading/writing, overwriting it if it already exists.
void PutUntyped(std::string_view path, const std::type_info &type, const void *obj, std::uint32_t flags)
Writes obj to file, without taking its ownership.
@ kPutOverwriteKeepCycle
When overwriting an object, preserve the existing one and create a new cycle, rather than removing it...
@ kPutAllowOverwrite
When encountering an object at the specified path, overwrite it with the new one instead of erroring ...
RFileKeyIterable ListKeys(std::string_view basePath="", std::uint32_t flags=kListObjects|kListRecursive) const
Returns an iterable over all keys of objects and/or directories written into this RFile starting at p...
RFile(std::unique_ptr< TFile > file)
Information about an RFile object's Key.
const std::string & GetClassName() const
const std::string & GetTitle() const
std::uint64_t fSeekParentDir
std::uint16_t GetCycle() const
const std::string & GetPath() const
Returns the absolute path of this key, i.e. the directory part plus the object name.
std::uint64_t GetSeekKey() const
Returns the on-disk offset of this object's key.
Base class for all ROOT issued exceptions.
A log configuration for a channel, e.g.
TClass instances represent classes, structs and namespaces in the ROOT type system.
ROOT::DirAutoAdd_t GetDirectoryAutoAdd() const
Return the wrapper around the directory auto add function.
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
TDirectory::TContext keeps track and restore the current directory.
Describe directory structure in memory.
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
Find a directory using apath.
virtual Int_t WriteObjectAny(const void *, const char *, const char *, Option_t *="", Int_t=0)
virtual TKey * GetKey(const char *, Short_t=9999) const
virtual TKey * FindKey(const char *) const
virtual TDirectory * mkdir(const char *name, const char *title="", Bool_t returnExistingDirectory=kFALSE)
Create a sub-directory "a" or a hierarchy of sub-directories "a/b/c/...".
virtual TList * GetListOfKeys() const
TDirectory * GetMotherDir() const
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
virtual Bool_t IsArchive() const
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Iterator abstract base class.
Book space in a file, create I/O buffers, to fill them, (un)compress them.
const char * GetTitle() const override
Returns title (title can contain 32x32 xpm thumbnail/icon).
virtual const char * GetClassName() const
virtual void * ReadObjectAny(const TClass *expectedClass)
To read an object (non deriving from TObject) from the file.
TDirectory * GetMotherDir() const
Short_t GetCycle() const
Return cycle number associated to this key.
TIterator * MakeIterator(Bool_t dir=kIterForward) const override
Return a list iterator.
const char * GetName() const override
Returns name of object.
Mother of all ROOT objects.
virtual TClass * IsA() const
std::pair< std::string_view, std::string_view > DecomposePath(std::string_view path)
Given a "path-like" string (like foo/bar/baz), returns a pair { dirName, baseName }...
ROOT::RLogChannel & RFileLog()
void * RFile_GetObjectFromKey(RFile &file, const RKeyInfo &key)
Returns an owning pointer to the object referenced by key.
TFile * GetRFileTFile(RFile &rfile)
void MarkTObjectAsNotOnHeap(TObject &obj)
std::string Join(const std::string &sep, StringCollection_t &&strings)
Concatenate a list of strings with a separator.
bool StartsWith(std::string_view string, std::string_view prefix)
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
std::shared_ptr< TIterator > fIter
RIterStackElem(TIterator *it, const std::string &path="")
int fCompressionSettings
See core/zip/inc/Compression.h for the meaning of the compression argument.