@@ -2097,6 +2097,10 @@ struct ZipHd2
20972097 lUInt16 getZIPAttr () { return _Attr_and_Offset[0 ]; }
20982098 lUInt32 getAttr () { return _Attr_and_Offset[1 ] | ((lUInt32)_Attr_and_Offset[2 ]<<16 ); }
20992099 lUInt32 getOffset () { return _Attr_and_Offset[3 ] | ((lUInt32)_Attr_and_Offset[4 ]<<16 ); }
2100+ void setOffset (lUInt32 offset) {
2101+ _Attr_and_Offset[3 ] = (lUInt16)(offset & 0xFFFF );
2102+ _Attr_and_Offset[4 ] = (lUInt16)(offset >> 16 );
2103+ }
21002104 void byteOrderConv ()
21012105 {
21022106 //
@@ -2489,14 +2493,20 @@ class LVZipDecodeStream : public LVNamedStream
24892493
24902494class LVZipArc : public LVArcContainerBase
24912495{
2496+ protected:
2497+ // whether the alternative "truncated" method was used, or is to be used
2498+ bool m_alt_reading_method = false ;
24922499public:
2500+ bool usedAltReadingMethod () { return m_alt_reading_method; }
2501+ void useAltReadingMethod () { m_alt_reading_method = true ; }
2502+
24932503 virtual LVStreamRef OpenStream ( const wchar_t * fname, lvopen_mode_t /* mode*/ )
24942504 {
24952505 if ( fname[0 ]==' /' )
24962506 fname++;
24972507 int found_index = -1 ;
24982508 for (int i=0 ; i<m_list.length (); i++) {
2499- if ( !lStr_cmp ( fname, m_list[i]->GetName () ) ) {
2509+ if ( m_list[i]-> GetName () != NULL && !lStr_cmp ( fname, m_list[i]->GetName () ) ) {
25002510 if ( m_list[i]->IsContainer () ) {
25012511 // found directory with same name!!!
25022512 return LVStreamRef ();
@@ -2592,6 +2602,18 @@ class LVZipArc : public LVArcContainerBase
25922602 }
25932603
25942604 truncated = !found;
2605+
2606+ // If the main reading method (using zip header at the end of the
2607+ // archive) failed, we can try using the alternative method used
2608+ // when this zip header is missing ("truncated"), which uses
2609+ // local zip headers met along while scanning the zip.
2610+ if (m_alt_reading_method)
2611+ truncated = true ; // do as if truncated
2612+ else if (truncated) // archive detected as truncated
2613+ // flag that, so there's no need to try that alt method,
2614+ // as it was used on first scan
2615+ m_alt_reading_method = true ;
2616+
25952617 if (truncated)
25962618 NextPosition=0 ;
25972619
@@ -2612,6 +2634,11 @@ class LVZipArc : public LVArcContainerBase
26122634
26132635 if (truncated)
26142636 {
2637+ // The offset (that we don't find in a local header, but
2638+ // that we will store in the ZipHeader we're building)
2639+ // happens to be the current position here.
2640+ lUInt32 offset = (lUInt32)m_stream->GetPos ();
2641+
26152642 m_stream->Read ( &ZipHd1, ZipHd1_size, &ReadSize);
26162643 ZipHd1.byteOrderConv ();
26172644
@@ -2636,6 +2663,10 @@ class LVZipArc : public LVArcContainerBase
26362663 ZipHeader.NameLen =ZipHd1.getNameLen ();
26372664 ZipHeader.AddLen =ZipHd1.getAddLen ();
26382665 ZipHeader.Method =ZipHd1.getMethod ();
2666+ ZipHeader.setOffset (offset);
2667+ // We may get a last invalid record with NameLen=0, which shouldn't hurt.
2668+ // If it does, use:
2669+ // if (ZipHeader.NameLen == 0) break;
26392670 } else {
26402671
26412672 m_stream->Read ( &ZipHeader, ZipHeader_size, &ReadSize);
@@ -2742,8 +2773,17 @@ class LVZipArc : public LVArcContainerBase
27422773 return NULL ;
27432774 LVZipArc * arc = new LVZipArc ( stream );
27442775 int itemCount = arc->ReadContents ();
2776+ if ( itemCount > 0 && arc->usedAltReadingMethod () ) {
2777+ printf (" CRE WARNING: zip file truncated: going on with possibly partial content.\n " );
2778+ }
2779+ else if ( itemCount <= 0 && !arc->usedAltReadingMethod () ) {
2780+ printf (" CRE WARNING: zip file corrupted or invalid: trying alternative processing...\n " );
2781+ arc->useAltReadingMethod ();
2782+ itemCount = arc->ReadContents ();
2783+ }
27452784 if ( itemCount <= 0 )
27462785 {
2786+ printf (" CRE WARNING: zip file corrupted or invalid: processing failure.\n " );
27472787 delete arc;
27482788 return NULL ;
27492789 }
0 commit comments