]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/tarstrm.cpp
fixing osx_cocoa
[wxWidgets.git] / src / common / tarstrm.cpp
index 513ea001878cf87a92f083fc12f467a689633be2..9a6d851a0e121ae9117d560b9f3929a3b534818a 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
-// Name:        tarstrm.cpp
+// Name:        src/common/tarstrm.cpp
 // Purpose:     Streams for Tar files
 // Author:      Mike Wetherell
 // RCS-ID:      $Id$
 // Purpose:     Streams for Tar files
 // Author:      Mike Wetherell
 // RCS-ID:      $Id$
@@ -19,7 +19,6 @@
 #include "wx/tarstrm.h"
 
 #ifndef WX_PRECOMP
 #include "wx/tarstrm.h"
 
 #ifndef WX_PRECOMP
-    #include "wx/hashmap.h"
     #include "wx/intl.h"
     #include "wx/log.h"
     #include "wx/utils.h"
     #include "wx/intl.h"
     #include "wx/log.h"
     #include "wx/utils.h"
 
 #include "wx/buffer.h"
 #include "wx/datetime.h"
 
 #include "wx/buffer.h"
 #include "wx/datetime.h"
-#include "wx/ptr_scpd.h"
+#include "wx/scopedptr.h"
 #include "wx/filename.h"
 #include "wx/filename.h"
+#include "wx/thread.h"
 
 #include <ctype.h>
 
 #ifdef __UNIX__
 
 #include <ctype.h>
 
 #ifdef __UNIX__
+#include <pwd.h>
 #include <grp.h>
 #endif
 
 #include <grp.h>
 #endif
 
@@ -62,7 +63,7 @@ enum {
 };
 
 enum {
 };
 
 enum {
-    TAR_BLOCKSIZE = 512,
+    TAR_BLOCKSIZE = 512
 };
 
 // checksum type
 };
 
 // checksum type
@@ -103,16 +104,16 @@ wxTarClassFactory::wxTarClassFactory()
 const wxChar * const *
 wxTarClassFactory::GetProtocols(wxStreamProtocolType type) const
 {
 const wxChar * const *
 wxTarClassFactory::GetProtocols(wxStreamProtocolType type) const
 {
-    static const wxChar *protocols[] = { _T("tar"), NULL };
-    static const wxChar *mimetypes[] = { _T("application/x-tar"), NULL };
-    static const wxChar *fileexts[]  = { _T(".tar"), NULL };
+    static const wxChar *protocols[] = { wxT("tar"), NULL };
+    static const wxChar *mimetypes[] = { wxT("application/x-tar"), NULL };
+    static const wxChar *fileexts[]  = { wxT(".tar"), NULL };
     static const wxChar *empty[]     = { NULL };
 
     switch (type) {
     static const wxChar *empty[]     = { NULL };
 
     switch (type) {
-        case wxSTREAM_PROTOCOL:         return protocols;
-        case wxSTREAM_MIMETYPE:         return mimetypes;
-        case wxSTREAM_FILEEXTENSION:    return fileexts;
-        default:                        return empty;
+        case wxSTREAM_PROTOCOL: return protocols;
+        case wxSTREAM_MIMETYPE: return mimetypes;
+        case wxSTREAM_FILEEXT:  return fileexts;
+        default:                return empty;
     }
 }
 
     }
 }
 
@@ -155,37 +156,39 @@ private:
     static void check();
 };
 
     static void check();
 };
 
