34enum class ENameCycleError {
43struct RNameCycleResult {
45 std::optional<std::int16_t> fCycle;
46 ENameCycleError fError;
50static const char *
ToString(ENameCycleError err)
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;
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;
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};
204std::unique_ptr<RFile> RFile::Open(std::string_view path,
const ROpenOptions &opts)
208 auto tfile = std::unique_ptr<TFile>(
TFile::Open(std::string(path).c_str(),
mode));
211 auto rfile = std::unique_ptr<RFile>(
new RFile(std::move(tfile)));
219 auto tfile = std::unique_ptr<TFile>(
TFile::Open(std::string(path).c_str(),
mode));
222 auto rfile = std::unique_ptr<RFile>(
new RFile(std::move(tfile)));
233 auto rfile = std::unique_ptr<RFile>(
new RFile(std::move(tfile)));
246 std::string fullPath = std::string(path);
247 char *dirName = fullPath.data();
248 char *restOfPath = strchr(dirName,
'/');
262 dirName = restOfPath;
263 restOfPath = strchr(restOfPath,
'/');
274 if (res.fError != ENameCycleError::kAnyCycle) {
275 if (res.fError != ENameCycleError::kNoError) {
276 R__LOG_ERROR(RFileLog()) <<
"error decoding namecycle '" << dirName <<
"': " <<
ToString(res.fError);
278 }
else if (res.fCycle && *res.fCycle != key->
GetCycle()) {
287 std::variant<
const char *, std::reference_wrapper<const std::type_info>>
type)
const
292 std::string pathStr{path};
296 TClass *operator()(std::reference_wrapper<const std::type_info> ty) {
return TClass::GetClass(ty.get()); }
298 const TClass *cls = std::visit(std::move(typeVisitor),
type);
314 autoAddFunc(obj,
fFile.get());
320 autoAddFunc(obj,
nullptr);
324 R__LOG_INFO(RFileLog()) <<
"Tried to get object '" << path <<
"' of type " << cls->
GetName()
325 <<
" but that path contains an object of type " << key->
GetClassName();
337 std::string path{pathSV};
341 if (path.find_first_of(
';') != std::string_view::npos) {
343 R__FAIL(
"Invalid object path '" + path +
344 "': character ';' is used to specify an object cycle, which only makes sense when reading."));
350 if (!
fFile->IsWritable())
360 const auto FullPathUntil = [&tokens](
auto idx) {
361 return ROOT::Join(
"/", std::span<const std::string>{tokens.data(), idx + 1});
364 for (
auto tokIdx = 0u; tokIdx < tokens.size() - 1; ++tokIdx) {
369 const TKey *existing = dir->
GetKey(tokens[tokIdx].c_str());
370 if (existing && strcmp(existing->
GetClassName(),
"TDirectory") != 0 &&
371 strcmp(existing->
GetClassName(),
"TDirectoryFile") != 0) {
373 FullPathUntil(tokIdx) +
"': name already taken by an object of type '" +
376 dir = dir->
mkdir(tokens[tokIdx].c_str(),
"",
true);
385 if (!allowOverwrite) {
386 const TKey *existing = dir->
GetKey(tokens[tokens.size() - 1].c_str());
391 }
else if (!backupCycle) {
392 writeOpts =
"WriteDelete";
395 int success = dir->
WriteObjectAny(obj, cls, tokens[tokens.size() - 1].c_str(), writeOpts);
403 : fIter(it), fDirPath(path)
415 if (!pattern.empty()) {
448 while (!fIterStack.empty()) {
449 auto &[iter, dirPath] = fIterStack.back();
451 TObject *keyObj = iter->Next();
454 fIterStack.pop_back();
458 assert(keyObj->
IsA() == TClass::GetClass<TKey>());
459 auto key =
static_cast<TKey *
>(keyObj);
461 const std::string dirSep = (dirPath.empty() ?
"" :
"/");
468 fIterStack.emplace_back(innerIter, dirPath + dirSep + dir->
GetName());
471 }
else if (!includeObj) {
476 const std::string &fullPath = dirPath + dirSep + key->GetName();
477 assert(!fIterStack.empty());
478 const std::size_t nesting = fIterStack.size() - 1;
490 if (!recursive && nesting != fRootDirNesting &&
491 (!isDir || nesting !=
static_cast<std::size_t
>(fRootDirNesting + 1)))
495 assert(!fullPath.empty());
503 if (fIterStack.empty())
506 const TKey *key = fCurKey;
512 const auto &dirPath = fIterStack.back().fDirPath;
516 keyInfo.
fPath = dirPath;
518 keyInfo.
fPath += std::string(dirPath.empty() ?
"" :
"/") + key->
GetName();
527 std::vector<RKeyInfo> keys;
528 auto keysIter = ListKeys();
529 for (
const auto &key : keysIter) {
530 keys.emplace_back(key);
533 std::sort(keys.begin(), keys.end(), [](
const auto &
a,
const auto &
b) { return a.GetPath() < b.GetPath(); });
534 for (
const auto &key : keys) {
535 out << key.GetClassName() <<
" " << key.GetPath() <<
";" << key.GetCycle() <<
": \"" << key.GetTitle() <<
"\"\n";
552 fTitle(key.GetTitle()),
553 fClassName(key.GetClassName()),
554 fCycle(key.GetCycle()),
555 fLenObj(key.GetObjlen()),
556 fNBytesObj(key.GetNbytes() - key.GetKeylen()),
557 fNBytesKey(key.GetKeylen()),
558 fSeekKey(key.GetSeekKey()),
559 fSeekParentDir(key.GetSeekPdir())
581 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)
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)
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
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.
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.
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 ...
RFile(std::unique_ptr< TFile > file)
static std::unique_ptr< RFile > Update(std::string_view path, const RUpdateOptions &opts=RUpdateOptions())
Opens the file for updating, creating a new one if it doesn't exist.
Information about an RFile object's Key.
const std::string & GetClassName() const
const std::string & GetPath() const
Returns the absolute path of this key, i.e. the directory part plus the object name.
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.
TList * GetListOfKeys() const override
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 ...
Int_t Write(const char *name=nullptr, Int_t opt=0, Int_t bufsize=0) override
Write memory objects to this file.
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.
R__ALWAYS_INLINE Bool_t IsZombie() const
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, InputIt_t begin, InputIt_t end)
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.
RIterStackElem(TIterator *it, const std::string &path="")
bool fEnableBrowsability
If true the RFile will show up in the TBrowser window.
bool fEnableBrowsability
If true the RFile will show up in the TBrowser window.
int fCompressionSettings
See core/zip/inc/Compression.h for the meaning of the compression argument.
bool fEnableBrowsability
If true the RFile will show up in the TBrowser window.