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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years, 2 months ago) by william
File size: 41062 byte(s)
committing r3113 initial commit again...
1 /////////////////////////////////////////////////////////////////////////////
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