-wxDEFINE_SCOPED_PTR_TYPE(wxTarHeaderBlock);
+wxDEFINE_SCOPED_PTR_TYPE(wxTarHeaderBlock)
 
 // A table giving the field names and offsets in a tar header block
 const wxTarField wxTarHeaderBlock::fields[] =
 {
 
 // A table giving the field names and offsets in a tar header block
 const wxTarField wxTarHeaderBlock::fields[] =
 {
-    { _T("name"), 0 },       // 100
-    { _T("mode"), 100 },     // 8
-    { _T("uid"), 108 },      // 8
-    { _T("gid"), 116 },      // 8
-    { _T("size"), 124 },     // 12
-    { _T("mtime"), 136 },    // 12
-    { _T("chksum"), 148 },   // 8
-    { _T("typeflag"), 156 }, // 1
-    { _T("linkname"), 157 }, // 100
-    { _T("magic"), 257 },    // 6
-    { _T("version"), 263 },  // 2
-    { _T("uname"), 265 },    // 32
-    { _T("gname"), 297 },    // 32
-    { _T("devmajor"), 329 }, // 8
-    { _T("devminor"), 337 }, // 8
-    { _T("prefix"), 345 },   // 155
-    { _T("unused"), 500 },   // 12
+    { wxT("name"), 0 },       // 100
+    { wxT("mode"), 100 },     // 8
+    { wxT("uid"), 108 },      // 8
+    { wxT("gid"), 116 },      // 8
+    { wxT("size"), 124 },     // 12
+    { wxT("mtime"), 136 },    // 12
+    { wxT("chksum"), 148 },   // 8
+    { wxT("typeflag"), 156 }, // 1
+    { wxT("linkname"), 157 }, // 100
+    { wxT("magic"), 257 },    // 6
+    { wxT("version"), 263 },  // 2
+    { wxT("uname"), 265 },    // 32
+    { wxT("gname"), 297 },    // 32
+    { wxT("devmajor"), 329 }, // 8
+    { wxT("devminor"), 337 }, // 8
+    { wxT("prefix"), 345 },   // 155
+    { wxT("unused"), 500 },   // 12
     { NULL, TAR_BLOCKSIZE }
 };
 
 void wxTarHeaderBlock::check()
 {
     { NULL, TAR_BLOCKSIZE }
 };
 
 void wxTarHeaderBlock::check()
 {
+#if 0
     wxCOMPILE_TIME_ASSERT(
         WXSIZEOF(fields) == TAR_NUMFIELDS + 1,
         Wrong_number_of_elements_in_fields_table
     );
     wxCOMPILE_TIME_ASSERT(
         WXSIZEOF(fields) == TAR_NUMFIELDS + 1,
         Wrong_number_of_elements_in_fields_table
     );
+#endif
 }
 
 bool wxTarHeaderBlock::IsAllZeros() const
 }
 
 bool wxTarHeaderBlock::IsAllZeros() const
@@ -227,7 +230,7 @@ wxUint32 wxTarHeaderBlock::SumField(int id)
 }
 
 bool wxTarHeaderBlock::Read(wxInputStream& in)
 }
 
 bool wxTarHeaderBlock::Read(wxInputStream& in)
-{   
+{
     bool ok = true;
 
     for (int id = 0; id < TAR_NUMFIELDS && ok; id++)
     bool ok = true;
 
     for (int id = 0; id < TAR_NUMFIELDS && ok; id++)
@@ -246,7 +249,7 @@ bool wxTarHeaderBlock::Write(wxOutputStream& out)
     return ok;
 }
 
     return ok;
 }
 
-bool wxTarHeaderBlock::WriteField(wxOutputStream& out, int id)
+inline bool wxTarHeaderBlock::WriteField(wxOutputStream& out, int id)
 {
     return out.Write(Get(id), Len(id)).LastWrite() == Len(id);
 }
 {
     return out.Write(Get(id), Len(id)).LastWrite() == Len(id);
 }
@@ -265,11 +268,11 @@ wxTarNumber wxTarHeaderBlock::GetOctal(int id)
 bool wxTarHeaderBlock::SetOctal(int id, wxTarNumber n)
 {
     // set an octal field, return true if the number fits
 bool wxTarHeaderBlock::SetOctal(int id, wxTarNumber n)
 {
     // set an octal field, return true if the number fits
-    char *field = Get(id); 
+    char *field = Get(id);
     char *p = field + Len(id);
     *--p = 0;
     while (p > field) {
     char *p = field + Len(id);
     *--p = 0;
     while (p > field) {
-        *--p = '0' + (n & 7);
+        *--p = char('0' + (n & 7));
         n >>= 3;
     }
     return n == 0;
         n >>= 3;
     }
     return n == 0;
@@ -288,7 +291,10 @@ bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv)
         size_t len = name.length();
         wxCharBuffer approx(len);
         for (size_t i = 0; i < len; i++)
         size_t len = name.length();
         wxCharBuffer approx(len);
         for (size_t i = 0; i < len; i++)
-            approx.data()[i] = name[i] & ~0x7F ? '_' : name[i];
+        {
+            wxChar c = name[i];
+            approx.data()[i] = c & ~0x7F ? '_' : c;
+        }
         nameBuf = approx;
     }
 
         nameBuf = approx;
     }
 
@@ -308,7 +314,7 @@ bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv)
 
     for (;;) {
         fits = i < maxprefix && len - i <= maxname;
 
     for (;;) {
         fits = i < maxprefix && len - i <= maxname;
-        
+
         if (!fits) {
             const char *p = strchr(mbName + i, '/');
             if (p)
         if (!fits) {
             const char *p = strchr(mbName + i, '/');
             if (p)
@@ -330,7 +336,7 @@ bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv)
     return fits && !badconv;
 }
 
     return fits && !badconv;
 }
 
-    
+
 /////////////////////////////////////////////////////////////////////////////
 // Some helpers
 
 /////////////////////////////////////////////////////////////////////////////
 // Some helpers
 
@@ -340,32 +346,101 @@ static wxFileOffset RoundUpSize(wxFileOffset size, int factor = 1)
     return ((size + chunk - 1) / chunk) * chunk;
 }
 
     return ((size + chunk - 1) / chunk) * chunk;
 }
 
