zipios  2.3.2
Zipios -- a small C++ library that provides easy access to .zip files.
zipcentraldirectoryentry.cpp
Go to the documentation of this file.
1 /*
2  Zipios -- a small C++ library that provides easy access to .zip files.
3 
4  Copyright (C) 2000-2007 Thomas Sondergaard
5  Copyright (c) 2015-2022 Made to Order Software Corp. All Rights Reserved
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 
31 
33 #include "zipios/dosdatetime.hpp"
34 
35 #include "zipios_common.hpp"
36 
37 
38 namespace zipios
39 {
40 
41 
42 
43 namespace
44 {
45 
46 
57 uint32_t const g_signature = 0x02014b50;
58 
59 
60 // The zip codes (values are pre-shifted)
61 uint16_t const g_msdos = 0x0000;
62 uint16_t const g_amiga = 0x0100;
63 uint16_t const g_open_vms = 0x0200;
64 uint16_t const g_unix = 0x0300;
65 uint16_t const g_vm_cms = 0x0400;
66 uint16_t const g_atari_st = 0x0500;
67 uint16_t const g_os2_hpfs = 0x0600;
68 uint16_t const g_macintosh = 0x0700;
69 uint16_t const g_z_system = 0x0800;
70 uint16_t const g_cpm = 0x0900;
71 uint16_t const g_windows = 0x0A00;
72 uint16_t const g_mvs = 0x0B00;
73 uint16_t const g_vse = 0x0C00;
74 uint16_t const g_acorn_risc = 0x0D00;
75 uint16_t const g_vfat = 0x0E00;
76 uint16_t const g_alternate_vms = 0x0F00;
77 uint16_t const g_beos = 0x1000;
78 uint16_t const g_tandem = 0x1100;
79 uint16_t const g_os400 = 0x1200;
80 uint16_t const g_osx = 0x1300;
81 
82 
103 {
104  uint32_t m_signature;
109  uint32_t m_dosdatetime;
110  uint32_t m_crc_32;
113  uint16_t m_filename_len;
120  //uint8_t m_filename[m_filename_len];
121  //uint8_t m_extra_field[m_extra_field_len];
122  //uint8_t m_file_comment[m_file_comment_len];
123 };
124 
125 
126 } // no name namespace
127 
128 
145 {
146 }
147 
148 
159  : ZipLocalEntry(entry)
160 {
161 }
162 
163 
169 {
170 }
171 
172 
181 {
187  // Note that the structure is 48 bytes because of an alignment
188  // and attempting to use options to avoid the alignment would
189  // not be portable so we use a hard coded value (yuck!)
190  return 46 /* sizeof(ZipCentralDirectoryEntryHeader) */
191  + m_filename.length() + (m_is_directory ? 1 : 0)
192  + m_extra_field.size()
193  + m_comment.length();
194 }
195 
196 
205 {
206  return std::make_shared<ZipCentralDirectoryEntry>(*this);
207 }
208 
209 
234 void ZipCentralDirectoryEntry::read(std::istream & is)
235 {
236  m_valid = false; // set back to true upon successful completion below.
237 
238  // verify the signature
239  uint32_t signature;
240  zipRead(is, signature);
241  if(g_signature != signature)
242  {
243  is.setstate(std::ios::failbit);
244  throw IOException("ZipCentralDirectoryEntry::read(): Expected Central Directory entry signature not found");
245  }
246 
247  uint16_t writer_version(0);
248  uint16_t compress_method(0);
249  uint32_t dosdatetime(0);
250  uint32_t compressed_size(0);
251  uint32_t uncompressed_size(0);
252  uint32_t rel_offset_loc_head(0);
253  uint16_t filename_len(0);
254  uint16_t extra_field_len(0);
255  uint16_t file_comment_len(0);
256  uint16_t intern_file_attr(0);
257  uint32_t extern_file_attr(0);
258  uint16_t disk_num_start(0);
259  std::string filename;
260 
261  // read the header
262  zipRead(is, writer_version); // 16
263  zipRead(is, m_extract_version); // 16
265  zipRead(is, compress_method); // 16
266  zipRead(is, dosdatetime); // 32
267  zipRead(is, m_crc_32); // 32
268  zipRead(is, compressed_size); // 32
269  zipRead(is, uncompressed_size); // 32
270  zipRead(is, filename_len); // 16
271  zipRead(is, extra_field_len); // 16
272  zipRead(is, file_comment_len); // 16
273  zipRead(is, disk_num_start); // 16
274  zipRead(is, intern_file_attr); // 16
275  zipRead(is, extern_file_attr); // 32
276  zipRead(is, rel_offset_loc_head); // 32
277  zipRead(is, filename, filename_len); // string
278  zipRead(is, m_extra_field, extra_field_len); // buffer
279  zipRead(is, m_comment, file_comment_len); // string
284  // the FilePath() will remove the trailing slash so make sure
285  // to defined the m_is_directory ahead of time!
286  m_is_directory = !filename.empty() && filename.back() == g_separator;
287 
288  m_compress_method = static_cast<StorageMethod>(compress_method);
289  DOSDateTime t;
290  t.setDOSDateTime(dosdatetime);
292  m_compressed_size = compressed_size;
293  m_uncompressed_size = uncompressed_size;
294  m_entry_offset = rel_offset_loc_head;
295  m_filename = FilePath(filename);
296 
297  // the zipRead() should throw if it is false...
298  m_valid = true;
299 }
300 
301 
327 void ZipCentralDirectoryEntry::write(std::ostream & os)
328 {
332  if(m_filename.length() > 0x10000
333  || m_extra_field.size() > 0x10000
334  || m_comment.length() > 0x10000)
335  {
336  throw InvalidStateException("ZipCentralDirectoryEntry::write(): file name, comment, or extra field too large to save in a Zip file.");
337  }
338 
339 // Solaris defines _ILP32 for 32 bit platforms
340 #if INTPTR_MAX != INT32_MAX
341  if(m_compressed_size >= 0x100000000ULL
342  || m_uncompressed_size >= 0x100000000ULL
343  || m_entry_offset >= 0x100000000LL)
344  {
345  // This represents really large files which we do not test at this point
346  throw InvalidStateException("ZipCentralDirectoryEntry::write(): The size of this file is too large to fit in a zip archive."); // LCOV_EXCL_LINE
347  }
348 #endif
349 
350  // define version
351  uint16_t writer_version = g_zip_format_version;
352  // including the "compatibility" code
353 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
354  // MS-Windows
355  // TBD: should we use g_msdos instead?
356  writer_version |= g_windows;
357 #elif defined(__APPLE__) && defined(__MACH__)
358  // OS/X
359  writer_version |= g_osx;
360 #else
361  // Other Unices
362  writer_version |= g_unix;
363 #endif
364 
365  std::string filename(m_filename);
366  if(m_is_directory)
367  {
368  // add a trailing separator for directories
369  // (this is VERY important for zip files which do not otherwise
370  // indicate that a file is a directory)
371  filename += g_separator;
372  }
373 
374  uint16_t compress_method(static_cast<uint8_t>(m_compress_method));
376  {
377  compress_method = static_cast<uint8_t>(StorageMethod::STORED);
378  }
379 
380  DOSDateTime t;
382  uint32_t dosdatetime(t.getDOSDateTime()); // type could be set to DOSDateTime::dosdatetime_t
383  uint32_t compressed_size(m_compressed_size);
384  uint32_t uncompressed_size(m_uncompressed_size);
385  uint16_t filename_len(filename.length());
386  uint16_t extra_field_len(m_extra_field.size());
387  uint16_t file_comment_len(m_comment.length());
388  uint16_t disk_num_start(0);
389  uint16_t intern_file_attr(0);
409  uint32_t extern_file_attr(m_is_directory ? 0x41FD0010 : 0x81B40000);
410  uint32_t rel_offset_loc_head(m_entry_offset);
411 
412  zipWrite(os, g_signature); // 32
413  zipWrite(os, writer_version); // 16
414  zipWrite(os, m_extract_version); // 16
416  zipWrite(os, compress_method); // 16
417  zipWrite(os, dosdatetime); // 32
418  zipWrite(os, m_crc_32); // 32
419  zipWrite(os, compressed_size); // 32
420  zipWrite(os, uncompressed_size); // 32
421  zipWrite(os, filename_len); // 16
422  zipWrite(os, extra_field_len); // 16
423  zipWrite(os, file_comment_len); // 16
424  zipWrite(os, disk_num_start); // 16
425  zipWrite(os, intern_file_attr); // 16
426  zipWrite(os, extern_file_attr); // 32
427  zipWrite(os, rel_offset_loc_head); // 32
428  zipWrite(os, filename); // string
429  zipWrite(os, m_extra_field); // buffer
430  zipWrite(os, m_comment); // string
431 }
432 
433 
434 } // zipios namespace
435 
436 // Local Variables:
437 // mode: cpp
438 // indent-tabs-mode: nil
439 // c-basic-offset: 4
440 // tab-width: 4
441 // End:
442 
443 // vim: ts=4 sw=4 et
Define a type to manage date and time in MS-DOS format.
StorageMethod m_compress_method
Definition: fileentry.hpp:137
The zipios namespace includes the Zipios library definitions.
Definition: backbuffer.cpp:35
virtual size_t getHeaderSize() const override
Compute and return the current header size.
size_t length() const
Get the length of the string.
Definition: filepath.cpp:336
dosdatetime_t getDOSDateTime() const
Retrieve the DOSDateTime value as is.
Various exceptions used throughout the Zipios library, all based on zipios::Exception.
std::time_t getUnixTimestamp() const
Retrieve the DOSDateTime as a Unix timestamp.
void setUnixTimestamp(std::time_t unix_timestamp)
Set the DOSDateTime value from a Unix timestamp.
void zipRead(std::istream &is, uint32_t &value)
virtual pointer_t clone() const override
Create a clone of this Central Directory entry.
buffer_t m_extra_field
Definition: fileentry.hpp:140
CompressionLevel m_compression_level
Definition: fileentry.hpp:138
StorageMethod
The types used with FileEntry::setMethod and FileEntry::getMethod.
Definition: fileentry.hpp:48
An implementation of the FileEntry for Zip archives.
static CompressionLevel const COMPRESSION_LEVEL_NONE
Definition: fileentry.hpp:90
FilePath m_filename
Definition: fileentry.hpp:132
void zipWrite(std::ostream &os, uint32_t const &value)
char const g_separator
The character used as the filename separator.
An IOException is used to signal an I/O error.
ZipCentralDirectoryEntry()
Initializes a default ZipCentralDirectoryEntry object.
virtual ~ZipCentralDirectoryEntry() override
Clean up the entry.
A FileEntry represents an entry in a FileCollection.
Definition: fileentry.hpp:75
Exception used when it is not possible to move forward.
uint16_t m_general_purpose_bitfield
Declaration of the zipios::ZipCentralDirectoryEntry, which represents a directory Zip archive entry...
Handle a file path and name and its statistics.
Definition: filepath.hpp:46
static uint16_t const g_zip_format_version
Various functions used throughout the library.
void setDOSDateTime(dosdatetime_t datetime)
Set the DOSDateTime value as is.
virtual void write(std::ostream &os) override
Write a Central Directory Entry to the output stream.
virtual void read(std::istream &is) override
Read a Central Directory entry.
std::streampos m_entry_offset
Definition: fileentry.hpp:136
std::shared_ptr< FileEntry > pointer_t
Definition: fileentry.hpp:78
uint32_t const g_signature
The signature of a ZipCentralDirectoryEntry.
std::string m_comment
Definition: fileentry.hpp:133
std::size_t m_uncompressed_size
Definition: fileentry.hpp:134