/** \brief Attempt to read an ZipEndOfCentralDirectory structure.
 *
 * This function tries to read an ZipEndOfCentralDirectory structure from the
 * specified buffer. This function expects a BackBuffer, which is used
 * because that is generally the fastest way to read the data (instead of
 * scanning the entire file).
 *
 * \note
 * If a read from the buffer fails, then an exception is raised. Since
 * we are reading from a buffer, it should not happen except if the
 * ZipEndOfCentralDirectory indicates that there is a comment and the comment
 * is not there or some characters are missing.
 *
 * \exception FileCollectionException
 * This exception is raised if the number of entries is not equal to
 * the total number of entries, as expected.
 *
 * \param[in] buf  The buffer with the file data.
 * \param[in] pos  The position at which we are expected to check.
 *
 * \return true if the ZipEndOfCentralDirectory was found, false otherwise.
 */
bool ZipEndOfCentralDirectory::read(::zipios::buffer_t const& buf, size_t pos)
{
    // the number of bytes we are going to read in the buffer
    // (including the signature)
    ssize_t const HEADER_SIZE(static_cast<ssize_t>(sizeof(uint32_t) * 3 + sizeof(uint16_t) * 5));

    // enough data in the buffer?
    //
    // Note: this quick check assumes a 0 length comment which is possible;
    //       if there is a comment and we find the signature too early, then
    //       it will throw
    //
    if(static_cast<ssize_t>(buf.size() - pos) < HEADER_SIZE)
    {
        return false;
    }

    // first read and check the signature
    uint32_t signature;
    zipRead(buf, pos, signature);               // 32
    if(signature != g_signature)
    {
        return false;
    }

    // next we read the other parameters
    uint16_t disk_number;
    uint16_t central_directory_entries;
    uint16_t central_directory_total_entries;
    uint32_t central_directory_size;
    uint32_t central_directory_offset;
    uint16_t comment_len;

    zipRead(buf, pos, disk_number);                         // 16
    zipRead(buf, pos, disk_number);                         // 16
    zipRead(buf, pos, central_directory_entries);           // 16
    zipRead(buf, pos, central_directory_total_entries);     // 16
    zipRead(buf, pos, central_directory_size);              // 32
    zipRead(buf, pos, central_directory_offset);            // 32
    zipRead(buf, pos, comment_len);                         // 16
    zipRead(buf, pos, m_zip_comment, comment_len);          // string

    // note that if disk_number is defined, then these following two
    // numbers should differ too
    if(central_directory_entries != central_directory_total_entries)
    {
        throw FileCollectionException("ZipEndOfCentralDirectory with a number of entries and total entries that differ is not supported, spanned zip files are not supported");
    }

    m_central_directory_entries = central_directory_entries;
    m_central_directory_size    = central_directory_size;
    m_central_directory_offset  = central_directory_offset;

    return true;
}
Esempio n. 2
0
/** \brief Open a zip archive that was previously appened to another file.
 *
 * Opens a Zip archive embedded in another file, by writing the zip
 * archive to the end of the file followed by the start offset of
 * the zip file on 4 bytes. The offset must be written in zip-file
 * byte-order (little endian).
 *
 * The program appendzip, which is part of the Zipios++ distribution can
 * be used to append a Zip archive to a file, e.g. a binary program.
 *
 * The function may throw various exception if the named file does not
 * seem to include a valid zip archive attached.
 *
 * \note
 * Only one file can be appended and opened in this way. Although
 * the appendzip tool can be used to append any number of files,
 * only the last one is accessible.
 *
 * \return A ZipFile that one can use to read compressed data.
 */
ZipFile::pointer_t ZipFile::openEmbeddedZipFile(std::string const& name)
{
    // open zipfile, read 4 last bytes close file
    // create ZipFile object.
    uint32_t start_offset;
    {
        std::ifstream ifs(name, std::ios::in | std::ios::binary);
        ifs.seekg(-4, std::ios::end);
        zipRead(ifs, start_offset);
        // TODO: add support for 64 bit (files of more than 4Gb)
    }
    return ZipFile::pointer_t(new ZipFile(name, start_offset, 4));
}
Esempio n. 3
0
BinaryInput::BinaryInput(
    const std::string&  filename,
    G3DEndian           fileEndian,
    bool                compressed) :
    m_filename(filename),
    m_bitPos(0),
    m_bitString(0),
    m_beginEndBits(0),
    m_alreadyRead(0),
    m_length(0),
    m_bufferLength(0),
    m_buffer(NULL),
    m_pos(0),
    m_freeBuffer(true) {

    setEndian(fileEndian);

    // Update global file tracker
    _internal::currentFilesUsed.insert(m_filename);


    if (! fileExists(m_filename, false)) {
        std::string zipfile;
        std::string internalfile;
        if (zipfileExists(m_filename, zipfile, internalfile)) {
            // Load from zipfile
            void* v;
            size_t s;
            zipRead(filename, v, s);
            m_buffer = reinterpret_cast<uint8*>(v);
            m_bufferLength = m_length = s;
            if (compressed) {
                decompress();
            }
            m_freeBuffer = true;
        } else {
            Log::common()->printf("Warning: File not found: %s\n", m_filename.c_str());
        }
        return;
    }

    // Figure out how big the file is and verify that it exists.
    m_length = fileLength(m_filename);

    // Read the file into memory
    FILE* file = fopen(m_filename.c_str(), "rb");

    if (! file || (m_length == -1)) {
        throw format("File not found: \"%s\"", m_filename.c_str());
        return;
    }

    if (! compressed && (m_length > INITIAL_BUFFER_LENGTH)) {
        // Read only a subset of the file so we don't consume
        // all available memory.
        m_bufferLength = INITIAL_BUFFER_LENGTH;
    } else {
        // Either the length is fine or the file is compressed
        // and requires us to read the whole thing for zlib.
        m_bufferLength = m_length;
    }

    debugAssert(m_freeBuffer);
    m_buffer = (uint8*)System::alignedMalloc(m_bufferLength, 16);
    if (m_buffer == NULL) {
        if (compressed) {
            throw "Not enough memory to load compressed file. (1)";
        }

        // Try to allocate a small array; not much memory is available.
        // Give up if we can't allocate even 1k.
        while ((m_buffer == NULL) && (m_bufferLength > 1024)) {
            m_bufferLength /= 2;
            m_buffer = (uint8*)System::alignedMalloc(m_bufferLength, 16);
        }
    }
    debugAssert(m_buffer);

    fread(m_buffer, m_bufferLength, sizeof(int8), file);
    fclose(file);
    file = NULL;

    if (compressed) {
        if (m_bufferLength != m_length) {
            throw "Not enough memory to load compressed file. (2)";
        }

        decompress();
    }
}