-static wxString GroupName()
-{
 #ifdef __UNIX__
 #ifdef __UNIX__
-    group *gr;
-    if ((gr = getgrgid(getgid())) != NULL)
-        return wxString(gr->gr_name, wxConvLibc);
+
+static wxString wxTarUserName(int uid)
+{
+    struct passwd *ppw;
+
+#ifdef HAVE_GETPWUID_R
+#if defined HAVE_SYSCONF && defined _SC_GETPW_R_SIZE_MAX
+    long pwsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+    size_t bufsize(wxMin(wxMax(1024l, pwsize), 32768l));
+#else
+    size_t bufsize = 1024;
+#endif
+    wxCharBuffer buf(bufsize);
+    struct passwd pw;
+
+    memset(&pw, 0, sizeof(pw));
+    if (getpwuid_r(uid, &pw, buf.data(), bufsize, &ppw) == 0 && pw.pw_name)
+        return wxString(pw.pw_name, wxConvLibc);
+#else
+    if ((ppw = getpwuid(uid)) != NULL)
+        return wxString(ppw->pw_name, wxConvLibc);
 #endif
     return _("unknown");
 }
 
 #endif
     return _("unknown");
 }
 
-static inline int UserId()
+static wxString wxTarGroupName(int gid)
 {
 {
-#ifdef __UNIX__
-    return getuid();
+    struct group *pgr;
+#ifdef HAVE_GETGRGID_R
+#if defined HAVE_SYSCONF && defined _SC_GETGR_R_SIZE_MAX
+    long grsize = sysconf(_SC_GETGR_R_SIZE_MAX);
+    size_t bufsize(wxMin(wxMax(1024l, grsize), 32768l));
+#else
+    size_t bufsize = 1024;
+#endif
+    wxCharBuffer buf(bufsize);
+    struct group gr;
+
+    memset(&gr, 0, sizeof(gr));
+    if (getgrgid_r(gid, &gr, buf.data(), bufsize, &pgr) == 0 && gr.gr_name)
+        return wxString(gr.gr_name, wxConvLibc);
 #else
 #else
-    return 0;
+    if ((pgr = getgrgid(gid)) != NULL)
+        return wxString(pgr->gr_name, wxConvLibc);
 #endif
 #endif
+    return _("unknown");
 }
 
 }
 
-static inline int GroupId()
+#endif  // __UNIX__
+
+// Cache the user and group names since getting them can be expensive,
+// get both names and ids at the same time.
+//
+struct wxTarUser
+{
+    wxTarUser();
+    ~wxTarUser() { delete [] uname; delete [] gname; }
+
+    int uid;
+    int gid;
+
+    wxChar *uname;
+    wxChar *gname;
+};
+
+wxTarUser::wxTarUser()
 {
 #ifdef __UNIX__
 {
 #ifdef __UNIX__
-    return getgid();
+    uid = getuid();
+    gid = getgid();
+    wxString usr = wxTarUserName(uid);
+    wxString grp = wxTarGroupName(gid);
 #else
 #else
-    return 0;
+    uid = 0;
+    gid = 0;
+    wxString usr = wxGetUserId();
+    wxString grp = _("unknown");
+#endif
+
+    uname = new wxChar[usr.length() + 1];
+    wxStrcpy(uname, usr.c_str());
+
+    gname = new wxChar[grp.length() + 1];
+    wxStrcpy(gname, grp.c_str());
+}
+
+static const wxTarUser& wxGetTarUser()
+{
+#if wxUSE_THREADS
+    static wxCriticalSection cs;
+    wxCriticalSectionLocker lock(cs);
 #endif
 #endif
+    static wxTarUser tu;
+    return tu;
 }
 
 // ignore the size field for entry types 3, 4, 5 and 6
 }
 
 // ignore the size field for entry types 3, 4, 5 and 6
@@ -380,7 +455,7 @@ static inline wxFileOffset GetDataSize(const wxTarEntry& entry)
             return 0;
         default:
             return entry.GetSize();
             return 0;
         default:
             return entry.GetSize();
-    };
+    }
 }
 
 
 }
 
 
@@ -393,14 +468,14 @@ wxTarEntry::wxTarEntry(const wxString& name /*=wxEmptyString*/,
                        wxFileOffset size    /*=0*/)
   : m_Mode(0644),
     m_IsModeSet(false),
                        wxFileOffset size    /*=0*/)
   : m_Mode(0644),
     m_IsModeSet(false),
-    m_UserId(UserId()),
-    m_GroupId(GroupId()),
+    m_UserId(wxGetTarUser().uid),
+    m_GroupId(wxGetTarUser().gid),
     m_Size(size),
     m_Offset(wxInvalidOffset),
     m_ModifyTime(dt),
     m_TypeFlag(wxTAR_REGTYPE),
     m_Size(size),
     m_Offset(wxInvalidOffset),
     m_ModifyTime(dt),
     m_TypeFlag(wxTAR_REGTYPE),
