# more res/file refactoring (split up archive provider and builder)
also remove some stupid "returns ERR_OK or negative error code" comments, which is now guaranteed by LibError return type anyway. This was SVN commit r3807.
This commit is contained in:
parent
64ef19475d
commit
64ecf79c6a
@ -704,239 +704,3 @@ LibError afile_unmap(File* f)
|
||||
H_DEREF(af->ha, Archive, a);
|
||||
return file_unmap(&a->f);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// archive builder
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static inline bool file_type_is_uncompressible(const char* fn)
|
||||
{
|
||||
const char* ext = path_extension(fn);
|
||||
|
||||
// this is a selection of file types that are certainly not
|
||||
// further compressible. we need not include every type under the sun -
|
||||
// this is only a slight optimization that avoids wasting time
|
||||
// compressing files. the real decision as to cmethod is made based
|
||||
// on attained compression ratio.
|
||||
static const char* uncompressible_exts[] =
|
||||
{
|
||||
"zip", "rar",
|
||||
"jpg", "jpeg", "png",
|
||||
"ogg", "mp3"
|
||||
};
|
||||
|
||||
for(uint i = 0; i < ARRAY_SIZE(uncompressible_exts); i++)
|
||||
{
|
||||
if(!stricmp(ext+1, uncompressible_exts[i]))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
struct CompressParams
|
||||
{
|
||||
bool attempt_compress;
|
||||
uintptr_t ctx;
|
||||
u32 crc;
|
||||
};
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
static LibError compress_cb(uintptr_t cb_ctx, const void* block, size_t size, size_t* bytes_processed)
|
||||
{
|
||||
CompressParams* p = (CompressParams*)cb_ctx;
|
||||
|
||||
// comp_feed already makes note of total #bytes fed, and we need
|
||||
// vfs_io to return the uc size (to check if all data was read).
|
||||
*bytes_processed = size;
|
||||
|
||||
// update checksum
|
||||
p->crc = crc32(p->crc, (const Bytef*)block, (uInt)size);
|
||||
|
||||
if(p->attempt_compress)
|
||||
(void)comp_feed(p->ctx, block, size);
|
||||
return INFO_CB_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
// final decision on whether to store the file as compressed,
|
||||
// given the observed compressed/uncompressed sizes.
|
||||
static bool should_store_compressed(size_t ucsize, size_t csize)
|
||||
{
|
||||
const float ratio = (float)ucsize / csize;
|
||||
const ssize_t bytes_saved = (ssize_t)ucsize - (ssize_t)csize;
|
||||
UNUSED2(bytes_saved);
|
||||
|
||||
// tiny - store compressed regardless of savings.
|
||||
// rationale:
|
||||
// - CPU cost is negligible and overlapped with IO anyway;
|
||||
// - reading from compressed files uses less memory because we
|
||||
// don't need to allocate space for padding in the final buffer.
|
||||
if(ucsize < 512)
|
||||
return true;
|
||||
|
||||
// large high-entropy file - store uncompressed.
|
||||
// rationale:
|
||||
// - any bigger than this and CPU time becomes a problem: it isn't
|
||||
// necessarily hidden by IO time anymore.
|
||||
if(ucsize >= 32*KiB && ratio < 1.02f)
|
||||
return false;
|
||||
|
||||
// TODO: any other cases?
|
||||
// we currently store everything else compressed.
|
||||
return true;
|
||||
}
|
||||
|
||||
static LibError read_and_compress_file(const char* atom_fn, uintptr_t ctx,
|
||||
ArchiveEntry& ent, void*& file_contents, FileIOBuf& buf) // out
|
||||
{
|
||||
struct stat s;
|
||||
RETURN_ERR(vfs_stat(atom_fn, &s));
|
||||
const size_t ucsize = s.st_size;
|
||||
// skip 0-length files.
|
||||
// rationale: zip.cpp needs to determine whether a CDFH entry is
|
||||
// a file or directory (the latter are written by some programs but
|
||||
// not needed - they'd only pollute the file table).
|
||||
// it looks like checking for ucsize=csize=0 is the safest way -
|
||||
// relying on file attributes (which are system-dependent!) is
|
||||
// even less safe.
|
||||
// we thus skip 0-length files to avoid confusing them with dirs.
|
||||
if(!ucsize)
|
||||
return INFO_SKIPPED;
|
||||
|
||||
const bool attempt_compress = !file_type_is_uncompressible(atom_fn);
|
||||
if(attempt_compress)
|
||||
{
|
||||
RETURN_ERR(comp_reset(ctx));
|
||||
RETURN_ERR(comp_alloc_output(ctx, ucsize));
|
||||
}
|
||||
|
||||
// read file into newly allocated buffer. if attempt_compress, also
|
||||
// compress the file into another buffer while waiting for IOs.
|
||||
size_t ucsize_read;
|
||||
const uint flags = 0;
|
||||
CompressParams params = { attempt_compress, ctx, 0 };
|
||||
RETURN_ERR(vfs_load(atom_fn, buf, ucsize_read, flags, compress_cb, (uintptr_t)¶ms));
|
||||
debug_assert(ucsize_read == ucsize);
|
||||
|
||||
// if we compressed the file trial-wise, check results and
|
||||
// decide whether to store as such or not (based on compression ratio)
|
||||
bool store_compressed = false;
|
||||
void* cdata = 0; size_t csize = 0;
|
||||
if(attempt_compress)
|
||||
{
|
||||
LibError ret = comp_finish(ctx, &cdata, &csize);
|
||||
if(ret < 0)
|
||||
{
|
||||
file_buf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
store_compressed = should_store_compressed(ucsize, csize);
|
||||
}
|
||||
|
||||
// store file info
|
||||
ent.ucsize = (off_t)ucsize;
|
||||
ent.mtime = s.st_mtime;
|
||||
// .. ent.ofs is set by zip_archive_add_file
|
||||
ent.flags = 0;
|
||||
ent.atom_fn = atom_fn;
|
||||
ent.crc = params.crc;
|
||||
if(store_compressed)
|
||||
{
|
||||
ent.method = CM_DEFLATE;
|
||||
ent.csize = (off_t)csize;
|
||||
file_contents = cdata;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent.method = CM_NONE;
|
||||
ent.csize = (off_t)ucsize;
|
||||
file_contents = (void*)buf;
|
||||
}
|
||||
|
||||
// note: no need to free cdata - it is owned by the
|
||||
// compression context and can be reused.
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LibError archive_build_init(const char* P_archive_filename, Filenames V_fns,
|
||||
ArchiveBuildState* ab)
|
||||
{
|
||||
RETURN_ERR(zip_archive_create(P_archive_filename, &ab->za));
|
||||
ab->ctx = comp_alloc(CT_COMPRESSION, CM_DEFLATE);
|
||||
ab->V_fns = V_fns;
|
||||
|
||||
// count number of files (needed to estimate progress)
|
||||
for(ab->num_files = 0; ab->V_fns[ab->num_files]; ab->num_files++) {}
|
||||
|
||||
ab->i = 0;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
#include "ps/Loader.h"
|
||||
|
||||
int archive_build_continue(ArchiveBuildState* ab)
|
||||
{
|
||||
|
||||
const double end_time = get_time() + 200e-3;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
const char* V_fn = ab->V_fns[ab->i];
|
||||
if(!V_fn)
|
||||
break;
|
||||
|
||||
ArchiveEntry ent; void* file_contents; FileIOBuf buf;
|
||||
if(read_and_compress_file(V_fn, ab->ctx, ent, file_contents, buf) == ERR_OK)
|
||||
{
|
||||
(void)zip_archive_add_file(ab->za, &ent, file_contents);
|
||||
(void)file_buf_free(buf);
|
||||
}
|
||||
|
||||
ab->i++;
|
||||
LDR_CHECK_TIMEOUT((int)ab->i, (int)ab->num_files);
|
||||
}
|
||||
|
||||
// note: this is currently known to fail if there are no files in the list
|
||||
// - zlib.h says: Z_DATA_ERROR is returned if freed prematurely.
|
||||
// safe to ignore.
|
||||
comp_free(ab->ctx); ab->ctx = 0;
|
||||
(void)zip_archive_finish(ab->za);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
void archive_build_cancel(ArchiveBuildState* ab)
|
||||
{
|
||||
// note: the GUI may call us even though no build was ever in progress.
|
||||
// be sure to make all steps no-op if <ab> is zeroed (initial state) or
|
||||
// no build is in progress.
|
||||
|
||||
comp_free(ab->ctx); ab->ctx = 0;
|
||||
if(ab->za)
|
||||
(void)zip_archive_finish(ab->za);
|
||||
memset(ab, 0, sizeof(*ab));
|
||||
}
|
||||
|
||||
|
||||
LibError archive_build(const char* P_archive_filename, Filenames V_fns)
|
||||
{
|
||||
ArchiveBuildState ab;
|
||||
RETURN_ERR(archive_build_init(P_archive_filename, V_fns, &ab));
|
||||
for(;;)
|
||||
{
|
||||
int ret = archive_build_continue(&ab);
|
||||
RETURN_ERR(ret);
|
||||
if(ret == ERR_OK)
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
@ -139,37 +139,6 @@ extern LibError afile_map(File* f, void*& p, size_t& size);
|
||||
extern LibError afile_unmap(File* f);
|
||||
|
||||
|
||||
//
|
||||
// archive creation
|
||||
//
|
||||
|
||||
// array of pointers to VFS filenames (including path), terminated by a
|
||||
// NULL entry.
|
||||
typedef const char** Filenames;
|
||||
|
||||
// rationale: this is fairly lightweight and simple, so we don't bother
|
||||
// making it opaque.
|
||||
struct ArchiveBuildState
|
||||
{
|
||||
ZipArchive* za;
|
||||
uintptr_t ctx;
|
||||
Filenames V_fns;
|
||||
size_t num_files; // number of filenames in V_fns (excluding final 0)
|
||||
size_t i;
|
||||
};
|
||||
|
||||
extern LibError archive_build_init(const char* P_archive_filename, Filenames V_fns,
|
||||
ArchiveBuildState* ab);
|
||||
|
||||
// create an archive (overwriting previous file) and fill it with the given
|
||||
// files. compression method is chosen intelligently based on extension and
|
||||
// file entropy / achieved compression ratio.
|
||||
extern int archive_build_continue(ArchiveBuildState* ab);
|
||||
|
||||
extern void archive_build_cancel(ArchiveBuildState* ab);
|
||||
|
||||
extern LibError archive_build(const char* P_archive_filename, Filenames V_fns);
|
||||
|
||||
|
||||
//
|
||||
// interface for backends
|
||||
|
257
source/lib/res/file/archive_builder.cpp
Normal file
257
source/lib/res/file/archive_builder.cpp
Normal file
@ -0,0 +1,257 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : archive_builder.cpp
|
||||
* Project : 0 A.D.
|
||||
* Description :
|
||||
*
|
||||
* @author Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003-2005 Jan Wassenberg
|
||||
*
|
||||
* Redistribution and/or modification are also permitted under the
|
||||
* terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation (version 2 or later, at your option).
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "lib.h"
|
||||
#include "lib/timer.h"
|
||||
#include "file_internal.h"
|
||||
|
||||
// un-nice dependencies:
|
||||
#include "ps/Loader.h"
|
||||
#include <zlib.h>
|
||||
|
||||
static inline bool file_type_is_uncompressible(const char* fn)
|
||||
{
|
||||
const char* ext = path_extension(fn);
|
||||
|
||||
// this is a selection of file types that are certainly not
|
||||
// further compressible. we need not include every type under the sun -
|
||||
// this is only a slight optimization that avoids wasting time
|
||||
// compressing files. the real decision as to cmethod is made based
|
||||
// on attained compression ratio.
|
||||
static const char* uncompressible_exts[] =
|
||||
{
|
||||
"zip", "rar",
|
||||
"jpg", "jpeg", "png",
|
||||
"ogg", "mp3"
|
||||
};
|
||||
|
||||
for(uint i = 0; i < ARRAY_SIZE(uncompressible_exts); i++)
|
||||
{
|
||||
if(!stricmp(ext+1, uncompressible_exts[i]))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
struct CompressParams
|
||||
{
|
||||
bool attempt_compress;
|
||||
uintptr_t ctx;
|
||||
u32 crc;
|
||||
};
|
||||
|
||||
static LibError compress_cb(uintptr_t cb_ctx, const void* block, size_t size, size_t* bytes_processed)
|
||||
{
|
||||
CompressParams* p = (CompressParams*)cb_ctx;
|
||||
|
||||
// comp_feed already makes note of total #bytes fed, and we need
|
||||
// vfs_io to return the uc size (to check if all data was read).
|
||||
*bytes_processed = size;
|
||||
|
||||
// update checksum
|
||||
p->crc = crc32(p->crc, (const Bytef*)block, (uInt)size);
|
||||
|
||||
if(p->attempt_compress)
|
||||
(void)comp_feed(p->ctx, block, size);
|
||||
return INFO_CB_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
// final decision on whether to store the file as compressed,
|
||||
// given the observed compressed/uncompressed sizes.
|
||||
static bool should_store_compressed(size_t ucsize, size_t csize)
|
||||
{
|
||||
const float ratio = (float)ucsize / csize;
|
||||
const ssize_t bytes_saved = (ssize_t)ucsize - (ssize_t)csize;
|
||||
UNUSED2(bytes_saved);
|
||||
|
||||
// tiny - store compressed regardless of savings.
|
||||
// rationale:
|
||||
// - CPU cost is negligible and overlapped with IO anyway;
|
||||
// - reading from compressed files uses less memory because we
|
||||
// don't need to allocate space for padding in the final buffer.
|
||||
if(ucsize < 512)
|
||||
return true;
|
||||
|
||||
// large high-entropy file - store uncompressed.
|
||||
// rationale:
|
||||
// - any bigger than this and CPU time becomes a problem: it isn't
|
||||
// necessarily hidden by IO time anymore.
|
||||
if(ucsize >= 32*KiB && ratio < 1.02f)
|
||||
return false;
|
||||
|
||||
// TODO: any other cases?
|
||||
// we currently store everything else compressed.
|
||||
return true;
|
||||
}
|
||||
|
||||
static LibError read_and_compress_file(const char* atom_fn, uintptr_t ctx,
|
||||
ArchiveEntry& ent, void*& file_contents, FileIOBuf& buf) // out
|
||||
{
|
||||
struct stat s;
|
||||
RETURN_ERR(vfs_stat(atom_fn, &s));
|
||||
const size_t ucsize = s.st_size;
|
||||
// skip 0-length files.
|
||||
// rationale: zip.cpp needs to determine whether a CDFH entry is
|
||||
// a file or directory (the latter are written by some programs but
|
||||
// not needed - they'd only pollute the file table).
|
||||
// it looks like checking for ucsize=csize=0 is the safest way -
|
||||
// relying on file attributes (which are system-dependent!) is
|
||||
// even less safe.
|
||||
// we thus skip 0-length files to avoid confusing them with dirs.
|
||||
if(!ucsize)
|
||||
return INFO_SKIPPED;
|
||||
|
||||
const bool attempt_compress = !file_type_is_uncompressible(atom_fn);
|
||||
if(attempt_compress)
|
||||
{
|
||||
RETURN_ERR(comp_reset(ctx));
|
||||
RETURN_ERR(comp_alloc_output(ctx, ucsize));
|
||||
}
|
||||
|
||||
// read file into newly allocated buffer. if attempt_compress, also
|
||||
// compress the file into another buffer while waiting for IOs.
|
||||
size_t ucsize_read;
|
||||
const uint flags = 0;
|
||||
CompressParams params = { attempt_compress, ctx, 0 };
|
||||
RETURN_ERR(vfs_load(atom_fn, buf, ucsize_read, flags, compress_cb, (uintptr_t)¶ms));
|
||||
debug_assert(ucsize_read == ucsize);
|
||||
|
||||
// if we compressed the file trial-wise, check results and
|
||||
// decide whether to store as such or not (based on compression ratio)
|
||||
bool store_compressed = false;
|
||||
void* cdata = 0; size_t csize = 0;
|
||||
if(attempt_compress)
|
||||
{
|
||||
LibError ret = comp_finish(ctx, &cdata, &csize);
|
||||
if(ret < 0)
|
||||
{
|
||||
file_buf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
store_compressed = should_store_compressed(ucsize, csize);
|
||||
}
|
||||
|
||||
// store file info
|
||||
ent.ucsize = (off_t)ucsize;
|
||||
ent.mtime = s.st_mtime;
|
||||
// .. ent.ofs is set by zip_archive_add_file
|
||||
ent.flags = 0;
|
||||
ent.atom_fn = atom_fn;
|
||||
ent.crc = params.crc;
|
||||
if(store_compressed)
|
||||
{
|
||||
ent.method = CM_DEFLATE;
|
||||
ent.csize = (off_t)csize;
|
||||
file_contents = cdata;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent.method = CM_NONE;
|
||||
ent.csize = (off_t)ucsize;
|
||||
file_contents = (void*)buf;
|
||||
}
|
||||
|
||||
// note: no need to free cdata - it is owned by the
|
||||
// compression context and can be reused.
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LibError archive_build_init(const char* P_archive_filename, Filenames V_fns,
|
||||
ArchiveBuildState* ab)
|
||||
{
|
||||
RETURN_ERR(zip_archive_create(P_archive_filename, &ab->za));
|
||||
ab->ctx = comp_alloc(CT_COMPRESSION, CM_DEFLATE);
|
||||
ab->V_fns = V_fns;
|
||||
|
||||
// count number of files (needed to estimate progress)
|
||||
for(ab->num_files = 0; ab->V_fns[ab->num_files]; ab->num_files++) {}
|
||||
|
||||
ab->i = 0;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
int archive_build_continue(ArchiveBuildState* ab)
|
||||
{
|
||||
const double end_time = get_time() + 200e-3;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
const char* V_fn = ab->V_fns[ab->i];
|
||||
if(!V_fn)
|
||||
break;
|
||||
|
||||
ArchiveEntry ent; void* file_contents; FileIOBuf buf;
|
||||
if(read_and_compress_file(V_fn, ab->ctx, ent, file_contents, buf) == ERR_OK)
|
||||
{
|
||||
(void)zip_archive_add_file(ab->za, &ent, file_contents);
|
||||
(void)file_buf_free(buf);
|
||||
}
|
||||
|
||||
ab->i++;
|
||||
LDR_CHECK_TIMEOUT((int)ab->i, (int)ab->num_files);
|
||||
}
|
||||
|
||||
// note: this is currently known to fail if there are no files in the list
|
||||
// - zlib.h says: Z_DATA_ERROR is returned if freed prematurely.
|
||||
// safe to ignore.
|
||||
comp_free(ab->ctx); ab->ctx = 0;
|
||||
(void)zip_archive_finish(ab->za);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
void archive_build_cancel(ArchiveBuildState* ab)
|
||||
{
|
||||
// note: the GUI may call us even though no build was ever in progress.
|
||||
// be sure to make all steps no-op if <ab> is zeroed (initial state) or
|
||||
// no build is in progress.
|
||||
|
||||
comp_free(ab->ctx); ab->ctx = 0;
|
||||
if(ab->za)
|
||||
(void)zip_archive_finish(ab->za);
|
||||
memset(ab, 0, sizeof(*ab));
|
||||
}
|
||||
|
||||
|
||||
LibError archive_build(const char* P_archive_filename, Filenames V_fns)
|
||||
{
|
||||
ArchiveBuildState ab;
|
||||
RETURN_ERR(archive_build_init(P_archive_filename, V_fns, &ab));
|
||||
for(;;)
|
||||
{
|
||||
int ret = archive_build_continue(&ab);
|
||||
RETURN_ERR(ret);
|
||||
if(ret == ERR_OK)
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
53
source/lib/res/file/archive_builder.h
Normal file
53
source/lib/res/file/archive_builder.h
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : archive_builder.h
|
||||
* Project : 0 A.D.
|
||||
* Description :
|
||||
*
|
||||
* @author Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003-2005 Jan Wassenberg
|
||||
*
|
||||
* Redistribution and/or modification are also permitted under the
|
||||
* terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation (version 2 or later, at your option).
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#ifndef ARCHIVE_BUILDER_H__
|
||||
#define ARCHIVE_BUILDER_H__
|
||||
|
||||
// array of pointers to VFS filenames (including path), terminated by a
|
||||
// NULL entry.
|
||||
typedef const char** Filenames;
|
||||
|
||||
// rationale: this is fairly lightweight and simple, so we don't bother
|
||||
// making it opaque.
|
||||
struct ArchiveBuildState
|
||||
{
|
||||
ZipArchive* za;
|
||||
uintptr_t ctx;
|
||||
Filenames V_fns;
|
||||
size_t num_files; // number of filenames in V_fns (excluding final 0)
|
||||
size_t i;
|
||||
};
|
||||
|
||||
extern LibError archive_build_init(const char* P_archive_filename, Filenames V_fns,
|
||||
ArchiveBuildState* ab);
|
||||
|
||||
// create an archive (overwriting previous file) and fill it with the given
|
||||
// files. compression method is chosen intelligently based on extension and
|
||||
// file entropy / achieved compression ratio.
|
||||
extern int archive_build_continue(ArchiveBuildState* ab);
|
||||
|
||||
extern void archive_build_cancel(ArchiveBuildState* ab);
|
||||
|
||||
extern LibError archive_build(const char* P_archive_filename, Filenames V_fns);
|
||||
|
||||
#endif // #ifndef ARCHIVE_BUILDER_H__
|
@ -75,8 +75,8 @@ cassert(sizeof(DirIterator_) <= sizeof(DirIterator));
|
||||
|
||||
|
||||
// prepare to iterate (once) over entries in the given directory.
|
||||
// returns a negative error code or 0 on success, in which case <d> is
|
||||
// ready for subsequent dir_next_ent calls and must be freed via dir_close.
|
||||
// if ERR_OK is returned, <d> is ready for subsequent dir_next_ent calls and
|
||||
// must be freed via dir_close.
|
||||
LibError dir_open(const char* P_path, DirIterator* d_)
|
||||
{
|
||||
DirIterator_* d = (DirIterator_*)d_;
|
||||
@ -105,7 +105,7 @@ LibError dir_open(const char* P_path, DirIterator* d_)
|
||||
|
||||
|
||||
// return ERR_DIR_END if all entries have already been returned once,
|
||||
// another negative error code, or 0 on success, in which case <ent>
|
||||
// another negative error code, or ERR_OK on success, in which case <ent>
|
||||
// describes the next (order is unspecified) directory entry.
|
||||
LibError dir_next_ent(DirIterator* d_, DirEnt* ent)
|
||||
{
|
||||
|
@ -124,12 +124,12 @@ struct DirEnt
|
||||
#define DIRENT_IS_DIR(p_ent) ((p_ent)->size == -1)
|
||||
|
||||
// prepare to iterate (once) over entries in the given directory.
|
||||
// returns a negative error code or 0 on success, in which case <d> is
|
||||
// ready for subsequent dir_next_ent calls and must be freed via dir_close.
|
||||
// if ERR_OK is returned, <d> is ready for subsequent dir_next_ent calls and
|
||||
// must be freed via dir_close.
|
||||
extern LibError dir_open(const char* P_path, DirIterator* d);
|
||||
|
||||
// return ERR_DIR_END if all entries have already been returned once,
|
||||
// another negative error code, or 0 on success, in which case <ent>
|
||||
// another negative error code, or ERR_OK on success, in which case <ent>
|
||||
// describes the next (order is unspecified) directory entry.
|
||||
extern LibError dir_next_ent(DirIterator* d, DirEnt* ent);
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "compression.h"
|
||||
#include "zip.h"
|
||||
#include "archive.h"
|
||||
#include "archive_builder.h"
|
||||
|
||||
#include "vfs.h"
|
||||
#include "vfs_mount.h"
|
||||
|
@ -73,8 +73,7 @@ enum TreeLookupFlags
|
||||
// a higher-priority file of the same name already exists
|
||||
// (used by VFile_reload when opening for writing).
|
||||
//
|
||||
// return 0 on success, or a negative error code
|
||||
// (in which case output params are undefined).
|
||||
// output params are only valid if ERR_OK is returned.
|
||||
extern LibError tree_lookup(const char* path, TFile** ptf, uint flags = 0);
|
||||
|
||||
// starting at VFS root, traverse <path> and pass back information
|
||||
@ -88,8 +87,7 @@ extern LibError tree_lookup(const char* path, TFile** ptf, uint flags = 0);
|
||||
// <path> can be to a file or dir (in which case it must end in '/',
|
||||
// to make sure the last component is treated as a directory).
|
||||
//
|
||||
// return 0 on success, or a negative error code
|
||||
// (in which case output params are undefined).
|
||||
// output params are only valid if ERR_OK is returned.
|
||||
extern LibError tree_lookup_dir(const char* path, TDir** ptd, uint flags = 0);
|
||||
|
||||
|
||||
|
@ -35,7 +35,6 @@ Handle ogl_shader_load(const char* fn, GLenum type);
|
||||
void ogl_shader_free(Handle& h);
|
||||
|
||||
// Attach a shader to the given OpenGL program.
|
||||
// Returns 0 on success and a negative error code otherwise.
|
||||
LibError ogl_shader_attach(GLhandleARB program, Handle& h);
|
||||
|
||||
|
||||
|
@ -193,9 +193,8 @@ extern LibError sys_clipboard_free(wchar_t* copy);
|
||||
// it is no longer needed and can be freed after this call returns.
|
||||
// hotspot (hx,hy) is the offset from its upper-left corner to the
|
||||
// position where mouse clicks are registered.
|
||||
// return: negative error code, or 0 on success. cursor is filled with
|
||||
// a pointer and undefined on failure. it must be sys_cursor_free-ed
|
||||
// when no longer needed.
|
||||
// cursor is only valid when ERR_OK is returned; in that case, it must be
|
||||
// sys_cursor_free-ed when no longer needed.
|
||||
extern LibError sys_cursor_create(uint w, uint h, void* bgra_img,
|
||||
uint hx, uint hy, void** cursor);
|
||||
|
||||
@ -229,14 +228,12 @@ extern LibError sys_error_description_r(int err, char* buf, size_t max_chars);
|
||||
wchar_t* sys_get_module_filename(void* addr, wchar_t* path);
|
||||
|
||||
// store full path to the current executable.
|
||||
// returns 0 or a negative error code.
|
||||
// useful for determining installation directory, e.g. for VFS.
|
||||
extern LibError sys_get_executable_name(char* n_path, size_t buf_size);
|
||||
|
||||
// have the user specify a directory via OS dialog.
|
||||
// stores its full path in the given buffer, which must hold at least
|
||||
// PATH_MAX chars.
|
||||
// returns 0 on success or a negative error code.
|
||||
extern LibError sys_pick_directory(char* n_path, size_t buf_size);
|
||||
|
||||
// execute the specified function once on each CPU.
|
||||
@ -244,9 +241,9 @@ extern LibError sys_pick_directory(char* n_path, size_t buf_size);
|
||||
// is never re-entered) in order of increasing OS CPU ID.
|
||||
// note: implemented by switching thread affinity masks and forcing
|
||||
// a reschedule, which is apparently not possible with POSIX.
|
||||
// return 0 on success or a negative error code on failure
|
||||
// (e.g. if OS is preventing us from running on some CPUs).
|
||||
// called from ia32.cpp get_cpu_count
|
||||
//
|
||||
// may fail if e.g. OS is preventing us from running on some CPUs.
|
||||
// called from ia32.cpp get_cpu_count.
|
||||
extern LibError sys_on_each_cpu(void (*cb)());
|
||||
|
||||
|
||||
|
@ -92,7 +92,6 @@ void dll_list_init(char* buf, size_t chars)
|
||||
|
||||
|
||||
// read DLL file version and append that and its name to the list.
|
||||
// return 0 on success or a negative error code.
|
||||
//
|
||||
// name should preferably be the complete path to DLL, to make sure
|
||||
// we don't inadvertently load another one on the library search path.
|
||||
|
@ -29,7 +29,6 @@
|
||||
extern void dll_list_init(char* buf, size_t chars);
|
||||
|
||||
// read DLL file version and append that and its name to the list.
|
||||
// return 0 on success or a negative error code.
|
||||
//
|
||||
// name should preferably be the complete path to DLL, to make sure
|
||||
// we don't inadvertently load another one on the library search path.
|
||||
|
@ -128,9 +128,9 @@ LibError win_get_cpu_info()
|
||||
// is never re-entered) in order of increasing OS CPU ID.
|
||||
// note: implemented by switching thread affinity masks and forcing
|
||||
// a reschedule, which is apparently not possible with POSIX.
|
||||
// return 0 on success or a negative error code on failure
|
||||
// (e.g. if OS is preventing us from running on some CPUs).
|
||||
// called from ia32.cpp get_cpu_count
|
||||
//
|
||||
// may fail if e.g. OS is preventing us from running on some CPUs.
|
||||
// called from ia32.cpp get_cpu_count.
|
||||
LibError sys_on_each_cpu(void (*cb)())
|
||||
{
|
||||
const HANDLE hProcess = GetCurrentProcess();
|
||||
|
@ -436,7 +436,7 @@ static LibError walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip
|
||||
|
||||
ret = cb(&sf, user_arg);
|
||||
// callback reports it's done; stop calling it and return that value.
|
||||
// (can be 0 for success, or a negative error code)
|
||||
// (can be either success or failure)
|
||||
if(ret != INFO_CB_CONTINUE)
|
||||
{
|
||||
debug_assert(ret <= 0); // shouldn't return > 0
|
||||
|
@ -468,9 +468,8 @@ static HCURSOR HCURSOR_from_ptr(void* p)
|
||||
// it is no longer needed and can be freed after this call returns.
|
||||
// hotspot (hx,hy) is the offset from its upper-left corner to the
|
||||
// position where mouse clicks are registered.
|
||||
// return: negative error code, or 0 on success. cursor is filled with
|
||||
// a pointer and undefined on failure. it must be sys_cursor_free-ed
|
||||
// when no longer needed.
|
||||
// cursor is only valid when ERR_OK is returned; in that case, it must be
|
||||
// sys_cursor_free-ed when no longer needed.
|
||||
LibError sys_cursor_create(uint w, uint h, void* bgra_img,
|
||||
uint hx, uint hy, void** cursor)
|
||||
{
|
||||
@ -593,7 +592,6 @@ wchar_t* sys_get_module_filename(void* addr, wchar_t* path)
|
||||
|
||||
|
||||
// store full path to the current executable.
|
||||
// returns 0 or a negative error code.
|
||||
// useful for determining installation directory, e.g. for VFS.
|
||||
inline LibError sys_get_executable_name(char* n_path, size_t buf_size)
|
||||
{
|
||||
@ -619,7 +617,6 @@ static int CALLBACK browse_cb(HWND hWnd, unsigned int msg, LPARAM UNUSED(lParam)
|
||||
// have the user specify a directory via OS dialog.
|
||||
// stores its full path in the given buffer, which must hold at least
|
||||
// PATH_MAX chars.
|
||||
// returns 0 on success or a negative error code.
|
||||
LibError sys_pick_directory(char* path, size_t buf_size)
|
||||
{
|
||||
// bring up dialog; set starting directory to current working dir.
|
||||
|
Loading…
Reference in New Issue
Block a user