TarReader Class Reference

#include <Pt/System/TarReader.h>

Reads a tar archive from a stream, one chunk at a time. More...

Public Member Functions

 TarReader ()
 Creates a reader with no stream attached.
 TarReader (std::istream &is)
 Creates a reader that parses is.
 ~TarReader ()
 Destructor.
void attach (std::istream &is)
 Attaches is as the source.
void detach ()
 Detaches the current source.
void reset ()
 Clears the parse state and detaches the source.
void reset (std::istream &is)
 Clears the parse state and attaches is.
const TarEntry * advance (std::streamsize importSize=0)
 Parses the next header or delivers the next content chunk.
bool isEnd () const
 Returns true after the end-of-archive marker has been read.

Detailed Description

A TarReader walks a Pax/UStar archive held by a std::istream. Each call to advance() does a bounded amount of work and then returns, so the same reader serves a file that is already complete and a socket that delivers the archive in pieces. The caller asks for the next step, processes what came back, and asks again.

advance() returns a TarEntry once a member header has been parsed, and returns the same entry again for each following content chunk. The pointer is null when the stream has no more bytes yet. That is a pause, not the end of the archive. The caller waits for more input and calls advance() again with the same reader. isEnd() becomes true only after the two zero blocks that mark the end of the archive have been read. A null return together with isEnd() means there is nothing further to read.

The entry stays valid until the next advance() call. Its metadata is complete on the first return for that member: path, type, size, link target, permissions, modification time, owner id and name, and group id and name. A Pax extended header that preceded the member is already applied, so the caller never sees the Pax header as an entry of its own. A global Pax header is skipped. A member type the reader does not recognise is skipped as well, including its content, and the next recognised member is what comes back.

Content arrives through the entry's window. TarEntry::data() points at TarEntry::avail() bytes inside the reader's buffer. Copy those bytes out before the next advance(), which reuses the buffer. For a file, repeat until TarEntry::isEnd() is true, then call advance() once more to move to the following member. A directory and a link have no content, so isEnd() is already true on the first return.

The importSize argument bounds how much advance() may pull from the stream. Zero means: use only the bytes the stream buffer already holds, and do not block. That is the right call from an event loop, after the loop has been told that the stream is readable. A positive value allows advance() to read up to that many additional bytes, which may block, and suits a file stream whose data is known to be available.

A header whose checksum does not match throws Pt::IOError. The archive is then unusable from the point of the bad header, because the reader can no longer trust the block boundaries.

TarReader reader(stream);
while( ! reader.isEnd() )
{
const TarEntry* entry = reader.advance();
if( ! entry )
break; // stream starved; call advance() again when more arrives
if(entry->type() == TarEntry::File)
{
do
{
out.write(entry->data(), entry->avail());
if(entry->isEnd())
break;
entry = reader.advance();
}
while(entry);
}
}
One entry in a tar archive.
Definition TarEntry.h:72
@ File
Regular file.
Definition TarEntry.h:79
const char * data() const
Returns the current content chunk of avail() bytes.
Definition TarEntry.h:147
bool isEnd() const
Returns true when every content byte has been delivered.
Definition TarEntry.h:121
std::size_t avail() const
Returns the number of bytes readable at data().
Definition TarEntry.h:138
Type type() const
Returns the member kind.
Definition TarEntry.h:152
TarReader()
Creates a reader with no stream attached.

Member Function Documentation

◆ attach()

void attach ( std::istream & is)

Parsing continues with the next header. Call reset() instead when the new stream is the start of an archive.

◆ detach()

void detach ( )

The parse state is kept. advance() returns null until a stream is attached again.

◆ reset()

void reset ( std::istream & is)

The next advance() call starts at the first header of is.

◆ advance()

const TarEntry * advance ( std::streamsize importSize = 0)

Consumes the chunk previously exposed through TarEntry::data() and then reads what it needs from the stream. Copy those bytes out before calling advance() again.

A return of null with isEnd() false means the stream buffer ran out. Call advance() again when more bytes are available. A return of null with isEnd() true means the end-of-archive marker has been read.

Parameters
importSizeMaximum number of additional bytes to pull from the stream. Zero uses only bytes already buffered and does not block.
Returns
The current entry, or null when more input is required or the archive has ended.
Exceptions
Pt::IOErrorif a header checksum does not match.