-    m_UserName(wxGetUserId()),
-    m_GroupName(GroupName()),
+    m_UserName(wxGetTarUser().uname),
+    m_GroupName(wxGetTarUser().gname),
     m_DevMajor(~0),
     m_DevMinor(~0)
 {
     m_DevMajor(~0),
     m_DevMinor(~0)
 {
@@ -413,7 +488,8 @@ wxTarEntry::~wxTarEntry()
 }
 
 wxTarEntry::wxTarEntry(const wxTarEntry& e)
 }
 
 wxTarEntry::wxTarEntry(const wxTarEntry& e)
-  : m_Name(e.m_Name),
+  : wxArchiveEntry(),
+    m_Name(e.m_Name),
     m_Mode(e.m_Mode),
     m_IsModeSet(e.m_IsModeSet),
     m_UserId(e.m_UserId),
     m_Mode(e.m_Mode),
     m_IsModeSet(e.m_IsModeSet),
     m_UserId(e.m_UserId),
@@ -463,15 +539,15 @@ wxString wxTarEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const
     switch (wxFileName::GetFormat(format)) {
         case wxPATH_DOS:
         {
     switch (wxFileName::GetFormat(format)) {
         case wxPATH_DOS:
         {
-            wxString name(isDir ? m_Name + _T("\\") : m_Name);
+            wxString name(isDir ? m_Name + wxT("\\") : m_Name);
             for (size_t i = 0; i < name.length(); i++)
             for (size_t i = 0; i < name.length(); i++)
-                if (name[i] == _T('/'))
-                    name[i] = _T('\\');
+                if (name[i] == wxT('/'))
+                    name[i] = wxT('\\');
             return name;
         }
 
         case wxPATH_UNIX:
             return name;
         }
 
         case wxPATH_UNIX:
-            return isDir ? m_Name + _T("/") : m_Name;
+            return isDir ? m_Name + wxT("/") : m_Name;
 
         default:
             ;
 
         default:
             ;
@@ -518,9 +594,9 @@ wxString wxTarEntry::GetInternalName(const wxString& name,
 
     while (!internal.empty() && *internal.begin() == '/')
         internal.erase(0, 1);
 
     while (!internal.empty() && *internal.begin() == '/')
         internal.erase(0, 1);
-    while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0)
+    while (!internal.empty() && internal.compare(0, 2, wxT("./")) == 0)
         internal.erase(0, 2);
         internal.erase(0, 2);
-    if (internal == _T(".") || internal == _T(".."))
+    if (internal == wxT(".") || internal == wxT(".."))
         internal = wxEmptyString;
 
     return internal;
         internal = wxEmptyString;
 
     return internal;
@@ -528,14 +604,14 @@ wxString wxTarEntry::GetInternalName(const wxString& name,
 
 bool wxTarEntry::IsDir() const
 {
 
 bool wxTarEntry::IsDir() const
 {
-    return m_TypeFlag - wxTAR_DIRTYPE == 0;
+    return m_TypeFlag == wxTAR_DIRTYPE;
 }
 
 void wxTarEntry::SetIsDir(bool isDir)
 {
     if (isDir)
         m_TypeFlag = wxTAR_DIRTYPE;
 }
 
 void wxTarEntry::SetIsDir(bool isDir)
 {
     if (isDir)
         m_TypeFlag = wxTAR_DIRTYPE;
-    else if (m_TypeFlag - wxTAR_DIRTYPE == 0)
+    else if (m_TypeFlag == wxTAR_DIRTYPE)
         m_TypeFlag = wxTAR_REGTYPE;
 }
 
         m_TypeFlag = wxTAR_REGTYPE;
 }
 
@@ -553,7 +629,7 @@ int wxTarEntry::GetMode() const
         return m_Mode;
     else
         return m_Mode | 0111;
         return m_Mode;
     else
         return m_Mode | 0111;
-    
+
 }
 
 void wxTarEntry::SetMode(int mode)
 }
 
 void wxTarEntry::SetMode(int mode)
@@ -619,9 +695,9 @@ wxTarEntry *wxTarInputStream::GetNextEntry()
 
     entry->SetOffset(m_offset);
 
 
     entry->SetOffset(m_offset);
 
-    entry->SetDateTime(GetHeaderDate(_T("mtime")));
-    entry->SetAccessTime(GetHeaderDate(_T("atime")));
-    entry->SetCreateTime(GetHeaderDate(_T("ctime")));
+    entry->SetDateTime(GetHeaderDate(wxT("mtime")));
+    entry->SetAccessTime(GetHeaderDate(wxT("atime")));
+    entry->SetCreateTime(GetHeaderDate(wxT("ctime")));
 
     entry->SetTypeFlag(*m_hdr->Get(TAR_TYPEFLAG));
     bool isDir = entry->IsDir();
 
     entry->SetTypeFlag(*m_hdr->Get(TAR_TYPEFLAG));
     bool isDir = entry->IsDir();
@@ -717,7 +793,9 @@ wxStreamError wxTarInputStream::ReadHeaders()
     while (!done) {
         m_hdr->Read(*m_parent_i_stream);
         if (m_parent_i_stream->Eof())
     while (!done) {
         m_hdr->Read(*m_parent_i_stream);
         if (m_parent_i_stream->Eof())
+        {
             wxLogError(_("incomplete header block in tar"));
             wxLogError(_("incomplete header block in tar"));
+        }
         if (!*m_parent_i_stream)
             return wxSTREAM_READ_ERROR;
         m_offset += TAR_BLOCKSIZE;
         if (!*m_parent_i_stream)
             return wxSTREAM_READ_ERROR;
         m_offset += TAR_BLOCKSIZE;
@@ -790,7 +868,7 @@ wxString wxTarInputStream::GetHeaderPath() const
 {
     wxString path;
 
 {
     wxString path;
 
-    if ((path = GetExtendedHeader(_T("path"))) != wxEmptyString)
+    if ((path = GetExtendedHeader(wxT("path"))) != wxEmptyString)
         return path;
 
     path = wxString(m_hdr->Get(TAR_NAME), GetConv());
         return path;
 
     path = wxString(m_hdr->Get(TAR_NAME), GetConv());
@@ -798,7 +876,7 @@ wxString wxTarInputStream::GetHeaderPath() const
         return path;
 
     const char *prefix = m_hdr->Get(TAR_PREFIX);
         return path;
 
     const char *prefix = m_hdr->Get(TAR_PREFIX);
-    return *prefix ? wxString(prefix, GetConv()) + _T("/") + path : path;
+    return *prefix ? wxString(prefix, GetConv()) + wxT("/") + path : path;
 }
 
 wxDateTime wxTarInputStream::GetHeaderDate(const wxString& key) const
 }
 
 wxDateTime wxTarInputStream::GetHeaderDate(const wxString& key) const
@@ -812,7 +890,7 @@ wxDateTime wxTarInputStream::GetHeaderDate(const wxString& key) const
         return ll;
     }
 
         return ll;
     }
 
-    if (key == _T("mtime"))
+    if (key == wxT("mtime"))
         return wxLongLong(m_hdr->GetOctal(TAR_MTIME)) * 1000L;
 
     return wxDateTime();
         return wxLongLong(m_hdr->GetOctal(TAR_MTIME)) * 1000L;
 
     return wxDateTime();
@@ -824,8 +902,8 @@ wxTarNumber wxTarInputStream::GetHeaderNumber(int id) const
 
     if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) {
         wxTarNumber n = 0;
 
     if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) {
         wxTarNumber n = 0;
-        const wxChar *p = value;
-        while (*p == ' ')
+        wxString::const_iterator p = value.begin();
+        while (*p == ' ' && p != value.end())
             p++;
         while (isdigit(*p))
             n = n * 10 + (*p++ - '0');
             p++;
         while (isdigit(*p))
             n = n * 10 + (*p++ - '0');
@@ -869,13 +947,13 @@ bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs)
     size_t recPos, recSize;
     bool ok = true;
 
     size_t recPos, recSize;
     bool ok = true;
 
