From e695505e6201defff922473f9cf24f19fe754980 Mon Sep 17 00:00:00 2001 From: James Turner Date: Wed, 15 Jun 2016 22:27:01 +0100 Subject: [PATCH] Tests for un-tar code. --- simgear/io/CMakeLists.txt | 8 +++ simgear/io/test.tar.gz | Bin 0 -> 1179 bytes simgear/io/test2.tar | Bin 0 -> 10240 bytes simgear/io/test_untar.cxx | 58 +++++++++++++++ simgear/io/untar.cxx | 148 ++++++++++++++++++++++++++++---------- simgear/io/untar.hxx | 3 + 6 files changed, 180 insertions(+), 37 deletions(-) create mode 100644 simgear/io/test.tar.gz create mode 100644 simgear/io/test2.tar create mode 100644 simgear/io/test_untar.cxx diff --git a/simgear/io/CMakeLists.txt b/simgear/io/CMakeLists.txt index a4cf2c8f..fa0d3fc6 100644 --- a/simgear/io/CMakeLists.txt +++ b/simgear/io/CMakeLists.txt @@ -83,4 +83,12 @@ add_executable(test_repository test_repository.cxx) target_link_libraries(test_repository ${TEST_LIBS}) 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) diff --git a/simgear/io/test.tar.gz b/simgear/io/test.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..22f2a5ccdafcb45ad5f57369e3895e4ccd0607bf GIT binary patch literal 1179 zcmV;M1Z4XkiwFoVe_>Yu19W9`bS`vZascgCU5g_{6rJb%iVMD|G%=H8HV=v*v-_~1 zi!i(5n^d|h$(8Erp85z2;(zzts{R_mkrhS|>%4T*T_5+Jd(N#2+K1QdzPfoqY&M(2 z-5sUptNh$-_xU-1ZnuZsW_vj7_IujgZuk4`4c)zDP$Qxb$|00r+wkl-3_G2k`99<^ zJ^v#JL;X)(w+6WeIRI5Wpb!WY%rsbRg3m zI~Uj!+n`+&TlwUfS|;B$%4nbdS2C7W9Sw$h#GzarovVaN@wln9Q8+fjCdls{-T@?PE~1U!)Ijaxh2ErXw;IcHNA@l zudaO6&Z%i8CSDkXsCgq0)8ldFpme5DMpZu-u#2k@CT&28F0i%%dxc%&(Y&}`5qE?nk3Ka$>!m7EBgVrI5HGKf#sD;rf*JP6H z;A!GaDL6+|3bf$6f#aZNoh+N?Ei^6;?mHi~)5Ogj=LH3G5O1K))jYW=Yh+9g@@~P6 z=xp#`a^twyEG48k6<{{aSWl1$0>(9j&j1f#o%~km8u@uTJ9XtorOqLPa$YB7nT?*Z zU5poA8DzCtsFk#g$#-I`#n{=qV}ELu_qn8_ci;y3ca5fxL4~E3wdGcX2N5AE3|Dm0 zsmqOCNi6o*n-R}K=pxl|%S;g`k*bj7n47_x?j3@BBD?JSEGIEfkBzfrbEg^E%F-0& zTzk!q1Oy1 z)<~-Dn(?U2eHrV)v#U=y|Hu2^1=M%z`bF*-e{=ua+}_Ujzun<3-T!X4<^K0?;4`#j z6B|w6)IK!aeY;w*T!9qZ&pDrRXWWy}CBMY)^Yx3>Z!01vX0i0<=eO^FdH8UD|K{Q0 t>(%d{qPv2Ef`WpAf`WpAf`WpAf`WpAf`WpAf`WpV!5_HSWz+yD008UMU}gXS literal 0 HcmV?d00001 diff --git a/simgear/io/test2.tar b/simgear/io/test2.tar new file mode 100644 index 0000000000000000000000000000000000000000..e219daae9c3869616786247815ffce1cafea6cf7 GIT binary patch literal 10240 zcmeH}TZ<$`5QXQte?@>VDn;4T-Lw6m2r|153%Us7if@u#l~o;*b=kZ$3*vwGL}p!j zVI6k{76h|jrlu+{5nr4WnO-~plI=G)pYgZdZjX0&bR&OXq`%wUA^wk7@kh72<9@q4 z9`}a>ZEtsn!|sOeK4VPF(!qIU5!xS}U*3J}0mGW+V;`n>Qy!8ee)P!5|I{Zx)xQ~r z(!YNk!E*x#j~6KGKh=MK+}$npKkWCY|NeM9+|c&98$M;;|GfS`4pw)>qYE9?gBdJ2 z_M|%P3#x|R>B?&#EUB7Db`|$6X~VvxU-_cC;K)_lXv^+h&;|8;I+ONfhSOj@JL2AJ zTZc|QIi`-u4Ye}b#s3Q#%c=?nLmlE!whHntMpDvGDqv;OEnaCm;0d2tby&n0uGoi~ zdkM1*nu4c(=*eqig2UXwo|rtsKu#SORI8Cs2w2T)g%30I+*e$O-eYu0FNa=NbkT+y zRWag29DV4kl3pXFR@*g4{hrY7zaZ-T+A3tzOg zYMF_NX9f_pZUitR_PelGI$^{#-RoX~a7jPlQT3!M0xRT~#vyXlabAp0e9}GYu&&xL ziiP39_KLa)xBh%K^v&tq!<8_X`q8<=?X%^0g@T< z8EmdXeh6+vIAEib$le81Wkjt!OS$U6v6l06z(Ua@WCi+kQI>;jFo&U9B(VfqkO`Fp z*2(*Fvw4HUkx`I3VxDRdjJI4th*4Ob!q#rBb=pzNubU<+&0?SefS;|>PD3S8tI;^% zcCAN&7(@y#4B*WIb7|piY*F3KaqiFi}$y#jJHmqNKMFJTz)xQREs; zk{rBDT#=UafT$F(0Iz}Lpk^H{8|PhVTpTov|Z3T9z+PlK&^aZ}RBoE%y~ z2R5R!$$!y}^Il7Z#Dq%$R@2P&gsA~wUPE|#cmOe{w@OzKzoXWw3)fH?I)@BOc{Ru~ z89inzU1S=MO=||ME(x`emN9Q0jdeA4_3qrCI^~>7BAmPfH;C^q!HmHx=rT6UsAb)A zC&Ghl5f!YasDUG|yb>vn=oXB4u7oa9owrPgIEoa(iyTukDCyn;zz4ERzE5(JMmS>Q zB-zwyW?D&_qMXz(rWnwn<<)uUMI0(fOPx`!Dwz8@&5=)CHR&r=3HH;&)DkB_i%*pt z0?CN7!zxkgu^A(;nj)GXa zXwCA)Pv=5%`Smfk8llmlWikA6&_Q7-{%p^|C)|JL``;Pphq8LY%ugTs zFZaLg?d^L1+aK@Z{qGj{|9t=ZbjHse`2}u0Ce)g~tDLWS_ + +#include + +#include "untar.hxx" + +#include +#include +#include + + +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; +} diff --git a/simgear/io/untar.cxx b/simgear/io/untar.cxx index c2e55b92..b65dd4a6 100644 --- a/simgear/io/untar.cxx +++ b/simgear/io/untar.cxx @@ -63,7 +63,7 @@ typedef struct const size_t TAR_HEADER_BLOCK_SIZE = 512; #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 TVERSLEN 2 @@ -106,10 +106,12 @@ public: z_stream zlibStream; uint8_t* zlibOutput; bool haveInitedZLib; + bool uncompressedData; // set if reading a plain .tar (not tar.gz) uint8_t* headerPtr; TarExtractorPrivate() : - haveInitedZLib(false) + haveInitedZLib(false), + uncompressedData(false) { } @@ -277,6 +279,7 @@ TarExtractor::TarExtractor(const SGPath& rootPath) : TarExtractor::~TarExtractor() { + } void TarExtractor::extractBytes(const char* bytes, size_t count) @@ -289,46 +292,63 @@ void TarExtractor::extractBytes(const char* bytes, size_t count) d->zlibStream.avail_in = count; if (!d->haveInitedZLib) { - if (inflateInit2(&d->zlibStream, ZLIB_INFLATE_WINDOW_BITS | ZLIB_DECODE_GZIP_HEADER) != Z_OK) { - SG_LOG(SG_IO, SG_WARN, "inflateInit2 failed"); - d->state = TarExtractorPrivate::BAD_DATA; - return; + // 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) { + SG_LOG(SG_IO, SG_WARN, "inflateInit2 failed"); + d->state = TarExtractorPrivate::BAD_DATA; + return; + } } else { - d->haveInitedZLib = true; - d->setState(TarExtractorPrivate::READING_HEADER); - } - } - - size_t writtenSize; + 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; + } - // loop, running zlib() inflate and sending output bytes to - // our request body handler. Keep calling inflate until no bytes are - // written, and ZLIB has consumed all available input - do { - d->zlibStream.next_out = d->zlibOutput; - d->zlibStream.avail_out = ZLIB_DECOMPRESS_BUFFER_SIZE; - int result = inflate(&d->zlibStream, Z_NO_FLUSH); - if (result == Z_OK || result == Z_STREAM_END) { - // nothing to do - - } else if (result == Z_BUF_ERROR) { - // transient error, fall through - } else { - // _error = result; - SG_LOG(SG_IO, SG_WARN, "Permanent ZLib error:" << d->zlibStream.msg); - d->state = TarExtractorPrivate::BAD_DATA; - return; + d->uncompressedData = true; } - writtenSize = ZLIB_DECOMPRESS_BUFFER_SIZE - d->zlibStream.avail_out; - if (writtenSize > 0) { - d->processBytes((const char*) d->zlibOutput, writtenSize); - } + d->haveInitedZLib = true; + d->setState(TarExtractorPrivate::READING_HEADER); + } // of init on first-bytes case - if (result == Z_STREAM_END) { - break; - } - } while ((d->zlibStream.avail_in > 0) || (writtenSize > 0)); + if (d->uncompressedData) { + d->processBytes(bytes, count); + } else { + size_t writtenSize; + // loop, running zlib() inflate and sending output bytes to + // our request body handler. Keep calling inflate until no bytes are + // written, and ZLIB has consumed all available input + do { + d->zlibStream.next_out = d->zlibOutput; + d->zlibStream.avail_out = ZLIB_DECOMPRESS_BUFFER_SIZE; + int result = inflate(&d->zlibStream, Z_NO_FLUSH); + if (result == Z_OK || result == Z_STREAM_END) { + // nothing to do + + } else if (result == Z_BUF_ERROR) { + // transient error, fall through + } else { + // _error = result; + SG_LOG(SG_IO, SG_WARN, "Permanent ZLib error:" << d->zlibStream.msg); + d->state = TarExtractorPrivate::BAD_DATA; + return; + } + + writtenSize = ZLIB_DECOMPRESS_BUFFER_SIZE - d->zlibStream.avail_out; + if (writtenSize > 0) { + d->processBytes((const char*) d->zlibOutput, writtenSize); + } + + if (result == Z_STREAM_END) { + break; + } + } while ((d->zlibStream.avail_in > 0) || (writtenSize > 0)); + } // of Zlib-compressed data } bool TarExtractor::isAtEndOfArchive() const @@ -341,4 +361,58 @@ bool TarExtractor::hasError() const 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(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(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 diff --git a/simgear/io/untar.hxx b/simgear/io/untar.hxx index b14da6ff..254d8548 100644 --- a/simgear/io/untar.hxx +++ b/simgear/io/untar.hxx @@ -20,6 +20,7 @@ #include +#include #include namespace simgear @@ -33,6 +34,8 @@ public: TarExtractor(const SGPath& rootPath); ~TarExtractor(); + static bool isTarData(const uint8_t* bytes, size_t count); + void extractBytes(const char* bytes, size_t count); bool isAtEndOfArchive() const;