34const char *kTransportSeparator =
"://";
37const char *kLineBreakTokens[] = {
"",
"\r\n",
"\n",
"\r\n"};
38constexpr unsigned int kLineBreakTokenSizes[] = {0, 2, 1, 2};
40const char *kLineBreakTokens[] = {
"",
"\n",
"\n",
"\r\n"};
41constexpr unsigned int kLineBreakTokenSizes[] = {0, 1, 1, 2};
43constexpr unsigned int kLineBuffer = 128;
51 size_t copiedBytes = 0;
53 if (offsetInBuffer <
static_cast<std::uint64_t
>(
fBufferSize)) {
54 size_t bytesInBuffer = std::min(nbytes,
static_cast<size_t>(
fBufferSize - offsetInBuffer));
55 memcpy(buffer,
fBuffer + offsetInBuffer, bytesInBuffer);
56 copiedBytes = bytesInBuffer;
69 delete[] fBufferSpace;
72std::unique_ptr<ROOT::Internal::RRawFile>
75 std::string transport = GetTransport(url);
76 if (transport ==
"file") {
78 return std::unique_ptr<RRawFile>(
new RRawFileWin(url, options));
80 return std::unique_ptr<RRawFile>(
new RRawFileUnix(url, options));
83 if (transport ==
"http" || transport ==
"https" ||
84 transport ==
"root" || transport ==
"roots" ) {
85 std::string plgclass = transport.compare( 0, 4,
"http" ) == 0 ?
86 "RRawFileDavix" :
"RRawFileNetXNG";
88 FindHandler(
"ROOT::Internal::RRawFile", std::string(url).c_str())) {
89 if (
h->LoadPlugin() == 0) {
90 return std::unique_ptr<RRawFile>(
reinterpret_cast<RRawFile *
>(
h->ExecPlugin(2, &url, &options)));
92 throw std::runtime_error(
"Cannot load plugin handler for " + plgclass);
94 throw std::runtime_error(
"Cannot find plugin handler for " + plgclass);
96 throw std::runtime_error(
"Unsupported transport protocol: " + transport);
102 throw std::runtime_error(
"Memory mapping unsupported");
107 for (
unsigned i = 0; i < nReq; ++i) {
114 throw std::runtime_error(
"Memory mapping unsupported");
119 auto idx = url.find(kTransportSeparator);
120 if (idx == std::string_view::npos)
121 return std::string(url);
122 return std::string(url.substr(idx + strlen(kTransportSeparator)));
131 if (fFileSize == kUnknownFileSize)
132 fFileSize = GetSizeImpl();
142 auto idx = url.find(kTransportSeparator);
143 if (idx == std::string_view::npos)
145 std::string transport(url.substr(0, idx));
146 std::transform(transport.begin(), transport.end(), transport.begin(), ::tolower);
155 return MapImpl(nbytes, offset, mapdOffset);
160 size_t res = ReadAt(buffer, nbytes, fFilePos);
173 if (nbytes >
static_cast<unsigned int>(fOptions.fBlockSize))
174 return ReadAtImpl(buffer, nbytes, offset);
176 if (fBufferSpace ==
nullptr) {
177 fBufferSpace =
new unsigned char[kNumBlockBuffers * fOptions.fBlockSize];
178 for (
unsigned int i = 0; i < kNumBlockBuffers; ++i)
179 fBlockBuffers[i].
fBuffer = fBufferSpace + i * fOptions.fBlockSize;
182 size_t totalBytes = 0;
183 size_t copiedBytes = 0;
185 for (
unsigned int idx = fBlockBufferIdx; idx < fBlockBufferIdx + kNumBlockBuffers; ++idx) {
186 copiedBytes = fBlockBuffers[idx % kNumBlockBuffers].CopyTo(buffer, nbytes, offset);
187 buffer =
reinterpret_cast<unsigned char *
>(buffer) + copiedBytes;
188 nbytes -= copiedBytes;
189 offset += copiedBytes;
190 totalBytes += copiedBytes;
192 fBlockBufferIdx = idx;
201 RBlockBuffer *thisBuffer = &fBlockBuffers[fBlockBufferIdx % kNumBlockBuffers];
202 size_t res = ReadAtImpl(thisBuffer->
fBuffer, fOptions.fBlockSize, offset);
205 size_t remainingBytes = std::min(res, nbytes);
206 memcpy(buffer, thisBuffer->
fBuffer, remainingBytes);
207 totalBytes += remainingBytes;
216 ReadVImpl(ioVec, nReq);
221 if (fOptions.fLineBreak == ELineBreaks::kAuto) {
223 fOptions.fLineBreak = ELineBreaks::kUnix;
224 bool res = Readln(
line);
225 if ((
line.length() > 0) && (*
line.rbegin() ==
'\r')) {
226 fOptions.fLineBreak = ELineBreaks::kWindows;
233 char buffer[kLineBuffer];
236 nbytes = Read(buffer,
sizeof(buffer));
237 std::string_view bufferView(buffer, nbytes);
238 auto idx = bufferView.find(kLineBreakTokens[
static_cast<int>(fOptions.fLineBreak)]);
239 if (idx != std::string_view::npos) {
241 line.append(buffer, idx);
242 fFilePos -= nbytes - idx;
243 fFilePos += kLineBreakTokenSizes[
static_cast<int>(fOptions.fLineBreak)];
246 line.append(buffer, nbytes);
247 }
while (nbytes > 0);
249 return !
line.empty();
260 throw std::runtime_error(
"Cannot unmap, file not open");
261 UnmapImpl(region, nbytes);
The RRawFileUnix class uses POSIX calls to read from a mounted file system.
The RRawFileWin class uses portable C I/O calls to read from a drive.
The RRawFile provides read-only access to local and remote files.
unsigned char * fBufferSpace
Memory block containing the block buffers consecutively.
static std::string GetLocation(std::string_view url)
Returns only the file location, e.g. "server/file" for http://server/file.
unsigned int fBlockBufferIdx
To be used modulo kNumBlockBuffers, points to the last used block buffer in fBlockBuffers.
RRawFile(std::string_view url, ROptions options)
std::uint64_t fFilePos
The current position in the file, which can be changed by Seek, Read, and Readln.
virtual void * MapImpl(size_t nbytes, std::uint64_t offset, std::uint64_t &mapdOffset)
If a derived class supports mmap, the MapImpl and UnmapImpl calls are supposed to be implemented,...
void Unmap(void *region, size_t nbytes)
Receives a pointer returned by Map() and should have nbytes set to the full length of the mapping.
virtual void ReadVImpl(RIOVec *ioVec, unsigned int nReq)
By default implemented as a loop of ReadAt calls but can be overwritten, e.g. XRootD or DAVIX impleme...
static std::string GetTransport(std::string_view url)
Returns only the transport protocol in lower case, e.g. "http" for HTTP://server/file.
std::uint64_t GetSize()
Returns the size of the file.
static std::unique_ptr< RRawFile > Create(std::string_view url, ROptions options=ROptions())
Factory method that returns a suitable concrete implementation according to the transport in the url.
void Seek(std::uint64_t offset)
Change the cursor fFilePos.
static constexpr std::uint64_t kUnknownFileSize
Derived classes do not necessarily need to provide file size information but they can return "not kno...
size_t ReadAt(void *buffer, size_t nbytes, std::uint64_t offset)
Buffered read from a random position.
bool fIsOpen
Files are opened lazily and only when required; the open state is kept by this flag.
bool Readln(std::string &line)
Read the next line starting from the current value of fFilePos. Returns false if the end of the file ...
void ReadV(RIOVec *ioVec, unsigned int nReq)
Opens the file if necessary and calls ReadVImpl.
size_t Read(void *buffer, size_t nbytes)
Read from fFilePos offset. Returns the actual number of bytes read.
std::string GetUrl() const
Returns the url of the file.
std::uint64_t fFileSize
The cached file size.
virtual void UnmapImpl(void *region, size_t nbytes)
Derived classes with mmap support must be able to unmap the memory area handed out by Map()
void * Map(size_t nbytes, std::uint64_t offset, std::uint64_t &mapdOffset)
Memory mapping according to POSIX standard; in particular, new mappings of the same range replace old...
std::uint64_t fBufferOffset
Where in the open file does fBuffer start.
unsigned char * fBuffer
Points into the I/O buffer with data from the file, not owned.
size_t CopyTo(void *buffer, size_t nbytes, std::uint64_t offset)
Tries to copy up to nbytes starting at offset from fBuffer into buffer. Returns number of bytes copie...
size_t fBufferSize
The number of currently buffered bytes in fBuffer.
Used for vector reads from multiple offsets into multiple buffers.
std::size_t fOutBytes
The number of actually read bytes, set by ReadV()
On construction, an ROptions parameter can customize the RRawFile behavior.