-    for (recPos = 0; recPos < len; recPos += recSize) {
+    for (recPos = 0; recPos < len && ok; recPos += recSize) {
         char *pRec = buf.data() + recPos;
         char *p = pRec;
 
         // read the record size (byte count in ascii decimal)
         recSize = 0;
         char *pRec = buf.data() + recPos;
         char *p = pRec;
 
         // read the record size (byte count in ascii decimal)
         recSize = 0;
-        while (isdigit(*p))
+        while (isdigit((unsigned char) *p))
             recSize = recSize * 10 + *p++ - '0';
 
         // validity checks
             recSize = recSize * 10 + *p++ - '0';
 
         // validity checks
@@ -909,7 +987,7 @@ bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs)
         if (value.empty())
             recs->erase(key);
         else
         if (value.empty())
             recs->erase(key);
         else
-            (*recs)[key] = value; 
+            (*recs)[key] = value;
     }
 
     if (!ok || recPos < len || size != lastread) {
     }
 
     if (!ok || recPos < len || size != lastread) {
@@ -958,13 +1036,15 @@ size_t wxTarInputStream::OnSysRead(void *buffer, size_t size)
 
     size_t lastread = m_parent_i_stream->Read(buffer, size).LastRead();
     m_pos += lastread;
 
     size_t lastread = m_parent_i_stream->Read(buffer, size).LastRead();
     m_pos += lastread;
-    
+
     if (m_pos >= m_size) {
         m_lasterror = wxSTREAM_EOF;
     } else if (!m_parent_i_stream->IsOk()) {
         // any other error will have been reported by the underlying stream
         if (m_parent_i_stream->Eof())
     if (m_pos >= m_size) {
         m_lasterror = wxSTREAM_EOF;
     } else if (!m_parent_i_stream->IsOk()) {
         // any other error will have been reported by the underlying stream
         if (m_parent_i_stream->Eof())
+        {
             wxLogError(_("unexpected end of file"));
             wxLogError(_("unexpected end of file"));
+        }
         m_lasterror = wxSTREAM_READ_ERROR;
     }
 
         m_lasterror = wxSTREAM_READ_ERROR;
     }
 
@@ -1009,12 +1089,12 @@ void wxTarOutputStream::Init(wxTarFormat format)
     m_extendedHdr = NULL;
     m_extendedSize = 0;
     m_lasterror = m_parent_o_stream->GetLastError();
     m_extendedHdr = NULL;
     m_extendedSize = 0;
     m_lasterror = m_parent_o_stream->GetLastError();
+    m_endrecWritten = false;
 }
 
 wxTarOutputStream::~wxTarOutputStream()
 {
 }
 
 wxTarOutputStream::~wxTarOutputStream()
 {
-    if (m_tarsize)
-        Close();
+    Close();
     delete m_hdr;
     delete m_hdr2;
     delete [] m_extendedHdr;
     delete m_hdr;
     delete m_hdr2;
     delete [] m_extendedHdr;
@@ -1047,10 +1127,10 @@ bool wxTarOutputStream::PutNextEntry(wxTarEntry *entry)
             wxTAR_LNKTYPE, wxTAR_SYMTYPE, wxTAR_CHRTYPE, wxTAR_BLKTYPE,
             wxTAR_DIRTYPE, wxTAR_FIFOTYPE, 0
         };
             wxTAR_LNKTYPE, wxTAR_SYMTYPE, wxTAR_CHRTYPE, wxTAR_BLKTYPE,
             wxTAR_DIRTYPE, wxTAR_FIFOTYPE, 0
         };
