/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/common/tarstrm.cpp
ViewVC logotype

Annotation of /trunk/3rdparty/wxWidgets/src/common/tarstrm.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years, 4 months ago) by william
File size: 41062 byte(s)
committing r3113 initial commit again...
1 william 31 /////////////////////////////////////////////////////////////////////////////
2     // Name: tarstrm.cpp
3     // Purpose: Streams for Tar files
4     // Author: Mike Wetherell
5     // RCS-ID: $Id: tarstrm.cpp 53248 2008-04-17 17:29:22Z MW $
6     // Copyright: (c) 2004 Mike Wetherell
7     // Licence: wxWindows licence
8     /////////////////////////////////////////////////////////////////////////////
9    
10     // For compilers that support precompilation, includes "wx.h".
11     #include "wx/wxprec.h"
12    
13     #ifdef __BORLANDC__
14     #pragma hdrstop
15     #endif
16    
17     #if wxUSE_TARSTREAM
18    
19     #include "wx/tarstrm.h"
20    
21     #ifndef WX_PRECOMP
22     #include "wx/intl.h"
23     #include "wx/log.h"
24     #include "wx/utils.h"
25     #endif
26    
27     #include "wx/buffer.h"
28     #include "wx/datetime.h"
29     #include "wx/ptr_scpd.h"
30     #include "wx/filename.h"
31     #include "wx/thread.h"
32    
33     #include <ctype.h>
34    
35     #ifdef __UNIX__
36     #include <pwd.h>
37     #include <grp.h>
38     #endif
39    
40    
41     /////////////////////////////////////////////////////////////////////////////
42     // constants
43    
44     enum {
45     TAR_NAME,
46     TAR_MODE,
47     TAR_UID,
48     TAR_GID,
49     TAR_SIZE,
50     TAR_MTIME,
51     TAR_CHKSUM,
52     TAR_TYPEFLAG,
53     TAR_LINKNAME,
54     TAR_MAGIC,
55     TAR_VERSION,
56     TAR_UNAME,
57     TAR_GNAME,
58     TAR_DEVMAJOR,
59     TAR_DEVMINOR,
60     TAR_PREFIX,
61     TAR_UNUSED,
62     TAR_NUMFIELDS
63     };
64    
65     enum {
66     TAR_BLOCKSIZE = 512
67     };
68    
69     // checksum type
70     enum {
71     SUM_UNKNOWN,
72     SUM_UNSIGNED,
73     SUM_SIGNED
74     };
75    
76     // type of input tar
77     enum {
78     TYPE_OLDTAR, // fields after TAR_LINKNAME are invalid
79     TYPE_GNUTAR, // all fields except TAR_PREFIX are valid
80     TYPE_USTAR // all fields are valid
81     };
82    
83     // signatures
84     static const char *USTAR_MAGIC = "ustar";
85     static const char *USTAR_VERSION = "00";
86     static const char *GNU_MAGIC = "ustar ";
87     static const char *GNU_VERION = " ";
88    
89     IMPLEMENT_DYNAMIC_CLASS(wxTarEntry, wxArchiveEntry)
90     IMPLEMENT_DYNAMIC_CLASS(wxTarClassFactory, wxArchiveClassFactory)
91    
92    
93     /////////////////////////////////////////////////////////////////////////////
94     // Class factory
95    
96     static wxTarClassFactory g_wxTarClassFactory;
97    
98     wxTarClassFactory::wxTarClassFactory()
99     {
100     if (this == &g_wxTarClassFactory)
101     PushFront();
102     }
103    
104     const wxChar * const *
105     wxTarClassFactory::GetProtocols(wxStreamProtocolType type) const
106     {
107     static const wxChar *protocols[] = { _T("tar"), NULL };
108     static const wxChar *mimetypes[] = { _T("application/x-tar"), NULL };
109     static const wxChar *fileexts[] = { _T(".tar"), NULL };
110     static const wxChar *empty[] = { NULL };
111    
112     switch (type) {
113     case wxSTREAM_PROTOCOL: return protocols;
114     case wxSTREAM_MIMETYPE: return mimetypes;
115     case wxSTREAM_FILEEXT: return fileexts;
116     default: return empty;
117     }
118     }
119    
120    
121     /////////////////////////////////////////////////////////////////////////////
122     // tar header block
123    
124     typedef wxFileOffset wxTarNumber;
125    
126     struct wxTarField { const wxChar *name; int pos; };
127    
128     class wxTarHeaderBlock
129     {
130     public:
131     wxTarHeaderBlock()
132     { memset(data, 0, sizeof(data)); }
133     wxTarHeaderBlock(const wxTarHeaderBlock& hb)
134     { memcpy(data, hb.data, sizeof(data)); }
135    
136     bool Read(wxInputStream& in);
137     bool Write(wxOutputStream& out);
138     inline bool WriteField(wxOutputStream& out, int id);
139    
140     bool IsAllZeros() const;
141     wxUint32 Sum(bool SignedSum = false);
142     wxUint32 SumField(int id);
143    
144     char *Get(int id) { return data + fields[id].pos + id; }
145     static size_t Len(int id) { return fields[id + 1].pos - fields[id].pos; }
146     static const wxChar *Name(int id) { return fields[id].name; }
147     static size_t Offset(int id) { return fields[id].pos; }
148    
149     bool SetOctal(int id, wxTarNumber n);
150     wxTarNumber GetOctal(int id);
151     bool SetPath(const wxString& name, wxMBConv& conv);
152    
153     private:
154     char data[TAR_BLOCKSIZE + TAR_NUMFIELDS];
155     static const wxTarField fields[];
156     static void check();
157     };
158    
159     wxDEFINE_SCOPED_PTR_TYPE(wxTarHeaderBlock)
160    
161     // A table giving the field names and offsets in a tar header block
162     const wxTarField wxTarHeaderBlock::fields[] =
163     {
164     { _T("name"), 0 }, // 100
165     { _T("mode"), 100 }, // 8
166     { _T("uid"), 108 }, // 8
167     { _T("gid"), 116 }, // 8
168     { _T("size"), 124 }, // 12
169     { _T("mtime"), 136 }, // 12
170     { _T("chksum"), 148 }, // 8
171     { _T("typeflag"), 156 }, // 1
172     { _T("linkname"), 157 }, // 100
173     { _T("magic"), 257 }, // 6
174     { _T("version"), 263 }, // 2
175     { _T("uname"), 265 }, // 32
176     { _T("gname"), 297 }, // 32
177     { _T("devmajor"), 329 }, // 8
178     { _T("devminor"), 337 }, // 8
179     { _T("prefix"), 345 }, // 155
180     { _T("unused"), 500 }, // 12
181     { NULL, TAR_BLOCKSIZE }
182     };
183    
184     void wxTarHeaderBlock::check()
185     {
186     #if 0
187     wxCOMPILE_TIME_ASSERT(
188     WXSIZEOF(fields) == TAR_NUMFIELDS + 1,
189     Wrong_number_of_elements_in_fields_table
190     );
191     #endif
192     }
193    
194     bool wxTarHeaderBlock::IsAllZeros() const
195     {
196     const char *p = data;
197     for (size_t i = 0; i < sizeof(data); i++)
198     if (p[i])
199     return false;
200     return true;
201     }
202    
203     wxUint32 wxTarHeaderBlock::Sum(bool SignedSum /*=false*/)
204     {
205     // the chksum field itself should be blanks during the calculation
206     memset(Get(TAR_CHKSUM), ' ', Len(TAR_CHKSUM));
207     const char *p = data;
208     wxUint32 n = 0;
209    
210     if (SignedSum)
211     for (size_t i = 0; i < sizeof(data); i++)
212     n += (signed char)p[i];
213     else
214     for (size_t i = 0; i < sizeof(data); i++)
215     n += (unsigned char)p[i];
216    
217     return n;
218     }
219    
220     wxUint32 wxTarHeaderBlock::SumField(int id)
221     {
222     unsigned char *p = (unsigned char*)Get(id);
223     unsigned char *q = p + Len(id);
224     wxUint32 n = 0;
225    
226     while (p < q)
227     n += *p++;
228    
229     return n;
230     }
231    
232     bool wxTarHeaderBlock::Read(wxInputStream& in)
233     {
234     bool ok = true;
235    
236     for (int id = 0; id < TAR_NUMFIELDS && ok; id++)
237     ok = in.Read(Get(id), Len(id)).LastRead() == Len(id);
238    
239     return ok;
240     }
241    
242     bool wxTarHeaderBlock::Write(wxOutputStream& out)
243     {
244     bool ok = true;
245    
246     for (int id = 0; id < TAR_NUMFIELDS && ok; id++)
247     ok = WriteField(out, id);
248    
249     return ok;
250     }
251    
252     inline bool wxTarHeaderBlock::WriteField(wxOutputStream& out, int id)
253     {
254     return out.Write(Get(id), Len(id)).LastWrite() == Len(id);
255     }
256    
257     wxTarNumber wxTarHeaderBlock::GetOctal(int id)
258     {
259     wxTarNumber n = 0;
260     const char *p = Get(id);
261     while (*p == ' ')
262     p++;
263     while (*p >= '0' && *p < '8')
264     n = (n << 3) | (*p++ - '0');
265     return n;
266     }
267    
268     bool wxTarHeaderBlock::SetOctal(int id, wxTarNumber n)
269     {
270     // set an octal field, return true if the number fits
271     char *field = Get(id);
272     char *p = field + Len(id);
273     *--p = 0;
274     while (p > field) {
275     *--p = char('0' + (n & 7));
276     n >>= 3;
277     }
278     return n == 0;
279     }
280    
281     bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv)
282     {
283     bool badconv = false;
284    
285     #if wxUSE_UNICODE
286     wxCharBuffer nameBuf = name.mb_str(conv);
287    
288     // if the conversion fails make an approximation
289     if (!nameBuf) {
290     badconv = true;
291     size_t len = name.length();
292     wxCharBuffer approx(len);
293     for (size_t i = 0; i < len; i++)
294     approx.data()[i] = name[i] & ~0x7F ? '_' : name[i];
295     nameBuf = approx;
296     }
297    
298     const char *mbName = nameBuf;
299     #else
300     const char *mbName = name.c_str();
301     (void)conv;
302     #endif
303    
304     bool fits;
305     bool notGoingToFit = false;
306     size_t len = strlen(mbName);
307     size_t maxname = Len(TAR_NAME);
308     size_t maxprefix = Len(TAR_PREFIX);
309     size_t i = 0;
310     size_t nexti = 0;
311    
312     for (;;) {
313     fits = i < maxprefix && len - i <= maxname;
314    
315     if (!fits) {
316     const char *p = strchr(mbName + i, '/');
317     if (p)
318     nexti = p - mbName + 1;
319     if (!p || nexti - 1 > maxprefix)
320     notGoingToFit = true;
321     }
322    
323     if (fits || notGoingToFit) {
324     strncpy(Get(TAR_NAME), mbName + i, maxname);
325     if (i > 0)
326     strncpy(Get(TAR_PREFIX), mbName, i - 1);
327     break;
328     }
329    
330     i = nexti;
331     }
332    
333     return fits && !badconv;
334     }
335    
336    
337     /////////////////////////////////////////////////////////////////////////////
338     // Some helpers
339    
340     static wxFileOffset RoundUpSize(wxFileOffset size, int factor = 1)
341     {
342     wxFileOffset chunk = TAR_BLOCKSIZE * factor;
343     return ((size + chunk - 1) / chunk) * chunk;
344     }
345    
346     #ifdef __UNIX__
347    
348     static wxString wxTarUserName(int uid)
349     {
350     struct passwd *ppw;
351    
352     #ifdef HAVE_GETPWUID_R
353     #if defined HAVE_SYSCONF && defined _SC_GETPW_R_SIZE_MAX
354     long pwsize = sysconf(_SC_GETPW_R_SIZE_MAX);
355     size_t bufsize(wxMin(wxMax(1024l, pwsize), 32768l));
356     #else
357     size_t bufsize = 1024;
358     #endif
359     wxCharBuffer buf(bufsize);
360     struct passwd pw;
361    
362     memset(&pw, 0, sizeof(pw));
363     if (getpwuid_r(uid, &pw, buf.data(), bufsize, &ppw) == 0 && pw.pw_name)
364     return wxString(pw.pw_name, wxConvLibc);
365     #else
366     if ((ppw = getpwuid(uid)) != NULL)
367     return wxString(ppw->pw_name, wxConvLibc);
368     #endif
369     return _("unknown");
370     }
371    
372     static wxString wxTarGroupName(int gid)
373     {
374     struct group *pgr;
375     #ifdef HAVE_GETGRGID_R
376     #if defined HAVE_SYSCONF && defined _SC_GETGR_R_SIZE_MAX
377     long grsize = sysconf(_SC_GETGR_R_SIZE_MAX);
378     size_t bufsize(wxMin(wxMax(1024l, grsize), 32768l));
379     #else
380     size_t bufsize = 1024;
381     #endif
382     wxCharBuffer buf(bufsize);
383     struct group gr;
384    
385     memset(&gr, 0, sizeof(gr));
386     if (getgrgid_r(gid, &gr, buf.data(), bufsize, &pgr) == 0 && gr.gr_name)
387     return wxString(gr.gr_name, wxConvLibc);
388     #else
389     if ((pgr = getgrgid(gid)) != NULL)
390     return wxString(pgr->gr_name, wxConvLibc);
391     #endif
392     return _("unknown");
393     }
394    
395     #endif // __UNIX__
396    
397     // Cache the user and group names since getting them can be expensive,
398     // get both names and ids at the same time.
399     //
400     struct wxTarUser
401     {
402     wxTarUser();
403     ~wxTarUser() { delete [] uname; delete [] gname; }
404    
405     int uid;
406     int gid;
407    
408     wxChar *uname;
409     wxChar *gname;
410     };
411    
412     wxTarUser::wxTarUser()
413     {
414     #ifdef __UNIX__
415     uid = getuid();
416     gid = getgid();
417     wxString usr = wxTarUserName(uid);
418     wxString grp = wxTarGroupName(gid);
419     #else
420     uid = 0;
421     gid = 0;
422     wxString usr = wxGetUserId();
423     wxString grp = _("unknown");
424     #endif
425    
426     uname = new wxChar[usr.length() + 1];
427     wxStrcpy(uname, usr.c_str());
428    
429     gname = new wxChar[grp.length() + 1];
430     wxStrcpy(gname, grp.c_str());
431     }
432    
433     static const wxTarUser& wxGetTarUser()
434     {
435     #if wxUSE_THREADS
436     static wxCriticalSection cs;
437     wxCriticalSectionLocker lock(cs);
438     #endif
439     static wxTarUser tu;
440     return tu;
441     }
442    
443     // ignore the size field for entry types 3, 4, 5 and 6
444     //
445     static inline wxFileOffset GetDataSize(const wxTarEntry& entry)
446     {
447     switch (entry.GetTypeFlag()) {
448     case wxTAR_CHRTYPE:
449     case wxTAR_BLKTYPE:
450     case wxTAR_DIRTYPE:
451     case wxTAR_FIFOTYPE:
452     return 0;
453     default:
454     return entry.GetSize();
455     }
456     }
457    
458    
459     /////////////////////////////////////////////////////////////////////////////
460     // Tar Entry
461     // Holds all the meta-data for a file in the tar
462    
463     wxTarEntry::wxTarEntry(const wxString& name /*=wxEmptyString*/,
464     const wxDateTime& dt /*=wxDateTime::Now()*/,
465     wxFileOffset size /*=0*/)
466     : m_Mode(0644),
467     m_IsModeSet(false),
468     m_UserId(wxGetTarUser().uid),
469     m_GroupId(wxGetTarUser().gid),
470     m_Size(size),
471     m_Offset(wxInvalidOffset),
472     m_ModifyTime(dt),
473     m_TypeFlag(wxTAR_REGTYPE),
474     m_UserName(wxGetTarUser().uname),
475     m_GroupName(wxGetTarUser().gname),
476     m_DevMajor(~0),
477     m_DevMinor(~0)
478     {
479     if (!name.empty())
480     SetName(name);
481     }
482    
483     wxTarEntry::~wxTarEntry()
484     {
485     }
486    
487     wxTarEntry::wxTarEntry(const wxTarEntry& e)
488     : wxArchiveEntry(),
489     m_Name(e.m_Name),
490     m_Mode(e.m_Mode),
491     m_IsModeSet(e.m_IsModeSet),
492     m_UserId(e.m_UserId),
493     m_GroupId(e.m_GroupId),
494     m_Size(e.m_Size),
495     m_Offset(e.m_Offset),
496     m_ModifyTime(e.m_ModifyTime),
497     m_AccessTime(e.m_AccessTime),
498     m_CreateTime(e.m_CreateTime),
499     m_TypeFlag(e.m_TypeFlag),
500     m_LinkName(e.m_LinkName),
501     m_UserName(e.m_UserName),
502     m_GroupName(e.m_GroupName),
503     m_DevMajor(e.m_DevMajor),
504     m_DevMinor(e.m_DevMinor)
505     {
506     }
507    
508     wxTarEntry& wxTarEntry::operator=(const wxTarEntry& e)
509     {
510     if (&e != this) {
511     m_Name = e.m_Name;
512     m_Mode = e.m_Mode;
513     m_IsModeSet = e.m_IsModeSet;
514     m_UserId = e.m_UserId;
515     m_GroupId = e.m_GroupId;
516     m_Size = e.m_Size;
517     m_Offset = e.m_Offset;
518     m_ModifyTime = e.m_ModifyTime;
519     m_AccessTime = e.m_AccessTime;
520     m_CreateTime = e.m_CreateTime;
521     m_TypeFlag = e.m_TypeFlag;
522     m_LinkName = e.m_LinkName;
523     m_UserName = e.m_UserName;
524     m_GroupName = e.m_GroupName;
525     m_DevMajor = e.m_DevMajor;
526     m_DevMinor = e.m_DevMinor;
527     }
528     return *this;
529     }
530    
531     wxString wxTarEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const
532     {
533     bool isDir = IsDir() && !m_Name.empty();
534    
535     // optimisations for common (and easy) cases
536     switch (wxFileName::GetFormat(format)) {
537     case wxPATH_DOS:
538     {
539     wxString name(isDir ? m_Name + _T("\\") : m_Name);
540     for (size_t i = 0; i < name.length(); i++)
541     if (name[i] == _T('/'))
542     name[i] = _T('\\');
543     return name;
544     }
545    
546     case wxPATH_UNIX:
547     return isDir ? m_Name + _T("/") : m_Name;
548    
549     default:
550     ;
551     }
552    
553     wxFileName fn;
554    
555     if (isDir)
556     fn.AssignDir(m_Name, wxPATH_UNIX);
557     else
558     fn.Assign(m_Name, wxPATH_UNIX);
559    
560     return fn.GetFullPath(format);
561     }
562    
563     void wxTarEntry::SetName(const wxString& name, wxPathFormat format)
564     {
565     bool isDir;
566     m_Name = GetInternalName(name, format, &isDir);
567     SetIsDir(isDir);
568     }
569    
570     // Static - Internally tars and zips use forward slashes for the path
571     // separator, absolute paths aren't allowed, and directory names have a
572     // trailing slash. This function converts a path into this internal format,
573     // but without a trailing slash for a directory.
574     //
575     wxString wxTarEntry::GetInternalName(const wxString& name,
576     wxPathFormat format /*=wxPATH_NATIVE*/,
577     bool *pIsDir /*=NULL*/)
578     {
579     wxString internal;
580    
581     if (wxFileName::GetFormat(format) != wxPATH_UNIX)
582     internal = wxFileName(name, format).GetFullPath(wxPATH_UNIX);
583     else
584     internal = name;
585    
586     bool isDir = !internal.empty() && internal.Last() == '/';
587     if (pIsDir)
588     *pIsDir = isDir;
589     if (isDir)
590     internal.erase(internal.length() - 1);
591    
592     while (!internal.empty() && *internal.begin() == '/')
593     internal.erase(0, 1);
594     while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0)
595     internal.erase(0, 2);
596     if (internal == _T(".") || internal == _T(".."))
597     internal = wxEmptyString;
598    
599     return internal;
600     }
601    
602     bool wxTarEntry::IsDir() const
603     {
604     return m_TypeFlag == wxTAR_DIRTYPE;
605     }
606    
607     void wxTarEntry::SetIsDir(bool isDir)
608     {
609     if (isDir)
610     m_TypeFlag = wxTAR_DIRTYPE;
611     else if (m_TypeFlag == wxTAR_DIRTYPE)
612     m_TypeFlag = wxTAR_REGTYPE;
613     }
614    
615     void wxTarEntry::SetIsReadOnly(bool isReadOnly)
616     {
617     if (isReadOnly)
618     m_Mode &= ~0222;
619     else
620     m_Mode |= 0200;
621     }
622    
623     int wxTarEntry::GetMode() const
624     {
625     if (m_IsModeSet || !IsDir())
626     return m_Mode;
627     else
628     return m_Mode | 0111;
629    
630     }
631    
632     void wxTarEntry::SetMode(int mode)
633     {
634     m_Mode = mode & 07777;
635     m_IsModeSet = true;
636     }
637    
638    
639     /////////////////////////////////////////////////////////////////////////////
640     // Input stream
641    
642     wxDECLARE_SCOPED_PTR(wxTarEntry, wxTarEntryPtr_)
643     wxDEFINE_SCOPED_PTR (wxTarEntry, wxTarEntryPtr_)
644    
645     wxTarInputStream::wxTarInputStream(wxInputStream& stream,
646     wxMBConv& conv /*=wxConvLocal*/)
647     : wxArchiveInputStream(stream, conv)
648     {
649     Init();
650     }
651    
652     wxTarInputStream::wxTarInputStream(wxInputStream *stream,
653     wxMBConv& conv /*=wxConvLocal*/)
654     : wxArchiveInputStream(stream, conv)
655     {
656     Init();
657     }
658    
659     void wxTarInputStream::Init()
660     {
661     m_pos = wxInvalidOffset;
662     m_offset = 0;
663     m_size = wxInvalidOffset;
664     m_sumType = SUM_UNKNOWN;
665     m_tarType = TYPE_USTAR;
666     m_hdr = new wxTarHeaderBlock;
667     m_HeaderRecs = NULL;
668     m_GlobalHeaderRecs = NULL;
669     m_lasterror = m_parent_i_stream->GetLastError();
670     }
671    
672     wxTarInputStream::~wxTarInputStream()
673     {
674     delete m_hdr;
675     delete m_HeaderRecs;
676     delete m_GlobalHeaderRecs;
677     }
678    
679     wxTarEntry *wxTarInputStream::GetNextEntry()
680     {
681     m_lasterror = ReadHeaders();
682    
683     if (!IsOk())
684     return NULL;
685    
686     wxTarEntryPtr_ entry(new wxTarEntry);
687    
688     entry->SetMode(GetHeaderNumber(TAR_MODE));
689     entry->SetUserId(GetHeaderNumber(TAR_UID));
690     entry->SetGroupId(GetHeaderNumber(TAR_UID));
691     entry->SetSize(GetHeaderNumber(TAR_SIZE));
692    
693     entry->SetOffset(m_offset);
694    
695     entry->SetDateTime(GetHeaderDate(_T("mtime")));
696     entry->SetAccessTime(GetHeaderDate(_T("atime")));
697     entry->SetCreateTime(GetHeaderDate(_T("ctime")));
698    
699     entry->SetTypeFlag(*m_hdr->Get(TAR_TYPEFLAG));
700     bool isDir = entry->IsDir();
701    
702     entry->SetLinkName(GetHeaderString(TAR_LINKNAME));
703    
704     if (m_tarType != TYPE_OLDTAR) {
705     entry->SetUserName(GetHeaderString(TAR_UNAME));
706     entry->SetGroupName(GetHeaderString(TAR_GNAME));
707    
708     entry->SetDevMajor(GetHeaderNumber(TAR_DEVMAJOR));
709     entry->SetDevMinor(GetHeaderNumber(TAR_DEVMINOR));
710     }
711    
712     entry->SetName(GetHeaderPath(), wxPATH_UNIX);
713     if (isDir)
714     entry->SetIsDir();
715    
716     if (m_HeaderRecs)
717     m_HeaderRecs->clear();
718    
719     m_size = GetDataSize(*entry);
720     m_pos = 0;
721    
722     return entry.release();
723     }
724    
725     bool wxTarInputStream::OpenEntry(wxTarEntry& entry)
726     {
727     wxFileOffset offset = entry.GetOffset();
728    
729     if (GetLastError() != wxSTREAM_READ_ERROR
730     && m_parent_i_stream->IsSeekable()
731     && m_parent_i_stream->SeekI(offset) == offset)
732     {
733     m_offset = offset;
734     m_size = GetDataSize(entry);
735     m_pos = 0;
736     m_lasterror = wxSTREAM_NO_ERROR;
737     return true;
738     } else {
739     m_lasterror = wxSTREAM_READ_ERROR;
740     return false;
741     }
742     }
743    
744     bool wxTarInputStream::OpenEntry(wxArchiveEntry& entry)
745     {
746     wxTarEntry *tarEntry = wxStaticCast(&entry, wxTarEntry);
747     return tarEntry ? OpenEntry(*tarEntry) : false;
748     }
749    
750     bool wxTarInputStream::CloseEntry()
751     {
752     if (m_lasterror == wxSTREAM_READ_ERROR)
753     return false;
754     if (!IsOpened())
755     return true;
756    
757     wxFileOffset size = RoundUpSize(m_size);
758     wxFileOffset remainder = size - m_pos;
759    
760     if (remainder && m_parent_i_stream->IsSeekable()) {
761     wxLogNull nolog;
762     if (m_parent_i_stream->SeekI(remainder, wxFromCurrent)
763     != wxInvalidOffset)
764     remainder = 0;
765     }
766    
767     if (remainder) {
768     const int BUFSIZE = 8192;
769     wxCharBuffer buf(BUFSIZE);
770    
771     while (remainder > 0 && m_parent_i_stream->IsOk())
772     remainder -= m_parent_i_stream->Read(
773     buf.data(), wxMin(BUFSIZE, remainder)).LastRead();
774     }
775    
776     m_pos = wxInvalidOffset;
777     m_offset += size;
778     m_lasterror = m_parent_i_stream->GetLastError();
779    
780     return IsOk();
781     }
782    
783     wxStreamError wxTarInputStream::ReadHeaders()
784     {
785     if (!CloseEntry())
786     return wxSTREAM_READ_ERROR;
787    
788     bool done = false;
789    
790     while (!done) {
791     m_hdr->Read(*m_parent_i_stream);
792     if (m_parent_i_stream->Eof())
793     wxLogError(_("incomplete header block in tar"));
794     if (!*m_parent_i_stream)
795     return wxSTREAM_READ_ERROR;
796     m_offset += TAR_BLOCKSIZE;
797    
798     // an all-zero header marks the end of the tar
799     if (m_hdr->IsAllZeros())
800     return wxSTREAM_EOF;
801    
802     // the checksum is supposed to be the unsigned sum of the header bytes,
803     // but there have been versions of tar that used the signed sum, so
804     // accept that too, but only if used throughout.
805     wxUint32 chksum = m_hdr->GetOctal(TAR_CHKSUM);
806     bool ok = false;
807    
808     if (m_sumType != SUM_SIGNED) {
809     ok = chksum == m_hdr->Sum();
810     if (m_sumType == SUM_UNKNOWN)
811     m_sumType = ok ? SUM_UNSIGNED : SUM_SIGNED;
812     }
813     if (m_sumType == SUM_SIGNED)
814     ok = chksum == m_hdr->Sum(true);
815     if (!ok) {
816     wxLogError(_("checksum failure reading tar header block"));
817     return wxSTREAM_READ_ERROR;
818     }
819    
820     if (strcmp(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC) == 0)
821     m_tarType = TYPE_USTAR;
822     else if (strcmp(m_hdr->Get(TAR_MAGIC), GNU_MAGIC) == 0 &&
823     strcmp(m_hdr->Get(TAR_VERSION), GNU_VERION) == 0)
824     m_tarType = TYPE_GNUTAR;
825     else
826     m_tarType = TYPE_OLDTAR;
827    
828     if (m_tarType != TYPE_USTAR)
829     break;
830    
831     switch (*m_hdr->Get(TAR_TYPEFLAG)) {
832     case 'g': ReadExtendedHeader(m_GlobalHeaderRecs); break;
833     case 'x': ReadExtendedHeader(m_HeaderRecs); break;
834     default: done = true;
835     }
836     }
837    
838     return wxSTREAM_NO_ERROR;
839     }
840    
841     wxString wxTarInputStream::GetExtendedHeader(const wxString& key) const
842     {
843     wxTarHeaderRecords::iterator it;
844    
845     // look at normal extended header records first
846     if (m_HeaderRecs) {
847     it = m_HeaderRecs->find(key);
848     if (it != m_HeaderRecs->end())
849     return wxString(it->second.wc_str(wxConvUTF8), GetConv());
850     }
851    
852     // if not found, look at the global header records
853     if (m_GlobalHeaderRecs) {
854     it = m_GlobalHeaderRecs->find(key);
855     if (it != m_GlobalHeaderRecs->end())
856     return wxString(it->second.wc_str(wxConvUTF8), GetConv());
857     }
858    
859     return wxEmptyString;
860     }
861    
862     wxString wxTarInputStream::GetHeaderPath() const
863     {
864     wxString path;
865    
866     if ((path = GetExtendedHeader(_T("path"))) != wxEmptyString)
867     return path;
868    
869     path = wxString(m_hdr->Get(TAR_NAME), GetConv());
870     if (m_tarType != TYPE_USTAR)
871     return path;
872    
873     const char *prefix = m_hdr->Get(TAR_PREFIX);
874     return *prefix ? wxString(prefix, GetConv()) + _T("/") + path : path;
875     }
876    
877     wxDateTime wxTarInputStream::GetHeaderDate(const wxString& key) const
878     {
879     wxString value;
880    
881     // try extended header, stored as decimal seconds since the epoch
882     if ((value = GetExtendedHeader(key)) != wxEmptyString) {
883     wxLongLong ll;
884     ll.Assign(wxAtof(value) * 1000.0);
885     return ll;
886     }
887    
888     if (key == _T("mtime"))
889     return wxLongLong(m_hdr->GetOctal(TAR_MTIME)) * 1000L;
890    
891     return wxDateTime();
892     }
893    
894     wxTarNumber wxTarInputStream::GetHeaderNumber(int id) const
895     {
896     wxString value;
897    
898     if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) {
899     wxTarNumber n = 0;
900     const wxChar *p = value;
901     while (*p == ' ')
902     p++;
903     while (isdigit(*p))
904     n = n * 10 + (*p++ - '0');
905     return n;
906     } else {
907     return m_hdr->GetOctal(id);
908     }
909     }
910    
911     wxString wxTarInputStream::GetHeaderString(int id) const
912     {
913     wxString value;
914    
915     if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString)
916     return value;
917    
918     return wxString(m_hdr->Get(id), GetConv());
919     }
920    
921     // An extended header consists of one or more records, each constructed:
922     // "%d %s=%s\n", <length>, <keyword>, <value>
923     // <length> is the byte length, <keyword> and <value> are UTF-8
924    
925     bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs)
926     {
927     if (!recs)
928     recs = new wxTarHeaderRecords;
929    
930     // round length up to a whole number of blocks
931     size_t len = m_hdr->GetOctal(TAR_SIZE);
932     size_t size = RoundUpSize(len);
933    
934     // read in the whole header since it should be small
935     wxCharBuffer buf(size);
936     size_t lastread = m_parent_i_stream->Read(buf.data(), size).LastRead();
937     if (lastread < len)
938     len = lastread;
939     buf.data()[len] = 0;
940     m_offset += lastread;
941    
942     size_t recPos, recSize;
943     bool ok = true;
944    
945     for (recPos = 0; recPos < len; recPos += recSize) {
946     char *pRec = buf.data() + recPos;
947     char *p = pRec;
948    
949     // read the record size (byte count in ascii decimal)
950     recSize = 0;
951     while (isdigit((unsigned char) *p))
952     recSize = recSize * 10 + *p++ - '0';
953    
954     // validity checks
955     if (recPos + recSize > len)
956     break;
957     if (recSize < p - pRec + (size_t)3 || *p != ' '
958     || pRec[recSize - 1] != '\012') {
959     ok = false;
960     continue;
961     }
962    
963     // replace the final '\n' with a nul, to terminate value
964     pRec[recSize - 1] = 0;
965     // the key is here, following the space
966     char *pKey = ++p;
967    
968     // look forward for the '=', the value follows
969     while (*p && *p != '=')
970     p++;
971     if (!*p) {
972     ok = false;
973     continue;
974     }
975     // replace the '=' with a nul, to terminate the key
976     *p++ = 0;
977    
978     wxString key(wxConvUTF8.cMB2WC(pKey), GetConv());
979     wxString value(wxConvUTF8.cMB2WC(p), GetConv());
980    
981     // an empty value unsets a previously given value
982     if (value.empty())
983     recs->erase(key);
984     else
985     (*recs)[key] = value;
986     }
987    
988     if (!ok || recPos < len || size != lastread) {
989     wxLogWarning(_("invalid data in extended tar header"));
990     return false;
991     }
992    
993     return true;
994     }
995    
996     wxFileOffset wxTarInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
997     {
998     if (!IsOpened()) {
999     wxLogError(_("tar entry not open"));
1000     m_lasterror = wxSTREAM_READ_ERROR;
1001     }
1002     if (!IsOk())
1003     return wxInvalidOffset;
1004    
1005     switch (mode) {
1006     case wxFromStart: break;
1007     case wxFromCurrent: pos += m_pos; break;
1008     case wxFromEnd: pos += m_size; break;
1009     }
1010    
1011     if (pos < 0 || m_parent_i_stream->SeekI(m_offset + pos) == wxInvalidOffset)
1012     return wxInvalidOffset;
1013    
1014     m_pos = pos;
1015     return m_pos;
1016     }
1017    
1018     size_t wxTarInputStream::OnSysRead(void *buffer, size_t size)
1019     {
1020     if (!IsOpened()) {
1021     wxLogError(_("tar entry not open"));
1022     m_lasterror = wxSTREAM_READ_ERROR;
1023     }
1024     if (!IsOk() || !size)
1025     return 0;
1026    
1027     if (m_pos >= m_size)
1028     size = 0;
1029     else if (m_pos + size > m_size + (size_t)0)
1030     size = m_size - m_pos;
1031    
1032     size_t lastread = m_parent_i_stream->Read(buffer, size).LastRead();
1033     m_pos += lastread;
1034    
1035     if (m_pos >= m_size) {
1036     m_lasterror = wxSTREAM_EOF;
1037     } else if (!m_parent_i_stream->IsOk()) {
1038     // any other error will have been reported by the underlying stream
1039     if (m_parent_i_stream->Eof())
1040     wxLogError(_("unexpected end of file"));
1041     m_lasterror = wxSTREAM_READ_ERROR;
1042     }
1043    
1044     return lastread;
1045     }
1046    
1047    
1048     /////////////////////////////////////////////////////////////////////////////
1049     // Output stream
1050    
1051     wxTarOutputStream::wxTarOutputStream(wxOutputStream& stream,
1052     wxTarFormat format /*=wxTAR_PAX*/,
1053     wxMBConv& conv /*=wxConvLocal*/)
1054     : wxArchiveOutputStream(stream, conv)
1055     {
1056     Init(format);
1057     }
1058    
1059     wxTarOutputStream::wxTarOutputStream(wxOutputStream *stream,
1060     wxTarFormat format /*=wxTAR_PAX*/,
1061     wxMBConv& conv /*=wxConvLocal*/)
1062     : wxArchiveOutputStream(stream, conv)
1063     {
1064     Init(format);
1065     }
1066    
1067     void wxTarOutputStream::Init(wxTarFormat format)
1068     {
1069     m_pos = wxInvalidOffset;
1070     m_maxpos = wxInvalidOffset;
1071     m_size = wxInvalidOffset;
1072     m_headpos = wxInvalidOffset;
1073     m_datapos = wxInvalidOffset;
1074     m_tarstart = wxInvalidOffset;
1075     m_tarsize = 0;
1076     m_pax = format == wxTAR_PAX;
1077     m_BlockingFactor = m_pax ? 10 : 20;
1078     m_chksum = 0;
1079     m_large = false;
1080     m_hdr = new wxTarHeaderBlock;
1081     m_hdr2 = NULL;
1082     m_extendedHdr = NULL;
1083     m_extendedSize = 0;
1084     m_lasterror = m_parent_o_stream->GetLastError();
1085     }
1086    
1087     wxTarOutputStream::~wxTarOutputStream()
1088     {
1089     if (m_tarsize)
1090     Close();
1091     delete m_hdr;
1092     delete m_hdr2;
1093     delete [] m_extendedHdr;
1094     }
1095    
1096     bool wxTarOutputStream::PutNextEntry(wxTarEntry *entry)
1097     {
1098     wxTarEntryPtr_ e(entry);
1099    
1100     if (!CloseEntry())
1101     return false;
1102    
1103     if (!m_tarsize) {
1104     wxLogNull nolog;
1105     m_tarstart = m_parent_o_stream->TellO();
1106     }
1107    
1108     if (m_tarstart != wxInvalidOffset)
1109     m_headpos = m_tarstart + m_tarsize;
1110    
1111     if (WriteHeaders(*e)) {
1112     m_pos = 0;
1113     m_maxpos = 0;
1114     m_size = GetDataSize(*e);
1115     if (m_tarstart != wxInvalidOffset)
1116     m_datapos = m_tarstart + m_tarsize;
1117    
1118     // types that are not allowd any data
1119     const char nodata[] = {
1120     wxTAR_LNKTYPE, wxTAR_SYMTYPE, wxTAR_CHRTYPE, wxTAR_BLKTYPE,
1121     wxTAR_DIRTYPE, wxTAR_FIFOTYPE, 0
1122     };
1123     int typeflag = e->GetTypeFlag();
1124    
1125     // pax does now allow data for wxTAR_LNKTYPE
1126     if (!m_pax || typeflag != wxTAR_LNKTYPE)
1127     if (strchr(nodata, typeflag) != NULL)
1128     CloseEntry();
1129     }
1130    
1131     return IsOk();
1132     }
1133    
1134     bool wxTarOutputStream::PutNextEntry(const wxString& name,
1135     const wxDateTime& dt,
1136     wxFileOffset size)
1137     {
1138     return PutNextEntry(new wxTarEntry(name, dt, size));
1139     }
1140    
1141     bool wxTarOutputStream::PutNextDirEntry(const wxString& name,
1142     const wxDateTime& dt)
1143     {
1144     wxTarEntry *entry = new wxTarEntry(name, dt);
1145     entry->SetIsDir();
1146     return PutNextEntry(entry);
1147     }
1148    
1149     bool wxTarOutputStream::PutNextEntry(wxArchiveEntry *entry)
1150     {
1151     wxTarEntry *tarEntry = wxStaticCast(entry, wxTarEntry);
1152     if (!tarEntry)
1153     delete entry;
1154     return PutNextEntry(tarEntry);
1155     }
1156    
1157     bool wxTarOutputStream::CopyEntry(wxTarEntry *entry,
1158     wxTarInputStream& inputStream)
1159     {
1160     if (PutNextEntry(entry))
1161     Write(inputStream);
1162     return IsOk() && inputStream.Eof();
1163     }
1164    
1165     bool wxTarOutputStream::CopyEntry(wxArchiveEntry *entry,
1166     wxArchiveInputStream& inputStream)
1167     {
1168     if (PutNextEntry(entry))
1169     Write(inputStream);
1170     return IsOk() && inputStream.Eof();
1171     }
1172    
1173     bool wxTarOutputStream::CloseEntry()
1174     {
1175     if (!IsOpened())
1176     return true;
1177    
1178     if (m_pos < m_maxpos) {
1179     wxASSERT(m_parent_o_stream->IsSeekable());
1180     m_parent_o_stream->SeekO(m_datapos + m_maxpos);
1181     m_lasterror = m_parent_o_stream->GetLastError();
1182     m_pos = m_maxpos;
1183     }
1184    
1185     if (IsOk()) {
1186     wxFileOffset size = RoundUpSize(m_pos);
1187     if (size > m_pos) {
1188     memset(m_hdr, 0, size - m_pos);
1189     m_parent_o_stream->Write(m_hdr, size - m_pos);
1190     m_lasterror = m_parent_o_stream->GetLastError();
1191     }
1192     m_tarsize += size;
1193     }
1194    
1195     if (IsOk() && m_pos != m_size)
1196     ModifyHeader();
1197    
1198     m_pos = wxInvalidOffset;
1199     m_maxpos = wxInvalidOffset;
1200     m_size = wxInvalidOffset;
1201     m_headpos = wxInvalidOffset;
1202     m_datapos = wxInvalidOffset;
1203    
1204     return IsOk();
1205     }
1206    
1207     bool wxTarOutputStream::Close()
1208     {
1209     if (!CloseEntry())
1210     return false;
1211    
1212     memset(m_hdr, 0, sizeof(*m_hdr));
1213     int count = (RoundUpSize(m_tarsize + 2 * TAR_BLOCKSIZE, m_BlockingFactor)
1214     - m_tarsize) / TAR_BLOCKSIZE;
1215     while (count--)
1216     m_parent_o_stream->Write(m_hdr, TAR_BLOCKSIZE);
1217    
1218     m_tarsize = 0;
1219     m_tarstart = wxInvalidOffset;
1220     m_lasterror = m_parent_o_stream->GetLastError();
1221     return IsOk();
1222     }
1223    
1224     bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
1225     {
1226     memset(m_hdr, 0, sizeof(*m_hdr));
1227    
1228     SetHeaderPath(entry.GetName(wxPATH_UNIX));
1229    
1230     SetHeaderNumber(TAR_MODE, entry.GetMode());
1231     SetHeaderNumber(TAR_UID, entry.GetUserId());
1232     SetHeaderNumber(TAR_GID, entry.GetGroupId());
1233    
1234     if (entry.GetSize() == wxInvalidOffset)
1235     entry.SetSize(0);
1236     m_large = !SetHeaderNumber(TAR_SIZE, entry.GetSize());
1237    
1238     SetHeaderDate(_T("mtime"), entry.GetDateTime());
1239     if (entry.GetAccessTime().IsValid())
1240     SetHeaderDate(_T("atime"), entry.GetAccessTime());
1241     if (entry.GetCreateTime().IsValid())
1242     SetHeaderDate(_T("ctime"), entry.GetCreateTime());
1243    
1244     *m_hdr->Get(TAR_TYPEFLAG) = char(entry.GetTypeFlag());
1245    
1246     strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC);
1247     strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION);
1248    
1249     SetHeaderString(TAR_LINKNAME, entry.GetLinkName());
1250     SetHeaderString(TAR_UNAME, entry.GetUserName());
1251     SetHeaderString(TAR_GNAME, entry.GetGroupName());
1252    
1253     if (~entry.GetDevMajor())
1254     SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor());
1255     if (~entry.GetDevMinor())
1256     SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor());
1257    
1258     m_chksum = m_hdr->Sum();
1259     m_hdr->SetOctal(TAR_CHKSUM, m_chksum);
1260     if (!m_large)
1261     m_chksum -= m_hdr->SumField(TAR_SIZE);
1262    
1263     // The main header is now fully prepared so we know what extended headers
1264     // (if any) will be needed. Output any extended headers before writing
1265     // the main header.
1266     if (m_extendedHdr && *m_extendedHdr) {
1267     wxASSERT(m_pax);
1268     // the extended headers are written to the tar as a file entry,
1269     // so prepare a regular header block for the pseudo-file.
1270     if (!m_hdr2)
1271     m_hdr2 = new wxTarHeaderBlock;
1272     memset(m_hdr2, 0, sizeof(*m_hdr2));
1273    
1274     // an old tar that doesn't understand extended headers will
1275     // extract it as a file, so give these fields reasonable values
1276     // so that the user will have access to read and remove it.
1277     m_hdr2->SetPath(PaxHeaderPath(_T("%d/PaxHeaders.%p/%f"),
1278     entry.GetName(wxPATH_UNIX)), GetConv());
1279     m_hdr2->SetOctal(TAR_MODE, 0600);
1280     strcpy(m_hdr2->Get(TAR_UID), m_hdr->Get(TAR_UID));
1281     strcpy(m_hdr2->Get(TAR_GID), m_hdr->Get(TAR_GID));
1282     size_t length = strlen(m_extendedHdr);
1283     m_hdr2->SetOctal(TAR_SIZE, length);
1284     strcpy(m_hdr2->Get(TAR_MTIME), m_hdr->Get(TAR_MTIME));
1285     *m_hdr2->Get(TAR_TYPEFLAG) = 'x';
1286     strcpy(m_hdr2->Get(TAR_MAGIC), USTAR_MAGIC);
1287     strcpy(m_hdr2->Get(TAR_VERSION), USTAR_VERSION);
1288     strcpy(m_hdr2->Get(TAR_UNAME), m_hdr->Get(TAR_UNAME));
1289     strcpy(m_hdr2->Get(TAR_GNAME), m_hdr->Get(TAR_GNAME));
1290    
1291     m_hdr2->SetOctal(TAR_CHKSUM, m_hdr2->Sum());
1292    
1293     m_hdr2->Write(*m_parent_o_stream);
1294     m_tarsize += TAR_BLOCKSIZE;
1295    
1296     size_t rounded = RoundUpSize(length);
1297     memset(m_extendedHdr + length, 0, rounded - length);
1298     m_parent_o_stream->Write(m_extendedHdr, rounded);
1299     m_tarsize += rounded;
1300    
1301     *m_extendedHdr = 0;
1302     }
1303    
1304     // if don't have extended headers just report error
1305     if (!m_badfit.empty()) {
1306     wxASSERT(!m_pax);
1307     wxLogWarning(_("%s did not fit the tar header for entry '%s'"),
1308     m_badfit.c_str(), entry.GetName().c_str());
1309     m_badfit.clear();
1310     }
1311    
1312     m_hdr->Write(*m_parent_o_stream);
1313     m_tarsize += TAR_BLOCKSIZE;
1314     m_lasterror = m_parent_o_stream->GetLastError();
1315    
1316     return IsOk();
1317     }
1318    
1319     wxString wxTarOutputStream::PaxHeaderPath(const wxString& format,
1320     const wxString& path)
1321     {
1322     wxString d = path.BeforeLast(_T('/'));
1323     wxString f = path.AfterLast(_T('/'));
1324     wxString ret;
1325    
1326     if (d.empty())
1327     d = _T(".");
1328    
1329     ret.reserve(format.length() + path.length() + 16);
1330    
1331     size_t begin = 0;
1332     size_t end;
1333    
1334     for (;;) {
1335     end = format.find('%', begin);
1336     if (end == wxString::npos || end + 1 >= format.length())
1337     break;
1338     ret << format.substr(begin, end - begin);
1339     switch (format[end + 1]) {
1340     case 'd': ret << d; break;
1341     case 'f': ret << f; break;
1342     case 'p': ret << wxGetProcessId(); break;
1343     case '%': ret << _T("%"); break;
1344     }
1345     begin = end + 2;
1346     }
1347    
1348     ret << format.substr(begin);
1349    
1350     return ret;
1351     }
1352    
1353     bool wxTarOutputStream::ModifyHeader()
1354     {
1355     wxFileOffset originalPos = wxInvalidOffset;
1356     wxFileOffset sizePos = wxInvalidOffset;
1357    
1358     if (!m_large && m_headpos != wxInvalidOffset
1359     && m_parent_o_stream->IsSeekable())
1360     {
1361     wxLogNull nolog;
1362     originalPos = m_parent_o_stream->TellO();
1363     if (originalPos != wxInvalidOffset)
1364     sizePos =
1365     m_parent_o_stream->SeekO(m_headpos + m_hdr->Offset(TAR_SIZE));
1366     }
1367    
1368     if (sizePos == wxInvalidOffset || !m_hdr->SetOctal(TAR_SIZE, m_pos)) {
1369     wxLogError(_("incorrect size given for tar entry"));
1370     m_lasterror = wxSTREAM_WRITE_ERROR;
1371     return false;
1372     }
1373    
1374     m_chksum += m_hdr->SumField(TAR_SIZE);
1375     m_hdr->SetOctal(TAR_CHKSUM, m_chksum);
1376     wxFileOffset sumPos = m_headpos + m_hdr->Offset(TAR_CHKSUM);
1377    
1378     return
1379     m_hdr->WriteField(*m_parent_o_stream, TAR_SIZE) &&
1380     m_parent_o_stream->SeekO(sumPos) == sumPos &&
1381     m_hdr->WriteField(*m_parent_o_stream, TAR_CHKSUM) &&
1382     m_parent_o_stream->SeekO(originalPos) == originalPos;
1383     }
1384    
1385     void wxTarOutputStream::SetHeaderPath(const wxString& name)
1386     {
1387     if (!m_hdr->SetPath(name, GetConv()) || (m_pax && !name.IsAscii()))
1388     SetExtendedHeader(_T("path"), name);
1389     }
1390    
1391     bool wxTarOutputStream::SetHeaderNumber(int id, wxTarNumber n)
1392     {
1393     if (m_hdr->SetOctal(id, n)) {
1394     return true;
1395     } else {
1396     SetExtendedHeader(m_hdr->Name(id), wxLongLong(n).ToString());
1397     return false;
1398     }
1399     }
1400    
1401     void wxTarOutputStream::SetHeaderString(int id, const wxString& str)
1402     {
1403     strncpy(m_hdr->Get(id), str.mb_str(GetConv()), m_hdr->Len(id));
1404     if (str.length() > m_hdr->Len(id))
1405     SetExtendedHeader(m_hdr->Name(id), str);
1406     }
1407    
1408     void wxTarOutputStream::SetHeaderDate(const wxString& key,
1409     const wxDateTime& datetime)
1410     {
1411     wxLongLong ll = datetime.IsValid() ? datetime.GetValue() : wxLongLong(0);
1412     wxLongLong secs = ll / 1000L;
1413    
1414     if (key != _T("mtime")
1415     || !m_hdr->SetOctal(TAR_MTIME, wxTarNumber(secs.GetValue()))
1416     || secs <= 0 || secs >= 0x7fffffff)
1417     {
1418     wxString str;
1419     if (ll >= LONG_MIN && ll <= LONG_MAX) {
1420     str.Printf(_T("%g"), ll.ToLong() / 1000.0);
1421     } else {
1422     str = ll.ToString();
1423     str.insert(str.end() - 3, '.');
1424     }
1425     SetExtendedHeader(key, str);
1426     }
1427     }
1428    
1429     void wxTarOutputStream::SetExtendedHeader(const wxString& key,
1430     const wxString& value)
1431     {
1432     if (m_pax) {
1433     const wxWX2WCbuf wide_key = key.wc_str(GetConv());
1434     const wxCharBuffer utf_key = wxConvUTF8.cWC2MB(wide_key);
1435    
1436     const wxWX2WCbuf wide_value = value.wc_str(GetConv());
1437     const wxCharBuffer utf_value = wxConvUTF8.cWC2MB(wide_value);
1438    
1439     // a small buffer to format the length field in
1440     char buf[32];
1441     // length of "99<space><key>=<value>\n"
1442     unsigned long length = strlen(utf_value) + strlen(utf_key) + 5;
1443     sprintf(buf, "%lu", length);
1444     // the length includes itself
1445     size_t lenlen = strlen(buf);
1446     if (lenlen != 2) {
1447     length += lenlen - 2;
1448     sprintf(buf, "%lu", length);
1449     if (strlen(buf) > lenlen)
1450     sprintf(buf, "%lu", ++length);
1451     }
1452    
1453     // reallocate m_extendedHdr if it's not big enough
1454     if (m_extendedSize < length) {
1455     size_t rounded = RoundUpSize(length);
1456     m_extendedSize <<= 1;
1457     if (rounded > m_extendedSize)
1458     m_extendedSize = rounded;
1459     char *oldHdr = m_extendedHdr;
1460     m_extendedHdr = new char[m_extendedSize];
1461     if (oldHdr) {
1462     strcpy(m_extendedHdr, oldHdr);
1463     delete oldHdr;
1464     } else {
1465     *m_extendedHdr = 0;
1466     }
1467     }
1468    
1469     // append the new record
1470     char *append = strchr(m_extendedHdr, 0);
1471     sprintf(append, "%s %s=%s\012", buf,
1472     (const char*)utf_key, (const char*)utf_value);
1473     }
1474     else {
1475     // if not pax then make a list of fields to report as errors
1476     if (!m_badfit.empty())
1477     m_badfit += _T(", ");
1478     m_badfit += key;
1479     }
1480     }
1481    
1482     void wxTarOutputStream::Sync()
1483     {
1484     m_parent_o_stream->Sync();
1485     }
1486    
1487     wxFileOffset wxTarOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
1488     {
1489     if (!IsOpened()) {
1490     wxLogError(_("tar entry not open"));
1491     m_lasterror = wxSTREAM_WRITE_ERROR;
1492     }
1493     if (!IsOk() || m_datapos == wxInvalidOffset)
1494     return wxInvalidOffset;
1495    
1496     switch (mode) {
1497     case wxFromStart: break;
1498     case wxFromCurrent: pos += m_pos; break;
1499     case wxFromEnd: pos += m_maxpos; break;
1500     }
1501    
1502     if (pos < 0 || m_parent_o_stream->SeekO(m_datapos + pos) == wxInvalidOffset)
1503     return wxInvalidOffset;
1504    
1505     m_pos = pos;
1506     return m_pos;
1507     }
1508    
1509     size_t wxTarOutputStream::OnSysWrite(const void *buffer, size_t size)
1510     {
1511     if (!IsOpened()) {
1512     wxLogError(_("tar entry not open"));
1513     m_lasterror = wxSTREAM_WRITE_ERROR;
1514     }
1515     if (!IsOk() || !size)
1516     return 0;
1517    
1518     size_t lastwrite = m_parent_o_stream->Write(buffer, size).LastWrite();
1519     m_pos += lastwrite;
1520     if (m_pos > m_maxpos)
1521     m_maxpos = m_pos;
1522    
1523     if (lastwrite != size)
1524     m_lasterror = wxSTREAM_WRITE_ERROR;
1525    
1526     return lastwrite;
1527     }
1528    
1529     #endif // wxUSE_TARSTREAM

  ViewVC Help
Powered by ViewVC 1.1.22