Tests for un-tar code.
This commit is contained in:
parent
f824cf85a4
commit
e695505e62
@ -83,4 +83,12 @@ add_executable(test_repository test_repository.cxx)
|
|||||||
target_link_libraries(test_repository ${TEST_LIBS})
|
target_link_libraries(test_repository ${TEST_LIBS})
|
||||||
add_test(http_repository ${EXECUTABLE_OUTPUT_PATH}/test_repository)
|
add_test(http_repository ${EXECUTABLE_OUTPUT_PATH}/test_repository)
|
||||||
|
|
||||||
|
add_executable(test_untar test_untar.cxx)
|
||||||
|
|
||||||
|
set_target_properties(test_untar PROPERTIES
|
||||||
|
COMPILE_DEFINITIONS "SRC_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"" )
|
||||||
|
|
||||||
|
target_link_libraries(test_untar ${TEST_LIBS})
|
||||||
|
add_test(untar ${EXECUTABLE_OUTPUT_PATH}/test_untar)
|
||||||
|
|
||||||
endif(ENABLE_TESTS)
|
endif(ENABLE_TESTS)
|
||||||
|
BIN
simgear/io/test.tar.gz
Normal file
BIN
simgear/io/test.tar.gz
Normal file
Binary file not shown.
BIN
simgear/io/test2.tar
Normal file
BIN
simgear/io/test2.tar
Normal file
Binary file not shown.
58
simgear/io/test_untar.cxx
Normal file
58
simgear/io/test_untar.cxx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// Test harness.
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "untar.hxx"
|
||||||
|
|
||||||
|
#include <simgear/misc/test_macros.hxx>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
#include <simgear/io/sg_file.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
using std::cout;
|
||||||
|
using std::cerr;
|
||||||
|
using std::endl;
|
||||||
|
|
||||||
|
using namespace simgear;
|
||||||
|
|
||||||
|
void testTarGz()
|
||||||
|
{
|
||||||
|
SGPath p = SGPath(SRC_DIR);
|
||||||
|
p.append("test.tar.gz");
|
||||||
|
|
||||||
|
SGBinaryFile f(p.str());
|
||||||
|
f.open(SG_IO_IN);
|
||||||
|
|
||||||
|
uint8_t* buf = (uint8_t*) alloca(8192);
|
||||||
|
size_t bufSize = f.read((char*) buf, 8192);
|
||||||
|
|
||||||
|
VERIFY(TarExtractor::isTarData(buf, bufSize));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void testPlainTar()
|
||||||
|
{
|
||||||
|
SGPath p = SGPath(SRC_DIR);
|
||||||
|
p.append("test2.tar");
|
||||||
|
|
||||||
|
SGBinaryFile f(p.str());
|
||||||
|
f.open(SG_IO_IN);
|
||||||
|
|
||||||
|
uint8_t* buf = (uint8_t*) alloca(8192);
|
||||||
|
size_t bufSize = f.read((char*) buf, 8192);
|
||||||
|
|
||||||
|
VERIFY(TarExtractor::isTarData(buf, bufSize));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int ac, char ** av)
|
||||||
|
{
|
||||||
|
testTarGz();
|
||||||
|
testPlainTar();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -63,7 +63,7 @@ typedef struct
|
|||||||
const size_t TAR_HEADER_BLOCK_SIZE = 512;
|
const size_t TAR_HEADER_BLOCK_SIZE = 512;
|
||||||
|
|
||||||
#define TMAGIC "ustar" /* ustar and a null */
|
#define TMAGIC "ustar" /* ustar and a null */
|
||||||
#define TMAGLEN 6
|
#define TMAGLEN 5 // 5, not 6, becuase some files use 'ustar '
|
||||||
#define TVERSION "00" /* 00 and no null */
|
#define TVERSION "00" /* 00 and no null */
|
||||||
#define TVERSLEN 2
|
#define TVERSLEN 2
|
||||||
|
|
||||||
@ -106,10 +106,12 @@ public:
|
|||||||
z_stream zlibStream;
|
z_stream zlibStream;
|
||||||
uint8_t* zlibOutput;
|
uint8_t* zlibOutput;
|
||||||
bool haveInitedZLib;
|
bool haveInitedZLib;
|
||||||
|
bool uncompressedData; // set if reading a plain .tar (not tar.gz)
|
||||||
uint8_t* headerPtr;
|
uint8_t* headerPtr;
|
||||||
|
|
||||||
TarExtractorPrivate() :
|
TarExtractorPrivate() :
|
||||||
haveInitedZLib(false)
|
haveInitedZLib(false),
|
||||||
|
uncompressedData(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,6 +279,7 @@ TarExtractor::TarExtractor(const SGPath& rootPath) :
|
|||||||
|
|
||||||
TarExtractor::~TarExtractor()
|
TarExtractor::~TarExtractor()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TarExtractor::extractBytes(const char* bytes, size_t count)
|
void TarExtractor::extractBytes(const char* bytes, size_t count)
|
||||||
@ -289,18 +292,34 @@ void TarExtractor::extractBytes(const char* bytes, size_t count)
|
|||||||
d->zlibStream.avail_in = count;
|
d->zlibStream.avail_in = count;
|
||||||
|
|
||||||
if (!d->haveInitedZLib) {
|
if (!d->haveInitedZLib) {
|
||||||
|
// now we have data, see if we're dealing with GZ-compressed data or not
|
||||||
|
uint8_t* ubytes = (uint8_t*) bytes;
|
||||||
|
if ((ubytes[0] == 0x1f) && (ubytes[1] == 0x8b)) {
|
||||||
|
// GZIP identification bytes
|
||||||
if (inflateInit2(&d->zlibStream, ZLIB_INFLATE_WINDOW_BITS | ZLIB_DECODE_GZIP_HEADER) != Z_OK) {
|
if (inflateInit2(&d->zlibStream, ZLIB_INFLATE_WINDOW_BITS | ZLIB_DECODE_GZIP_HEADER) != Z_OK) {
|
||||||
SG_LOG(SG_IO, SG_WARN, "inflateInit2 failed");
|
SG_LOG(SG_IO, SG_WARN, "inflateInit2 failed");
|
||||||
d->state = TarExtractorPrivate::BAD_DATA;
|
d->state = TarExtractorPrivate::BAD_DATA;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
UstarHeaderBlock* header = (UstarHeaderBlock*) bytes;
|
||||||
|
if (strncmp(header->magic, TMAGIC, TMAGLEN) != 0) {
|
||||||
|
SG_LOG(SG_IO, SG_WARN, "didn't find tar magic in header");
|
||||||
|
d->state = TarExtractorPrivate::BAD_DATA;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->uncompressedData = true;
|
||||||
|
}
|
||||||
|
|
||||||
d->haveInitedZLib = true;
|
d->haveInitedZLib = true;
|
||||||
d->setState(TarExtractorPrivate::READING_HEADER);
|
d->setState(TarExtractorPrivate::READING_HEADER);
|
||||||
}
|
} // of init on first-bytes case
|
||||||
}
|
|
||||||
|
|
||||||
|
if (d->uncompressedData) {
|
||||||
|
d->processBytes(bytes, count);
|
||||||
|
} else {
|
||||||
size_t writtenSize;
|
size_t writtenSize;
|
||||||
|
|
||||||
// loop, running zlib() inflate and sending output bytes to
|
// loop, running zlib() inflate and sending output bytes to
|
||||||
// our request body handler. Keep calling inflate until no bytes are
|
// our request body handler. Keep calling inflate until no bytes are
|
||||||
// written, and ZLIB has consumed all available input
|
// written, and ZLIB has consumed all available input
|
||||||
@ -329,6 +348,7 @@ void TarExtractor::extractBytes(const char* bytes, size_t count)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while ((d->zlibStream.avail_in > 0) || (writtenSize > 0));
|
} while ((d->zlibStream.avail_in > 0) || (writtenSize > 0));
|
||||||
|
} // of Zlib-compressed data
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TarExtractor::isAtEndOfArchive() const
|
bool TarExtractor::isAtEndOfArchive() const
|
||||||
@ -341,4 +361,58 @@ bool TarExtractor::hasError() const
|
|||||||
return (d->state >= TarExtractorPrivate::ERROR_STATE);
|
return (d->state >= TarExtractorPrivate::ERROR_STATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TarExtractor::isTarData(const uint8_t* bytes, size_t count)
|
||||||
|
{
|
||||||
|
if (count < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UstarHeaderBlock* header = 0;
|
||||||
|
if ((bytes[0] == 0x1f) && (bytes[1] == 0x8b)) {
|
||||||
|
// GZIP identification bytes
|
||||||
|
z_stream z;
|
||||||
|
uint8_t* zlibOutput = static_cast<uint8_t*>(alloca(4096));
|
||||||
|
memset(&z, 0, sizeof(z_stream));
|
||||||
|
z.zalloc = Z_NULL;
|
||||||
|
z.zfree = Z_NULL;
|
||||||
|
z.avail_out = 4096;
|
||||||
|
z.next_out = zlibOutput;
|
||||||
|
z.next_in = (uint8_t*) bytes;
|
||||||
|
z.avail_in = count;
|
||||||
|
|
||||||
|
if (inflateInit2(&z, ZLIB_INFLATE_WINDOW_BITS | ZLIB_DECODE_GZIP_HEADER) != Z_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = inflate(&z, Z_SYNC_FLUSH);
|
||||||
|
if (result != Z_OK) {
|
||||||
|
SG_LOG(SG_IO, SG_WARN, "inflate failed:" << result);
|
||||||
|
return false; // not tar data
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t written = 4096 - z.avail_out;
|
||||||
|
if (written < TAR_HEADER_BLOCK_SIZE) {
|
||||||
|
SG_LOG(SG_IO, SG_WARN, "insufficient data for header");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
header = reinterpret_cast<UstarHeaderBlock*>(zlibOutput);
|
||||||
|
} else {
|
||||||
|
// uncompressed tar
|
||||||
|
if (count < TAR_HEADER_BLOCK_SIZE) {
|
||||||
|
SG_LOG(SG_IO, SG_WARN, "insufficient data for header");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
header = (UstarHeaderBlock*) bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(header->magic, TMAGIC, TMAGLEN) != 0) {
|
||||||
|
SG_LOG(SG_IO, SG_WARN, "not a tar file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // of simgear
|
} // of simgear
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
@ -33,6 +34,8 @@ public:
|
|||||||
TarExtractor(const SGPath& rootPath);
|
TarExtractor(const SGPath& rootPath);
|
||||||
~TarExtractor();
|
~TarExtractor();
|
||||||
|
|
||||||
|
static bool isTarData(const uint8_t* bytes, size_t count);
|
||||||
|
|
||||||
void extractBytes(const char* bytes, size_t count);
|
void extractBytes(const char* bytes, size_t count);
|
||||||
|
|
||||||
bool isAtEndOfArchive() const;
|
bool isAtEndOfArchive() const;
|
||||||
|
Loading…
Reference in New Issue
Block a user