-        char typeflag = e->GetTypeFlag();
+        int typeflag = e->GetTypeFlag();
 
         // pax does now allow data for wxTAR_LNKTYPE
 
         // pax does now allow data for wxTAR_LNKTYPE
-        if (!m_pax || typeflag - wxTAR_LNKTYPE != 0)
+        if (!m_pax || typeflag != wxTAR_LNKTYPE)
             if (strchr(nodata, typeflag) != NULL)
                 CloseEntry();
     }
             if (strchr(nodata, typeflag) != NULL)
                 CloseEntry();
     }
@@ -1133,7 +1213,7 @@ bool wxTarOutputStream::CloseEntry()
 
 bool wxTarOutputStream::Close()
 {
 
 bool wxTarOutputStream::Close()
 {
-    if (!CloseEntry())
+    if (!CloseEntry() || (m_tarsize == 0 && m_endrecWritten))
         return false;
 
     memset(m_hdr, 0, sizeof(*m_hdr));
         return false;
 
     memset(m_hdr, 0, sizeof(*m_hdr));
@@ -1145,6 +1225,7 @@ bool wxTarOutputStream::Close()
     m_tarsize = 0;
     m_tarstart = wxInvalidOffset;
     m_lasterror = m_parent_o_stream->GetLastError();
     m_tarsize = 0;
     m_tarstart = wxInvalidOffset;
     m_lasterror = m_parent_o_stream->GetLastError();
+    m_endrecWritten = true;
     return IsOk();
 }
 
     return IsOk();
 }
 
@@ -1160,18 +1241,18 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
 
     if (entry.GetSize() == wxInvalidOffset)
         entry.SetSize(0);
 
     if (entry.GetSize() == wxInvalidOffset)
         entry.SetSize(0);
-    m_large = SetHeaderNumber(TAR_SIZE, entry.GetSize());
+    m_large = !SetHeaderNumber(TAR_SIZE, entry.GetSize());
 
 
-    SetHeaderDate(_T("mtime"), entry.GetDateTime());
+    SetHeaderDate(wxT("mtime"), entry.GetDateTime());
     if (entry.GetAccessTime().IsValid())
     if (entry.GetAccessTime().IsValid())
-        SetHeaderDate(_T("atime"), entry.GetAccessTime());
+        SetHeaderDate(wxT("atime"), entry.GetAccessTime());
     if (entry.GetCreateTime().IsValid())
     if (entry.GetCreateTime().IsValid())
-        SetHeaderDate(_T("ctime"), entry.GetCreateTime());
+        SetHeaderDate(wxT("ctime"), entry.GetCreateTime());
 
 
-    *m_hdr->Get(TAR_TYPEFLAG) = entry.GetTypeFlag();
+    *m_hdr->Get(TAR_TYPEFLAG) = char(entry.GetTypeFlag());
 
     strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC);
 
     strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC);
