bool wxTarOutputStream::CloseEntry() { if (!IsOpened()) return true; if (m_pos < m_maxpos) { wxASSERT(m_parent_o_stream->IsSeekable()); m_parent_o_stream->SeekO(m_datapos + m_maxpos); m_lasterror = m_parent_o_stream->GetLastError(); m_pos = m_maxpos; } if (IsOk()) { wxFileOffset size = RoundUpSize(m_pos); if (size > m_pos) { m_hdr->Clear(size - m_pos); m_parent_o_stream->Write(m_hdr, size - m_pos); m_lasterror = m_parent_o_stream->GetLastError(); } m_tarsize += size; } if (IsOk() && m_pos != m_size) ModifyHeader(); m_pos = wxInvalidOffset; m_maxpos = wxInvalidOffset; m_size = wxInvalidOffset; m_headpos = wxInvalidOffset; m_datapos = wxInvalidOffset; return IsOk(); }
bool wxTarInputStream::CloseEntry() { if (m_lasterror == wxSTREAM_READ_ERROR) return false; if (!IsOpened()) return true; wxFileOffset size = RoundUpSize(m_size); wxFileOffset remainder = size - m_pos; if (remainder && m_parent_i_stream->IsSeekable()) { wxLogNull nolog; if (m_parent_i_stream->SeekI(remainder, wxFromCurrent) != wxInvalidOffset) remainder = 0; } if (remainder) { const int BUFSIZE = 8192; wxCharBuffer buf(BUFSIZE); while (remainder > 0 && m_parent_i_stream->IsOk()) remainder -= m_parent_i_stream->Read( buf.data(), wxMin(BUFSIZE, remainder)).LastRead(); } m_pos = wxInvalidOffset; m_offset += size; m_lasterror = m_parent_i_stream->GetLastError(); return IsOk(); }
void wxTarOutputStream::SetExtendedHeader(const wxString& key, 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); #endif // wxUSE_UNICODE/!wxUSE_UNICODE // a small buffer to format the length field in char buf[32]; // length of "99<space><key>=<value>\n" unsigned long length = strlen(utf_value) + strlen(utf_key) + 5; sprintf(buf, "%lu", length); // the length includes itself size_t lenlen = strlen(buf); if (lenlen != 2) { length += lenlen - 2; sprintf(buf, "%lu", length); if (strlen(buf) > lenlen) sprintf(buf, "%lu", ++length); } // reallocate m_extendedHdr if it's not big enough if (m_extendedSize < length) { size_t rounded = RoundUpSize(length); m_extendedSize <<= 1; if (rounded > m_extendedSize) m_extendedSize = rounded; char *oldHdr = m_extendedHdr; m_extendedHdr = new char[m_extendedSize]; if (oldHdr) { strcpy(m_extendedHdr, oldHdr); delete oldHdr; } else { *m_extendedHdr = 0; } } // append the new record char *append = strchr(m_extendedHdr, 0); sprintf(append, "%s %s=%s\012", buf, (const char*)utf_key, (const char*)utf_value); } else { // if not pax then make a list of fields to report as errors if (!m_badfit.empty()) m_badfit += wxT(", "); m_badfit += key; } }
void KRBundle::append(KRResource &resource) { // Serialize resource to binary representation KRDataBlock resource_data; resource.save(resource_data); std::string file_name = resource.getName() + "." + resource.getExtension(); // Padding is added at the end of file to align next header to a 512 byte boundary. Padding at the end of the archive includes an additional 1024 bytes -- two zero-ed out file headers that mark the end of the archive size_t padding_size = RoundUpSize(resource_data.getSize()) - resource_data.getSize() + KRENGINE_KRBUNDLE_HEADER_SIZE * 2; m_pData->expand(KRENGINE_KRBUNDLE_HEADER_SIZE + resource_data.getSize() + padding_size - KRENGINE_KRBUNDLE_HEADER_SIZE * 2); // We will overwrite the existing zero-ed out file headers that marked the end of the archive, so we don't have to include their size here m_pData->lock(); // Get location of file header tar_header_type *file_header = (tar_header_type *)((unsigned char *)m_pData->getEnd() - padding_size - resource_data.getSize() - KRENGINE_KRBUNDLE_HEADER_SIZE); // Zero out new file header memset(file_header, 0, KRENGINE_KRBUNDLE_HEADER_SIZE); // Copy resource data resource_data.lock(); memcpy((unsigned char *)m_pData->getEnd() - padding_size - resource_data.getSize(), resource_data.getStart(), resource_data.getSize()); resource_data.unlock(); // Zero out alignment padding and terminating set of file header blocks memset((unsigned char *)m_pData->getEnd() - padding_size, 0, padding_size); // Populate new file header fields strncpy(file_header->file_name, file_name.c_str(), 100); strcpy(file_header->file_mode, "000644 "); strcpy(file_header->owner_id, "000000 "); strcpy(file_header->group_id, "000000 "); sprintf(file_header->file_size, "%011o", (int)resource_data.getSize()); file_header->file_size[11] = ' '; // Terminate with space rather than '\0' sprintf(file_header->mod_time, "%011o", (int)time(NULL)); file_header->mod_time[11] = ' '; // Terminate with space rather than '\0' // Calculate and write checksum for header memset(file_header->checksum, ' ', 8); // Must be filled with spaces and no null terminator during checksum calculation int check_sum = 0; for(int i=0; i < KRENGINE_KRBUNDLE_HEADER_SIZE; i++) { unsigned char *byte_ptr = (unsigned char *)file_header; check_sum += byte_ptr[i]; } sprintf(file_header->checksum, "%07o", check_sum); m_pData->unlock(); }
bool wxTarOutputStream::Close() { if (!CloseEntry() || (m_tarsize == 0 && m_endrecWritten)) return false; m_hdr->Clear(); int count = (RoundUpSize(m_tarsize + 2 * TAR_BLOCKSIZE, m_BlockingFactor) - m_tarsize) / TAR_BLOCKSIZE; while (count--) m_parent_o_stream->Write(m_hdr, TAR_BLOCKSIZE); m_tarsize = 0; m_tarstart = wxInvalidOffset; m_lasterror = m_parent_o_stream->GetLastError(); m_endrecWritten = true; return IsOk(); }
KRBundle::KRBundle(KRContext &context, std::string name, KRDataBlock *pData) : KRResource(context, name) { m_pData = pData; __int64_t file_pos = 0; while(file_pos < m_pData->getSize()) { tar_header_type file_header; m_pData->copy(&file_header, file_pos, sizeof(file_header)); size_t file_size = strtol(file_header.file_size, NULL, 8); file_pos += 512; // Skip past the header to the file contents if(file_header.file_name[0] != '\0' && file_header.file_name[0] != '.') { // We ignore the last two records in the tar file, which are zero'ed out tar_header structures KRDataBlock *pFileData = pData->getSubBlock(file_pos, file_size); context.loadResource(file_header.file_name, pFileData); } file_pos += RoundUpSize(file_size); } }
bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs) { if (!recs) recs = new wxTarHeaderRecords; // round length up to a whole number of blocks size_t len = m_hdr->GetOctal(TAR_SIZE); size_t size = RoundUpSize(len); // read in the whole header since it should be small wxCharBuffer buf(size); size_t lastread = m_parent_i_stream->Read(buf.data(), size).LastRead(); if (lastread < len) len = lastread; buf.data()[len] = 0; m_offset += lastread; size_t recPos, recSize; bool ok = true; 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; while (isdigit((unsigned char) *p)) recSize = recSize * 10 + *p++ - '0'; // validity checks if (recPos + recSize > len) break; if (recSize < p - pRec + (size_t)3 || *p != ' ' || pRec[recSize - 1] != '\012') { ok = false; continue; } // replace the final '\n' with a nul, to terminate value pRec[recSize - 1] = 0; // the key is here, following the space char *pKey = ++p; // look forward for the '=', the value follows while (*p && *p != '=') p++; if (!*p) { ok = false; continue; } // replace the '=' with a nul, to terminate the key *p++ = 0; wxString key(wxConvUTF8.cMB2WC(pKey), GetConv()); wxString value(wxConvUTF8.cMB2WC(p), GetConv()); // an empty value unsets a previously given value if (value.empty()) recs->erase(key); else (*recs)[key] = value; } if (!ok || recPos < len || size != lastread) { wxLogWarning(_("invalid data in extended tar header")); return false; } return true; }
bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry) { m_hdr->Clear(); SetHeaderPath(entry.GetName(wxPATH_UNIX)); SetHeaderNumber(TAR_MODE, entry.GetMode()); SetHeaderNumber(TAR_UID, entry.GetUserId()); SetHeaderNumber(TAR_GID, entry.GetGroupId()); if (entry.GetSize() == wxInvalidOffset) entry.SetSize(0); m_large = !SetHeaderNumber(TAR_SIZE, entry.GetSize()); SetHeaderDate(wxT("mtime"), entry.GetDateTime()); if (entry.GetAccessTime().IsValid()) SetHeaderDate(wxT("atime"), entry.GetAccessTime()); if (entry.GetCreateTime().IsValid()) SetHeaderDate(wxT("ctime"), entry.GetCreateTime()); *m_hdr->Get(TAR_TYPEFLAG) = char(entry.GetTypeFlag()); strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC); strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION); SetHeaderString(TAR_LINKNAME, entry.GetLinkName()); SetHeaderString(TAR_UNAME, entry.GetUserName()); SetHeaderString(TAR_GNAME, entry.GetGroupName()); if (~entry.GetDevMajor()) SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor()); if (~entry.GetDevMinor()) SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor()); m_chksum = m_hdr->Sum(); m_hdr->SetOctal(TAR_CHKSUM, m_chksum); if (!m_large) m_chksum -= m_hdr->SumField(TAR_SIZE); // The main header is now fully prepared so we know what extended headers // (if any) will be needed. Output any extended headers before writing // the main header. if (m_extendedHdr && *m_extendedHdr) { wxASSERT(m_pax); // the extended headers are written to the tar as a file entry, // so prepare a regular header block for the pseudo-file. if (!m_hdr2) m_hdr2 = new wxTarHeaderBlock; m_hdr2->Clear(); // 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(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)); strcpy(m_hdr2->Get(TAR_GID), m_hdr->Get(TAR_GID)); size_t length = strlen(m_extendedHdr); m_hdr2->SetOctal(TAR_SIZE, length); 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_UNAME), m_hdr->Get(TAR_UNAME)); strcpy(m_hdr2->Get(TAR_GNAME), m_hdr->Get(TAR_GNAME)); m_hdr2->SetOctal(TAR_CHKSUM, m_hdr2->Sum()); m_hdr2->Write(*m_parent_o_stream); m_tarsize += TAR_BLOCKSIZE; size_t rounded = RoundUpSize(length); memset(m_extendedHdr + length, 0, rounded - length); m_parent_o_stream->Write(m_extendedHdr, rounded); 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 (!m_badfit.empty()) { wxASSERT(!m_pax); wxLogWarning(_("%s did not fit the tar header for entry '%s'"), 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(); return IsOk(); }