Skip to content
Snippets Groups Projects
zipfile.cpp 2.24 KiB
Newer Older
Vicki Pfau's avatar
Vicki Pfau committed
#include "zipfile.h"

#include <algorithm>

using namespace Retro;
using namespace std;

Zip::Zip(const string& path)
	: m_path(path) {
}

Zip::~Zip() {
	close();
}

bool Zip::open(bool readwrite) {
	m_zip = zip_open(m_path.c_str(), readwrite ? ZIP_CREATE : ZIP_RDONLY, nullptr);
	return m_zip;
}

void Zip::close() {
	if (!m_zip) {
		return;
	}
	for (auto& file : m_files) {
		file->flush();
	}
	zip_close(m_zip);
	m_zip = nullptr;
	m_files.clear();
}

Zip::File* Zip::openFile(const std::string& name, bool write) {
	if (!m_zip) {
		return nullptr;
	}
	Zip::File* zf;
	if (!write) {
		zip_file_t* file = zip_fopen(m_zip, name.c_str(), 0);
		if (!file) {
			return nullptr;
		}
		zf = new Zip::File(m_zip, name, file);
	} else {
		zf = new Zip::File(m_zip, name);
	}
	m_files.emplace_back(zf);
	return zf;
}

Zip::File::File(zip_t* zip, const std::string& name, zip_file_t* file)
	: m_zip(zip)
	, m_file(file)
	, m_name(name) {
}

string Zip::File::readline() {
	auto pos = m_buffer.end();
	pos = find(m_buffer.begin(), m_buffer.end(), '\n');
	while (pos == m_buffer.end()) {
		size_t size = m_buffer.size();
		m_buffer.resize(size + 256);
		size_t r = read(static_cast<void*>(&m_buffer[size]), 256);
		if (!r) {
			string s(m_buffer.begin(), m_buffer.end() - 256);
			m_buffer.clear();
			return s;
		}
		if (r < 256) {
			m_buffer.erase(m_buffer.end() - 256 + r, m_buffer.end());
		}
		pos = find(m_buffer.begin(), m_buffer.end(), '\n');
	}
	if (pos != m_buffer.begin() && *(pos - 1) == '\r') {
		// Strip out carriage returns
		--pos;
	}
	string s(m_buffer.begin(), pos);
	if (*pos == '\r') {
		++pos;
	}
	m_buffer.erase(m_buffer.begin(), pos + 1);
	return s;
}

ssize_t Zip::File::read(void* buffer, size_t size) {
	return zip_fread(m_file, buffer, size);
}

ssize_t Zip::File::write(const void* buffer, size_t size) {
	m_buffer.insert(m_buffer.end(), static_cast<const char*>(buffer), static_cast<const char*>(buffer) + size);
	return size;
}

bool Zip::File::flush() {
	if (!m_buffer.size()) {
		return false;
	}
	zip_source_t* source = zip_source_buffer(m_zip, static_cast<void*>(&m_buffer.front()), m_buffer.size(), 0);
	if (!source) {
		return false;
	}
	zip_int64_t i = zip_file_add(m_zip, m_name.c_str(), source, ZIP_FL_OVERWRITE);
	if (i < 0) {
		return false;
	}
	return true;
}