-    strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION); 
+    strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION);
 
     SetHeaderString(TAR_LINKNAME, entry.GetLinkName());
     SetHeaderString(TAR_UNAME, entry.GetUserName());
 
     SetHeaderString(TAR_LINKNAME, entry.GetLinkName());
     SetHeaderString(TAR_UNAME, entry.GetUserName());
@@ -1180,7 +1261,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
     if (~entry.GetDevMajor())
         SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor());
     if (~entry.GetDevMinor())
     if (~entry.GetDevMajor())
         SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor());
     if (~entry.GetDevMinor())
-        SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor()); 
+        SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor());
 
     m_chksum = m_hdr->Sum();
     m_hdr->SetOctal(TAR_CHKSUM, m_chksum);
 
     m_chksum = m_hdr->Sum();
     m_hdr->SetOctal(TAR_CHKSUM, m_chksum);
@@ -1201,7 +1282,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
         // an old tar that doesn't understand extended headers will
         // extract it as a file, so give these fields reasonable values
         // so that the user will have access to read and remove it.
         // an old tar that doesn't understand extended headers will
         // extract it as a file, so give these fields reasonable values
         // so that the user will have access to read and remove it.
-        m_hdr2->SetPath(PaxHeaderPath(_T("%d/PaxHeaders.%p/%f"),
+        m_hdr2->SetPath(PaxHeaderPath(wxT("%d/PaxHeaders.%p/%f"),
                                       entry.GetName(wxPATH_UNIX)), GetConv());
         m_hdr2->SetOctal(TAR_MODE, 0600);
         strcpy(m_hdr2->Get(TAR_UID), m_hdr->Get(TAR_UID));
                                       entry.GetName(wxPATH_UNIX)), GetConv());
         m_hdr2->SetOctal(TAR_MODE, 0600);
         strcpy(m_hdr2->Get(TAR_UID), m_hdr->Get(TAR_UID));
@@ -1211,7 +1292,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
         strcpy(m_hdr2->Get(TAR_MTIME), m_hdr->Get(TAR_MTIME));
         *m_hdr2->Get(TAR_TYPEFLAG) = 'x';
         strcpy(m_hdr2->Get(TAR_MAGIC), USTAR_MAGIC);
         strcpy(m_hdr2->Get(TAR_MTIME), m_hdr->Get(TAR_MTIME));
         *m_hdr2->Get(TAR_TYPEFLAG) = 'x';
         strcpy(m_hdr2->Get(TAR_MAGIC), USTAR_MAGIC);
-        strcpy(m_hdr2->Get(TAR_VERSION), USTAR_VERSION); 
+        strcpy(m_hdr2->Get(TAR_VERSION), USTAR_VERSION);
         strcpy(m_hdr2->Get(TAR_UNAME), m_hdr->Get(TAR_UNAME));
         strcpy(m_hdr2->Get(TAR_GNAME), m_hdr->Get(TAR_GNAME));
 
         strcpy(m_hdr2->Get(TAR_UNAME), m_hdr->Get(TAR_UNAME));
         strcpy(m_hdr2->Get(TAR_GNAME), m_hdr->Get(TAR_GNAME));
 
@@ -1226,6 +1307,11 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
         m_tarsize += rounded;
 
         *m_extendedHdr = 0;
         m_tarsize += rounded;
 
         *m_extendedHdr = 0;
+
+        // update m_headpos which is used to seek back to fix up the file
+        // length if it is not known in advance
+        if (m_tarstart != wxInvalidOffset)
+            m_headpos = m_tarstart + m_tarsize;
     }
 
     // if don't have extended headers just report error
     }
 
     // if don't have extended headers just report error
@@ -1235,7 +1321,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
                      m_badfit.c_str(), entry.GetName().c_str());
         m_badfit.clear();
     }
                      m_badfit.c_str(), entry.GetName().c_str());
         m_badfit.clear();
     }
-                         
+
     m_hdr->Write(*m_parent_o_stream);
     m_tarsize += TAR_BLOCKSIZE;
     m_lasterror = m_parent_o_stream->GetLastError();
     m_hdr->Write(*m_parent_o_stream);
     m_tarsize += TAR_BLOCKSIZE;
     m_lasterror = m_parent_o_stream->GetLastError();
