godot/tools/pck/pck_packer.cpp
Rémi Verschelde d4993b74fc Add missing argument names in GDScript bindings
All classes were reviewed apart from VisualServer for which no argument name is documented at all.
While doing this review, I found quite a few bugs that were fixed either in earlier commits or this one (mostly documentation bugs though, i.e. some arguments were listed at the wrong place).
2015-12-28 02:13:05 +01:00

164 lines
3.1 KiB
C++

#include "pck_packer.h"
#include "core/os/file_access.h"
static uint64_t _align(uint64_t p_n, int p_alignment) {
if (p_alignment == 0)
return p_n;
uint64_t rest = p_n % p_alignment;
if (rest == 0)
return p_n;
else
return p_n + (p_alignment - rest);
};
static void _pad(FileAccess* p_file, int p_bytes) {
for (int i=0; i<p_bytes; i++) {
p_file->store_8(0);
};
};
void PCKPacker::_bind_methods() {
ObjectTypeDB::bind_method(_MD("pck_start","pck_name","alignment"),&PCKPacker::pck_start);
ObjectTypeDB::bind_method(_MD("add_file","pck_path","source_path"),&PCKPacker::add_file);
ObjectTypeDB::bind_method(_MD("flush","verbose"),&PCKPacker::flush);
};
Error PCKPacker::pck_start(const String& p_file, int p_alignment) {
file = FileAccess::open(p_file, FileAccess::WRITE);
if (file == NULL) {
return ERR_CANT_CREATE;
};
alignment = p_alignment;
file->store_32(0x43504447); // MAGIC
file->store_32(0); // # version
file->store_32(0); // # major
file->store_32(0); // # minor
file->store_32(0); // # revision
for (int i=0; i<16; i++) {
file->store_32(0); // reserved
};
files.clear();
return OK;
};
Error PCKPacker::add_file(const String& p_file, const String& p_src) {
FileAccess* f = FileAccess::open(p_src, FileAccess::READ);
if (!f) {
return ERR_FILE_CANT_OPEN;
};
File pf;
pf.path = p_file;
pf.src_path = p_src;
pf.size = f->get_len();
pf.offset_offset = 0;
files.push_back(pf);
f->close();
memdelete(f);
return OK;
};
Error PCKPacker::flush(bool p_verbose) {
if (!file) {
ERR_FAIL_COND_V(!file, ERR_INVALID_PARAMETER);
return ERR_INVALID_PARAMETER;
};
// write the index
file->store_32(files.size());
for (int i=0; i<files.size(); i++) {
file->store_pascal_string(files[i].path);
files[i].offset_offset = file->get_pos();
file->store_64(0); // offset
file->store_64(files[i].size); // size
// # empty md5
file->store_32(0);
file->store_32(0);
file->store_32(0);
file->store_32(0);
};
uint64_t ofs = file->get_pos();
ofs = _align(ofs, alignment);
_pad(file, ofs - file->get_pos());
const uint32_t buf_max = 65536;
uint8_t *buf = memnew_arr(uint8_t, buf_max);
int count = 0;
for (int i=0; i<files.size(); i++) {
FileAccess* src = FileAccess::open(files[i].src_path, FileAccess::READ);
uint64_t to_write = files[i].size;
while (to_write > 0) {
int read = src->get_buffer(buf, MIN(to_write, buf_max));
file->store_buffer(buf, read);
to_write -= read;
};
uint64_t pos = file->get_pos();
file->seek(files[i].offset_offset); // go back to store the file's offset
file->store_64(ofs);
file->seek(pos);
ofs = _align(ofs + files[i].size, alignment);
_pad(file, ofs - pos);
src->close();
memdelete(src);
count += 1;
if (p_verbose) {
if (count % 100 == 0) {
printf("%i/%i (%.2f)\r", count, files.size(), float(count) / files.size() * 100);
fflush(stdout);
};
};
};
if (p_verbose)
printf("\n");
file->close();
return OK;
};
PCKPacker::PCKPacker() {
file = NULL;
};
PCKPacker::~PCKPacker() {
if (file != NULL) {
memdelete(file);
};
file = NULL;
};