@@ -1246,12 +1332,12 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
 wxString wxTarOutputStream::PaxHeaderPath(const wxString& format,
                                           const wxString& path)
 {
 wxString wxTarOutputStream::PaxHeaderPath(const wxString& format,
                                           const wxString& path)
 {
-    wxString d = path.BeforeLast(_T('/'));
-    wxString f = path.AfterLast(_T('/'));
+    wxString d = path.BeforeLast(wxT('/'));
+    wxString f = path.AfterLast(wxT('/'));
     wxString ret;
     wxString ret;
-    
+
     if (d.empty())
     if (d.empty())
-        d = _T(".");
+        d = wxT(".");
 
     ret.reserve(format.length() + path.length() + 16);
 
 
     ret.reserve(format.length() + path.length() + 16);
 
@@ -1263,11 +1349,11 @@ wxString wxTarOutputStream::PaxHeaderPath(const wxString& format,
         if (end == wxString::npos || end + 1 >= format.length())
             break;
         ret << format.substr(begin, end - begin);
         if (end == wxString::npos || end + 1 >= format.length())
             break;
         ret << format.substr(begin, end - begin);
-        switch (format[end + 1]) {
+        switch ( format[end + 1].GetValue() ) {
             case 'd': ret << d; break;
             case 'f': ret << f; break;
             case 'p': ret << wxGetProcessId(); break;
             case 'd': ret << d; break;
             case 'f': ret << f; break;
             case 'p': ret << wxGetProcessId(); break;
-            case '%': ret << _T("%"); break;
+            case '%': ret << wxT("%"); break;
         }
         begin = end + 2;
     }
         }
         begin = end + 2;
     }
@@ -1312,7 +1398,7 @@ bool wxTarOutputStream::ModifyHeader()
 void wxTarOutputStream::SetHeaderPath(const wxString& name)
 {
     if (!m_hdr->SetPath(name, GetConv()) || (m_pax && !name.IsAscii()))
 void wxTarOutputStream::SetHeaderPath(const wxString& name)
 {
     if (!m_hdr->SetPath(name, GetConv()) || (m_pax && !name.IsAscii()))
-        SetExtendedHeader(_T("path"), name);
+        SetExtendedHeader(wxT("path"), name);
 }
 
 bool wxTarOutputStream::SetHeaderNumber(int id, wxTarNumber n)
 }
 
 bool wxTarOutputStream::SetHeaderNumber(int id, wxTarNumber n)
@@ -1338,12 +1424,13 @@ void wxTarOutputStream::SetHeaderDate(const wxString& key,
     wxLongLong ll = datetime.IsValid() ? datetime.GetValue() : wxLongLong(0);
     wxLongLong secs = ll / 1000L;
 
     wxLongLong ll = datetime.IsValid() ? datetime.GetValue() : wxLongLong(0);
     wxLongLong secs = ll / 1000L;
 
-    if (key != _T("mtime") || !m_hdr->SetOctal(TAR_MTIME, secs.GetValue())
+    if (key != wxT("mtime")
+        || !m_hdr->SetOctal(TAR_MTIME, wxTarNumber(secs.GetValue()))
         || secs <= 0 || secs >= 0x7fffffff)
     {
         wxString str;
         if (ll >= LONG_MIN && ll <= LONG_MAX) {
         || secs <= 0 || secs >= 0x7fffffff)
     {
         wxString str;
         if (ll >= LONG_MIN && ll <= LONG_MAX) {
-            str.Printf(_T("%g"), ll.ToLong() / 1000.0);
+            str.Printf(wxT("%g"), ll.ToLong() / 1000.0);
         } else {
             str = ll.ToString();
             str.insert(str.end() - 3, '.');
         } else {
             str = ll.ToString();
             str.insert(str.end() - 3, '.');
@@ -1356,11 +1443,16 @@ void wxTarOutputStream::SetExtendedHeader(const wxString& key,
                                           const wxString& value)
 {
     if (m_pax) {
                                           const wxString& value)
 {
     if (m_pax) {
+#if wxUSE_UNICODE
+        const wxCharBuffer utf_key = key.utf8_str();
+        const wxCharBuffer utf_value = value.utf8_str();
+#else
         const wxWX2WCbuf wide_key = key.wc_str(GetConv());
         const wxCharBuffer utf_key = wxConvUTF8.cWC2MB(wide_key);
 
         const wxWX2WCbuf wide_value = value.wc_str(GetConv());
         const wxCharBuffer utf_value = wxConvUTF8.cWC2MB(wide_value);
         const wxWX2WCbuf wide_key = key.wc_str(GetConv());
         const wxCharBuffer utf_key = wxConvUTF8.cWC2MB(wide_key);
 
         const wxWX2WCbuf wide_value = value.wc_str(GetConv());
         const wxCharBuffer utf_value = wxConvUTF8.cWC2MB(wide_value);
+#endif // wxUSE_UNICODE/!wxUSE_UNICODE
 
         // a small buffer to format the length field in
         char buf[32];
 
         // a small buffer to format the length field in
         char buf[32];
@@ -1400,7 +1492,7 @@ void wxTarOutputStream::SetExtendedHeader(const wxString& key,
     else {
         // if not pax then make a list of fields to report as errors
         if (!m_badfit.empty())
     else {
         // if not pax then make a list of fields to report as errors
         if (!m_badfit.empty())
-            m_badfit += _T(", ");
+            m_badfit += wxT(", ");
         m_badfit += key;
     }
 }
         m_badfit += key;
     }
 }