From 1a7d67a97f35e4f67db342adadbdaf14ebf01e14 Mon Sep 17 00:00:00 2001 From: janwas Date: Tue, 6 Sep 2005 22:44:48 +0000 Subject: [PATCH] dyn_array: efficient expandable array that doesn't waste mem or relocate itself. TODO: self test and dox file: expose block size constant; always round user transfers up tex: transform() now receives what to change, not what to achieve. tex*: encoding works with DynArray+VFS backend GameSetup: free g_BuildingPlacer to avoid mem leak. fixed some warnings+bugs. This was SVN commit r2679. --- source/lib/dyn_array.cpp | 213 ++++++++++++++++++++++++++++ source/lib/dyn_array.h | 25 ++++ source/lib/res/file/file.cpp | 9 +- source/lib/res/file/file.h | 7 + source/lib/res/graphics/tex.cpp | 95 +++++++++---- source/lib/res/graphics/tex.h | 4 +- source/lib/res/graphics/tex_bmp.cpp | 15 +- source/lib/res/graphics/tex_codec.h | 11 +- source/lib/res/graphics/tex_dds.cpp | 13 +- source/lib/res/graphics/tex_jpg.cpp | 94 ++++++------ source/lib/res/graphics/tex_png.cpp | 74 +++++----- source/lib/res/graphics/tex_tga.cpp | 14 +- source/lib/sysdep/win/wdbg.cpp | 13 +- source/lib/sysdep/win/wdetect.cpp | 23 ++- source/lib/sysdep/win/wposix.cpp | 47 ++++-- source/ps/GameSetup/GameSetup.cpp | 2 + source/ps/Util.cpp | 4 +- source/scripting/ScriptGlue.cpp | 2 +- 18 files changed, 476 insertions(+), 189 deletions(-) create mode 100644 source/lib/dyn_array.cpp create mode 100644 source/lib/dyn_array.h diff --git a/source/lib/dyn_array.cpp b/source/lib/dyn_array.cpp new file mode 100644 index 0000000000..596b523103 --- /dev/null +++ b/source/lib/dyn_array.cpp @@ -0,0 +1,213 @@ +#include "precompiled.h" +#include "posix.h" + +#include "dyn_array.h" + + +static const size_t page_size = sysconf(_SC_PAGE_SIZE); + +static bool is_page_multiple(uintptr_t x) +{ + return (x % page_size) == 0; +} + +static size_t round_up_to_page(size_t size) +{ + return round_up(size, page_size); +} + + +static int validate_da(DynArray* da) +{ + if(!da) + return ERR_INVALID_PARAM; + u8* const base = da->base; + const size_t max_size_pa = da->max_size_pa; + const size_t cur_size = da->cur_size; + const size_t pos = da->pos; + const int prot = da->prot; + + if(debug_is_pointer_bogus(base)) + return -1; + if(!is_page_multiple((uintptr_t)base)) + return -2; + if(!is_page_multiple(max_size_pa)) + return -3; + if(cur_size > max_size_pa) + return -4; + if(pos > cur_size || pos > max_size_pa) + return -5; + if(prot & ~(PROT_READ|PROT_WRITE|PROT_EXEC)) + return -6; + + return 0; +} + +#define CHECK_DA(da) CHECK_ERR(validate_da(da)) + + +//----------------------------------------------------------------------------- +// very thin wrapper on top of sys/mman.h that makes the intent more obvious +// (its commit/decommit semantics are difficult to tell apart). + +static const int mmap_flags = MAP_PRIVATE|MAP_ANONYMOUS; + +static int mem_reserve(size_t size, u8** pp) +{ + void* ret = mmap(0, size, PROT_NONE, mmap_flags|MAP_NORESERVE, -1, 0); + if(ret == MAP_FAILED) + return ERR_NO_MEM; + *pp = (u8*)ret; + return 0; +} + +static int mem_release(u8* p, size_t size) +{ + return munmap(p, size); +} + +static int mem_commit(u8* p, size_t size, int prot) +{ + if(prot == PROT_NONE) + { + debug_warn("mem_commit: prot=PROT_NONE isn't allowed (misinterpreted by mmap)"); + return ERR_INVALID_PARAM; + } + void* ret = mmap(p, size, prot, mmap_flags|MAP_FIXED, -1, 0); + return (ret == MAP_FAILED)? -1 : 0; +} + +static int mem_decommit(u8* p, size_t size) +{ + void* ret = mmap(p, size, PROT_NONE, mmap_flags|MAP_NORESERVE|MAP_FIXED, -1, 0); + return (ret == MAP_FAILED)? -1 : 0; +} + +static int mem_protect(u8* p, size_t size, int prot) +{ + return mprotect(p, size, prot); +} + +//----------------------------------------------------------------------------- + + +int da_alloc(DynArray* da, size_t max_size) +{ + const size_t max_size_pa = round_up_to_page(max_size); + + u8* p; + CHECK_ERR(mem_reserve(max_size_pa, &p)); + + da->base = p; + da->max_size_pa = max_size_pa; + da->cur_size = 0; + da->pos = 0; + da->prot = PROT_READ|PROT_WRITE; + CHECK_DA(da); + return 0; +} + + +int da_free(DynArray* da) +{ + CHECK_DA(da); + + // latch pointer; wipe out the DynArray for safety + // (must be done here because mem_release may fail) + u8* p = da->base; + size_t size = da->max_size_pa; + memset(da, 0, sizeof(*da)); + + CHECK_ERR(mem_release(p, size)); + return 0; +} + + +int da_set_size(DynArray* da, size_t new_size) +{ + CHECK_DA(da); + + // determine how much to add/remove + const size_t cur_size_pa = round_up_to_page(da->cur_size); + const size_t new_size_pa = round_up_to_page(new_size); + if(new_size_pa > da->max_size_pa) + CHECK_ERR(ERR_INVALID_PARAM); + const ssize_t size_delta_pa = (ssize_t)new_size_pa - (ssize_t)cur_size_pa; + + u8* end = da->base + cur_size_pa; + // expanding + if(size_delta_pa > 0) + CHECK_ERR(mem_commit(end, size_delta_pa, da->prot)); + // shrinking + else if(size_delta_pa < 0) + CHECK_ERR(mem_decommit(end+size_delta_pa, size_delta_pa)); + // else: no change in page count, e.g. if going from size=1 to 2 + // (we don't want mem_* to have to handle size=0) + + da->cur_size = new_size; + CHECK_DA(da); + return 0; +} + + +int da_set_prot(DynArray* da, int prot) +{ + CHECK_DA(da); + + da->prot = prot; + CHECK_ERR(mem_protect(da->base, da->cur_size, prot)); + + CHECK_DA(da); + return 0; +} + + +int da_read(DynArray* da, void* data, size_t size) +{ + void* src = da->base + da->pos; + + // make sure we have enough data to read + da->pos += size; + if(da->pos > da->cur_size) + return -1; + + memcpy(data, src, size); + return 0; +} + + +int da_append(DynArray* da, const void* data, size_t size) +{ + RETURN_ERR(da_set_size(da, da->pos+size)); + memcpy(da->base+da->pos, data, size); + da->pos += size; + return 0; +} + + + +//----------------------------------------------------------------------------- +// built-in self test +//----------------------------------------------------------------------------- + +#if SELF_TEST_ENABLED +namespace test { + +static void test_api() +{ +} + +static void test_expand() +{ +} + +static void self_test() +{ + test_api(); + test_expand(); +} + +RUN_SELF_TEST; + +} // namespace test +#endif // #if SELF_TEST_ENABLED \ No newline at end of file diff --git a/source/lib/dyn_array.h b/source/lib/dyn_array.h new file mode 100644 index 0000000000..faf917590a --- /dev/null +++ b/source/lib/dyn_array.h @@ -0,0 +1,25 @@ +#include "lib/types.h" + +struct DynArray +{ + u8* base; + size_t max_size_pa; // reserved + size_t cur_size; // committed + size_t pos; + int prot; // applied to newly committed pages +}; + + +extern int da_alloc(DynArray* da, size_t max_size); + +extern int da_free(DynArray* da); + +extern int da_set_size(DynArray* da, size_t new_size); + +extern int da_set_prot(DynArray* da, int prot); + + + +extern int da_read(DynArray* da, void* data_dst, size_t size); + +extern int da_append(DynArray* da, const void* data_src, size_t size); diff --git a/source/lib/res/file/file.cpp b/source/lib/res/file/file.cpp index 6cbb4949dc..a758377012 100755 --- a/source/lib/res/file/file.cpp +++ b/source/lib/res/file/file.cpp @@ -351,7 +351,6 @@ int dir_open(const char* P_path, DirIterator* d_) CHECK_ERR(err); } - // (see pp declaration) return pp_set_dir(&d->pp, n_path); } @@ -1109,12 +1108,8 @@ debug_printf("file_io fd=%d size=%d ofs=%d\n", f->fd, data_size, data_ofs); const size_t ofs_misalign = data_ofs % BLOCK_SIZE; const size_t lead_padding = do_align? ofs_misalign : 0; // for convenience; used below. - - if(do_align) - { - actual_ofs -= (off_t)ofs_misalign; - actual_size = round_up(ofs_misalign + data_size, BLOCK_SIZE); - } + actual_ofs -= (off_t)lead_padding; + actual_size = round_up(lead_padding + data_size, BLOCK_SIZE); // skip aio code, use lowio diff --git a/source/lib/res/file/file.h b/source/lib/res/file/file.h index 1f0c8c1613..f54e517122 100755 --- a/source/lib/res/file/file.h +++ b/source/lib/res/file/file.h @@ -94,9 +94,12 @@ extern int file_rel_chdir(const char* argv0, const char* rel_path); // rationale: some private storage apart from opendir's DIR* is required // to support stat(). we prefer having the caller reserve room (on the stack) // rather than allocating dynamically (less efficient or more complicated). +// // this is an opaque struct to avoid exposing our internals and insulate // user code against changes; we verify at compile-time that the // public/private definitions match. +// note: cannot just typedef to DirIterator_ because other modules +// instantiate this. struct DirIterator { char opaque[512]; @@ -245,6 +248,10 @@ extern int file_discard_io(FileIo* io); // synchronous IO // +// user-specified offsets and transfer lengths must be multiples of this! +// (simplifies file_io) +const size_t FILE_BLOCK_SIZE = 64*KiB; + // return value: // < 0: failed; abort transfer. // >= 0: bytes output; continue. diff --git a/source/lib/res/graphics/tex.cpp b/source/lib/res/graphics/tex.cpp index e13bbd336c..30172d5f2e 100755 --- a/source/lib/res/graphics/tex.cpp +++ b/source/lib/res/graphics/tex.cpp @@ -73,22 +73,21 @@ static int validate_format(uint bpp, uint flags) // but is much easier to maintain than providing all<->all conversion paths. // // somewhat optimized (loops are hoisted, cache associativity accounted for) -static int plain_transform(Tex* t, uint new_format) +static int plain_transform(Tex* t, uint transforms) { // extract texture info - const int pending_transforms = t->flags ^ new_format; const uint w = t->w, h = t->h, bpp = t->bpp, flags = t->flags; u8* const img = tex_get_data(t); // sanity checks (not errors, we just can't handle these cases) // .. unknown transform - if(pending_transforms & ~(TEX_BGR|TEX_ORIENTATION)) + if(transforms & ~(TEX_BGR|TEX_ORIENTATION)) return TEX_CODEC_CANNOT_HANDLE; // .. img is not in "plain" format if(validate_format(bpp, flags) != 0) return TEX_CODEC_CANNOT_HANDLE; // .. nothing to do - if(!pending_transforms) + if(!transforms) return 0; // setup row source/destination pointers (simplifies outer loop) @@ -99,7 +98,7 @@ static int plain_transform(Tex* t, uint new_format) // avoid y*pitch multiply in row loop; instead, add row_ofs. void* clone_img = 0; // flipping rows (0,1,2 -> 2,1,0) - if(pending_transforms & TEX_ORIENTATION) + if(transforms & TEX_ORIENTATION) { // L1 cache is typically A2 => swapping in-place with a line buffer // leads to thrashing. we'll assume the whole texture*2 fits in cache, @@ -117,7 +116,7 @@ static int plain_transform(Tex* t, uint new_format) } // no BGR convert necessary - if(!(pending_transforms & TEX_BGR)) + if(!(transforms & TEX_BGR)) { for(uint y = 0; y < h; y++) { @@ -206,18 +205,22 @@ int tex_codec_register(const TexCodecVTbl* c) // note: we don't allocate the data param ourselves because this function is // needed for encoding, too (where data is already present). int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch, - int file_orientation, RowArray& rows) + uint src_flags, uint dst_orientation, RowArray& rows) { - debug_assert((file_orientation & ~TEX_ORIENTATION) == 0); + // convenience for caller: allow passing all flags. + const uint src_orientation = src_flags & TEX_ORIENTATION; + if(dst_orientation == 0) + dst_orientation = global_orientation; rows = (RowArray)malloc(h * sizeof(RowPtr)); if(!rows) return ERR_NO_MEM; // determine start position and direction - const bool flip = (file_orientation ^ global_orientation) != 0; - RowPtr pos = flip? data+pitch*(h-1) : data; - ssize_t add = flip? -(ssize_t)pitch : (ssize_t)pitch; + const bool flip = (src_orientation ^ dst_orientation) != 0; + RowPtr pos = flip? data+pitch*(h-1) : data; + const ssize_t add = flip? -(ssize_t)pitch : (ssize_t)pitch; + const RowPtr end = flip? data-pitch : data+pitch*h; for(size_t i = 0; i < h; i++) { @@ -225,15 +228,26 @@ int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch, pos += add; } + debug_assert(pos == end); return 0; } -int tex_codec_set_orientation(Tex* t, int file_orientation) +int tex_codec_set_orientation(Tex* t, uint file_orientation) { - int pending_transforms = file_orientation ^ global_orientation; - int new_flags = t->flags ^ pending_transforms; - return plain_transform(t, new_flags); + uint transforms = file_orientation ^ global_orientation; + return plain_transform(t, transforms); +} + + +int tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da) +{ + RETURN_ERR(tex_transform(t, transforms)); + + void* img_data = tex_get_data(t); const size_t img_size = tex_img_size(t); + RETURN_ERR(da_append(da, hdr, hdr_size)); + RETURN_ERR(da_append(da, img_data, img_size)); + return 0; } @@ -277,6 +291,9 @@ int tex_load_mem(Handle hm, const char* fn, Tex* t) // find codec that understands the data, and decode for(int i = 0; i < MAX_CODECS; i++) { + // MAX_CODECS isn't a tight bound and we have hit a 0 entry + if(!codecs[i]) + continue; const char* err_msg = 0; int err = codecs[i]->decode(p, size, t, &err_msg); if(err == TEX_CODEC_CANNOT_HANDLE) @@ -321,14 +338,21 @@ u8* tex_get_data(const Tex* t) return p + t->ofs; } +size_t tex_img_size(const Tex* t) +{ + return t->w * t->h * t->bpp/8; +} -int tex_transform(Tex* t, uint new_flags) + +int tex_transform(Tex* t, uint transforms) { // find codec that understands the data, and transform for(int i = 0; i < MAX_CODECS; i++) { - const char* err_msg = 0; - int err = codecs[i]->transform(t, new_flags); + // MAX_CODECS isn't a tight bound and we have hit a 0 entry + if(!codecs[i]) + continue; + int err = codecs[i]->transform(t, transforms); if(err == TEX_CODEC_CANNOT_HANDLE) continue; if(err == 0) @@ -338,12 +362,14 @@ int tex_transform(Tex* t, uint new_flags) } // last chance - return plain_transform(t, new_flags); + return plain_transform(t, transforms); } int tex_write(const char* fn, uint w, uint h, uint bpp, uint flags, void* in_img) { + int err = -1; + if(validate_format(bpp, flags) != 0) return ERR_TEX_FMT_INVALID; @@ -362,24 +388,37 @@ int tex_write(const char* fn, uint w, uint h, uint bpp, uint flags, void* in_img w, h, bpp, flags }; - u8* out; size_t out_size; + DynArray da; + const size_t max_out_size = (w*h*4 + 256*KiB)*2; + CHECK_ERR(da_alloc(&da, max_out_size)); + for(int i = 0; i < MAX_CODECS; i++) { + // MAX_CODECS isn't a tight bound and we have hit a 0 entry + if(!codecs[i]) + continue; const char* err_msg = 0; - int err = codecs[i]->encode(ext, &t, &out, &out_size, &err_msg); + err = codecs[i]->encode(ext, &t, &da, &err_msg); if(err == TEX_CODEC_CANNOT_HANDLE) continue; - if(err == 0) - goto have_codec; - debug_printf("tex_write(%s): %s: %s", codecs[i]->name, fn, err_msg); - CHECK_ERR(err); + if(err < 0) + { + debug_printf("tex_write(%s): %s: %s", codecs[i]->name, fn, err_msg); + WARN_ERR(err); + goto ret; + } + goto have_codec; // success } // no codec found return ERR_UNKNOWN_FORMAT; have_codec: - WARN_ERR(vfs_store(fn, out, out_size)); - free(out); - return 0; + size_t rounded_size = round_up(da.cur_size, FILE_BLOCK_SIZE); + CHECK_ERR(da_set_size(&da, rounded_size)); + WARN_ERR(vfs_store(fn, da.base, da.pos)); + err = 0; +ret: + WARN_ERR(da_free(&da)); + return err; } diff --git a/source/lib/res/graphics/tex.h b/source/lib/res/graphics/tex.h index eb5d5e0469..181436d5a2 100755 --- a/source/lib/res/graphics/tex.h +++ b/source/lib/res/graphics/tex.h @@ -72,7 +72,9 @@ extern int tex_load_mem(Handle hm, const char* fn, Tex* t); extern int tex_free(Tex* t); extern u8* tex_get_data(const Tex* t); -extern int tex_transform(Tex* t, uint new_flags); +extern size_t tex_img_size(const Tex* t); + +extern int tex_transform(Tex* t, uint transforms); extern int tex_write(const char* fn, uint w, uint h, uint bpp, uint flags, void* img); diff --git a/source/lib/res/graphics/tex_bmp.cpp b/source/lib/res/graphics/tex_bmp.cpp index c88678a05d..99185c68a0 100644 --- a/source/lib/res/graphics/tex_bmp.cpp +++ b/source/lib/res/graphics/tex_bmp.cpp @@ -34,7 +34,7 @@ struct BmpHeader #define BI_RGB 0 // biCompression -static int bmp_transform(Tex* t, int new_flags) +static int bmp_transform(Tex* UNUSED(t), uint UNUSED(transforms)) { return TEX_CODEC_CANNOT_HANDLE; } @@ -67,9 +67,7 @@ fail: const int orientation = (h_ < 0)? TEX_TOP_DOWN : TEX_BOTTOM_UP; const long h = abs(h_); - const size_t pitch = w * bpp/8; - const size_t img_size = h * pitch; - u8* const img = file + ofs; + const size_t img_size = tex_img_size(t); int flags = TEX_BGR; if(bpp == 32) @@ -101,21 +99,19 @@ fail: } -static int bmp_encode(const char* ext, Tex* t, u8** out, size_t* out_size, const char** perr_msg) +static int bmp_encode(const char* ext, Tex* t, DynArray* da, const char** UNUSED(perr_msg)) { if(stricmp(ext, "bmp")) return TEX_CODEC_CANNOT_HANDLE; -size_t img_size = t->w * t->h * t->bpp/8; - const size_t hdr_size = sizeof(BmpHeader); // needed for BITMAPFILEHEADER + const size_t img_size = tex_img_size(t); const size_t file_size = hdr_size + img_size; const long h = (t->flags & TEX_TOP_DOWN)? -(long)t->h : t->h; int transforms = t->flags; transforms &= ~TEX_ORIENTATION; // no flip needed - we can set top-down bit. transforms ^= TEX_BGR; // BMP is native BGR. - tex_transform(t, transforms); const BmpHeader hdr = { @@ -135,8 +131,7 @@ size_t img_size = t->w * t->h * t->bpp/8; (u32)img_size, // biSizeImage 0, 0, 0, 0 // unused (bi?PelsPerMeter, biClr*) }; - - return 0; + return tex_codec_write(t, transforms, &hdr, hdr_size, da); } TEX_CODEC_REGISTER(bmp); diff --git a/source/lib/res/graphics/tex_codec.h b/source/lib/res/graphics/tex_codec.h index de7439c740..92acf37e01 100644 --- a/source/lib/res/graphics/tex_codec.h +++ b/source/lib/res/graphics/tex_codec.h @@ -2,6 +2,7 @@ #define TEX_CODEC_H__ #include "tex.h" +#include "dyn_array.h" // rationale: no C++ to allow us to store const char* name in vtbl. @@ -17,9 +18,9 @@ struct TexCodecVTbl // rationale: some codecs cannot calculate the output size beforehand // (e.g. PNG output via libpng); we therefore require each one to // allocate memory itself and return the pointer. - int (*encode)(const char* ext, Tex* t, u8** out, size_t* out_size, const char** perr_msg); + int (*encode)(const char* ext, Tex* t, DynArray* da, const char** perr_msg); - int (*transform)(Tex* t, int new_flags); + int (*transform)(Tex* t, uint transforms); const char* name; }; @@ -52,9 +53,11 @@ extern int tex_codec_register(const TexCodecVTbl* c); typedef const u8* RowPtr; typedef RowPtr* RowArray; extern int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch, - int file_orientation, RowArray& rows); + uint src_flags, uint dst_orientation, RowArray& rows); -extern int tex_codec_set_orientation(Tex* t, int file_orientation); +extern int tex_codec_set_orientation(Tex* t, uint file_orientation); + +extern int tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da); struct MemSource diff --git a/source/lib/res/graphics/tex_dds.cpp b/source/lib/res/graphics/tex_dds.cpp index dc304328b1..15b9d4d3e3 100644 --- a/source/lib/res/graphics/tex_dds.cpp +++ b/source/lib/res/graphics/tex_dds.cpp @@ -191,11 +191,11 @@ static int dds_decompress(Tex* t) return 0; } -static int dds_transform(Tex* t, int new_flags) +static int dds_transform(Tex* t, uint transforms) { - const int dxt = t->flags & TEX_DXT, new_dxt = new_flags & TEX_DXT; + const int is_dxt = t->flags & TEX_DXT, transform_dxt = transforms & TEX_DXT; // requesting decompression - if(dxt && !new_dxt) + if(is_dxt && transform_dxt) return dds_decompress(t); // both are DXT (unsupported; there are no flags we can change while // compressed) or requesting compression (not implemented) or @@ -308,9 +308,12 @@ fail: } -static int dds_encode(const char* UNUSED(ext), Tex* UNUSED(t), u8** UNUSED(out), size_t* UNUSED(out_size), const char** UNUSED(perr_msg)) +static int dds_encode(const char* UNUSED(ext), Tex* UNUSED(t), DynArray* UNUSED(da), const char** UNUSED(perr_msg)) { - return ERR_NOT_IMPLEMENTED; + // note: do not return ERR_NOT_IMPLEMENTED et al. because that would + // break tex_write (which assumes either this, 0 or errors are returned). + return TEX_CODEC_CANNOT_HANDLE; + } TEX_CODEC_REGISTER(dds); diff --git a/source/lib/res/graphics/tex_jpg.cpp b/source/lib/res/graphics/tex_jpg.cpp index a7c68868fa..4fb8a688f0 100644 --- a/source/lib/res/graphics/tex_jpg.cpp +++ b/source/lib/res/graphics/tex_jpg.cpp @@ -197,30 +197,37 @@ GLOBAL(void) src_prepare(j_decompress_ptr cinfo, void* p, size_t size) typedef struct { struct jpeg_destination_mgr pub; /* public fields */ - JOCTET* buf; - // jpeg-6b interface needs a memory buffer + DynArray* da; } DstMgr; typedef DstMgr* DstPtr; -#define OUTPUT_BUF_SIZE 16*KiB /* choose an efficiently writeable size */ +#define OUTPUT_BUF_SIZE 64*KiB /* choose an efficiently writeable size */ + +// note: can't call dst_empty_output_buffer from dst_init or vice versa +// because only the former must advance da->pos. +static void make_room_in_buffer(j_compress_ptr cinfo) +{ + DstPtr dst = (DstPtr)cinfo->dest; + DynArray* da = dst->da; + + void* start = da->base + da->cur_size; + + if(da_set_size(da, da->cur_size+OUTPUT_BUF_SIZE) != 0) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dst->pub.next_output_byte = (JOCTET*)start; + dst->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} /* * Initialize destination --- called by jpeg_start_compress * before any data is actually written. */ - METHODDEF(void) dst_init(j_compress_ptr cinfo) { - DstPtr dst = (DstPtr)cinfo->dest; - - /* Allocate the output buffer --- it will be released when done with image */ - dst->buf = (JOCTET*)(*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_IMAGE, - OUTPUT_BUF_SIZE * sizeof(JOCTET)); - - dst->pub.next_output_byte = dst->buf; - dst->pub.free_in_buffer = OUTPUT_BUF_SIZE; + make_room_in_buffer(cinfo); } @@ -232,34 +239,20 @@ METHODDEF(void) dst_init(j_compress_ptr cinfo) * reset the pointer & count to the start of the buffer, and return TRUE * indicating that the buffer has been dumped. * -* In applications that need to be able to suspend compression due to output -* overrun, a FALSE return indicates that the buffer cannot be emptied now. -* In this situation, the compressor will return to its caller (possibly with -* an indication that it has not accepted all the supplied scanlines). The -* application should resume compression after it has made more room in the -* output buffer. Note that there are substantial restrictions on the use of -* suspension --- see the documentation. -* -* When suspending, the compressor will back up to a convenient restart point -* (typically the start of the current MCU). next_output_byte & free_in_buffer -* indicate where the restart point will be if the current call returns FALSE. -* Data beyond this point will be regenerated after resumption, so do not -* write it out when emptying the buffer externally. +* */ - METHODDEF(boolean) dst_empty_output_buffer(j_compress_ptr cinfo) { DstPtr dst = (DstPtr)cinfo->dest; + DynArray* da = dst->da; // writing out OUTPUT_BUF_SIZE-dst->pub.free_in_buffer bytes // sounds reasonable, but makes for broken output. -// if(vfs_io(dst->hf, OUTPUT_BUF_SIZE, (void**)&dst->buf) != OUTPUT_BUF_SIZE) -// ERREXIT(cinfo, JERR_FILE_WRITE); + da->pos += OUTPUT_BUF_SIZE; - dst->pub.next_output_byte = dst->buf; - dst->pub.free_in_buffer = OUTPUT_BUF_SIZE; + make_room_in_buffer(cinfo); - return TRUE; + return TRUE; // not suspended } @@ -271,17 +264,13 @@ METHODDEF(boolean) dst_empty_output_buffer(j_compress_ptr cinfo) * application must deal with any cleanup that should happen even * for error exit. */ - METHODDEF(void) dst_term(j_compress_ptr cinfo) { DstPtr dst = (DstPtr)cinfo->dest; + DynArray* da = dst->da; - // make sure any data left in the buffer is written out - const size_t bytes_in_buf = OUTPUT_BUF_SIZE - dst->pub.free_in_buffer; -// if(vfs_io(dst->hf, bytes_in_buf, (void**)&dst->buf) != (ssize_t)bytes_in_buf) -// ERREXIT(cinfo, JERR_FILE_WRITE); - - // flush file, if necessary. + // account for nbytes left in buffer + da->pos += OUTPUT_BUF_SIZE - dst->pub.free_in_buffer; } @@ -291,7 +280,7 @@ METHODDEF(void) dst_term(j_compress_ptr cinfo) * for closing it after finishing compression. */ -GLOBAL(void) dst_prepare(j_compress_ptr cinfo) +GLOBAL(void) dst_prepare(j_compress_ptr cinfo, DynArray* da) { /* The destination object is made permanent so that multiple JPEG images * can be written to the same file without re-executing jpeg_stdio_dest. @@ -308,6 +297,7 @@ GLOBAL(void) dst_prepare(j_compress_ptr cinfo) dst->pub.init_destination = dst_init; dst->pub.empty_output_buffer = dst_empty_output_buffer; dst->pub.term_destination = dst_term; + dst->da = da; } @@ -396,7 +386,7 @@ JpgErrorMgr::JpgErrorMgr(j_common_ptr cinfo) //----------------------------------------------------------------------------- -static int jpg_transform(Tex* t, int new_flags) +static int jpg_transform(Tex* UNUSED(t), uint UNUSED(transforms)) { return TEX_CODEC_CANNOT_HANDLE; } @@ -457,7 +447,7 @@ static int jpg_decode_impl(Tex* t, u8* file, size_t file_size, return ERR_NO_MEM; // read rows - RETURN_ERR(tex_codec_alloc_rows(img, h, pitch, TEX_TOP_DOWN, rows)); + RETURN_ERR(tex_codec_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows)); // could use cinfo->output_scanline to keep track of progress, // but we need to count lines_left anyway (paranoia). JSAMPARRAY row = (JSAMPARRAY)rows; @@ -495,9 +485,9 @@ static int jpg_decode_impl(Tex* t, u8* file, size_t file_size, static int jpg_encode_impl(Tex* t, jpeg_compress_struct* cinfo, - RowArray& rows, const char** perr_msg) + RowArray& rows, DynArray* da, const char** perr_msg) { - dst_prepare(cinfo); + dst_prepare(cinfo, da); // describe image format // required: @@ -514,12 +504,12 @@ static int jpg_encode_impl(Tex* t, jpeg_start_compress(cinfo, TRUE); // if BGR, convert to RGB. - const int bgr_transform = t->flags & TEX_BGR; // JPG is native RGB. - WARN_ERR(tex_transform(t, bgr_transform)); + const int transform_bgr = t->flags & TEX_BGR; // JPG is native RGB. + WARN_ERR(tex_transform(t, transform_bgr)); const size_t pitch = t->w * t->bpp / 8; u8* data = tex_get_data(t); - RETURN_ERR(tex_codec_alloc_rows(data, t->h, pitch, TEX_TOP_DOWN, rows)); + RETURN_ERR(tex_codec_alloc_rows(data, t->h, pitch, t->flags, TEX_TOP_DOWN, rows)); // could use cinfo->output_scanline to keep track of progress, @@ -551,6 +541,7 @@ static int jpg_decode(u8* file, size_t file_size, Tex* t, const char** perr_msg) if(file[0] != 0xff || file[1] == 0xd8) return TEX_CODEC_CANNOT_HANDLE; + int err = -1; // freed when ret is reached: // .. contains the JPEG decompression parameters and pointers to // working space (allocated as needed by the JPEG library). @@ -572,7 +563,7 @@ fail: jpeg_create_decompress(&cinfo); - int err = jpg_decode_impl(t, file, file_size, &cinfo, img_hm, rows, perr_msg); + err = jpg_decode_impl(t, file, file_size, &cinfo, img_hm, rows, perr_msg); if(err < 0) goto fail; @@ -584,11 +575,12 @@ ret: // limitation: palette images aren't supported -static int jpg_encode(const char* ext, Tex* t, u8** out, size_t* out_size, const char** perr_msg) +static int jpg_encode(const char* ext, Tex* t, DynArray* da, const char** perr_msg) { if(stricmp(ext, "jpg") && stricmp(ext, "jpeg")) return TEX_CODEC_CANNOT_HANDLE; + int err = -1; // freed when ret is reached: // .. contains the JPEG compression parameters and pointers to // working space (allocated as needed by the JPEG library). @@ -596,9 +588,6 @@ static int jpg_encode(const char* ext, Tex* t, u8** out, size_t* out_size, const // .. array of pointers to scanlines (see rationale above) RowArray rows = 0; - // freed when fail is reached: - // (mem buffer) - JpgErrorMgr jerr((j_common_ptr)&cinfo); if(setjmp(jerr.call_site)) { @@ -609,14 +598,13 @@ fail: jpeg_create_compress(&cinfo); - int err = jpg_encode_impl(t, &cinfo, rows, perr_msg); + err = jpg_encode_impl(t, &cinfo, rows, da, perr_msg); if(err < 0) goto fail; ret: jpeg_destroy_compress(&cinfo); // releases a "good deal" of memory free(rows); - // (free mem buffer) return err; } diff --git a/source/lib/res/graphics/tex_png.cpp b/source/lib/res/graphics/tex_png.cpp index 1b24355bb7..6c4c5469ab 100644 --- a/source/lib/res/graphics/tex_png.cpp +++ b/source/lib/res/graphics/tex_png.cpp @@ -42,30 +42,22 @@ // pass data from PNG file in memory to libpng static void io_read(png_struct* png_ptr, u8* data, png_size_t length) { - MemSource* ms = (MemSource*)png_ptr->io_ptr; - - void* src = (u8*)(ms->p + ms->pos); - - // make sure there's enough new data remaining in the buffer - ms->pos += length; - if(ms->pos > ms->size) - png_error(png_ptr, "png_read: not enough data to satisfy request!"); - - memcpy(data, src, length); + DynArray* da = (DynArray*)png_ptr->io_ptr; + if(da_read(da, data, length) != 0) + png_error(png_ptr, "io_read failed"); } // write libpng output to PNG file static void io_write(png_struct* png_ptr, u8* data, png_size_t length) { - void* p = (void*)data; - Handle hf = *(Handle*)png_ptr->io_ptr; - if(vfs_io(hf, length, &p) != (ssize_t)length) - png_error(png_ptr, "png_write: !"); + DynArray* da = (DynArray*)png_ptr->io_ptr; + if(da_append(da, data, length) != 0) + png_error(png_ptr, "io_write failed"); } -static void io_flush(png_structp) +static void io_flush(png_structp UNUSED(png_ptr)) { } @@ -73,7 +65,7 @@ static void io_flush(png_structp) //----------------------------------------------------------------------------- -static int png_transform(Tex* t, int new_flags) +static int png_transform(Tex* UNUSED(t), uint UNUSED(transforms)) { return TEX_CODEC_CANNOT_HANDLE; } @@ -88,8 +80,13 @@ static int png_decode_impl(Tex* t, u8* file, size_t file_size, png_structp png_ptr, png_infop info_ptr, Handle& img_hm, RowArray& rows, const char** perr_msg) { - MemSource ms = { file, file_size, 0 }; - png_set_read_fn(png_ptr, &ms, io_read); +DynArray da; +da.base = file; +da.max_size_pa = round_up(file_size, 4096); +da.cur_size = file_size; +da.pos = 0; +da.prot = PROT_READ|PROT_WRITE; + png_set_read_fn(png_ptr, &da, io_read); // read header and determine format png_read_info(png_ptr, info_ptr); @@ -97,7 +94,7 @@ static int png_decode_impl(Tex* t, u8* file, size_t file_size, int bit_depth, colour_type; png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &colour_type, 0, 0, 0); const size_t pitch = png_get_rowbytes(png_ptr, info_ptr); - const u32 bpp = (u32)(pitch / w * 8); + const u32 bpp = (u32)(pitch/w * 8); int flags = 0; if(bpp == 32) @@ -122,13 +119,13 @@ static int png_decode_impl(Tex* t, u8* file, size_t file_size, if(!img) return ERR_NO_MEM; - CHECK_ERR(tex_codec_alloc_rows(img, h, pitch, TEX_TOP_DOWN, rows)); + RETURN_ERR(tex_codec_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows)); png_read_image(png_ptr, (png_bytepp)rows); png_read_end(png_ptr, info_ptr); // success; make sure all data was consumed. - debug_assert(ms.p == file && ms.size == file_size && ms.pos == ms.size); + debug_assert(da.base == file && da.cur_size == file_size && da.pos == da.cur_size); // store image info // .. transparently switch handles - free the old (compressed) @@ -149,13 +146,10 @@ static int png_decode_impl(Tex* t, u8* file, size_t file_size, // "dtor / setjmp interaction" warning. static int png_encode_impl(Tex* t, png_structp png_ptr, png_infop info_ptr, - RowArray& rows, const char** perr_msg) + RowArray& rows, DynArray* da, const char** perr_msg) { UNUSED2(perr_msg); // we don't produce any error messages ATM. - const int png_transforms = (t->flags & TEX_BGR)? PNG_TRANSFORM_BGR : PNG_TRANSFORM_IDENTITY; - // PNG is native RGB. - const png_uint_32 w = t->w, h = t->h; const size_t pitch = w * t->bpp / 8; @@ -175,16 +169,16 @@ static int png_encode_impl(Tex* t, colour_type = PNG_COLOR_TYPE_RGB; break; } -/* - hf = vfs_open(fn, FILE_WRITE|FILE_NO_AIO); - CHECK_ERR(hf); - png_set_write_fn(png_ptr, &hf, io_write, io_flush); -*/ + + png_set_write_fn(png_ptr, da, io_write, io_flush); png_set_IHDR(png_ptr, info_ptr, w, h, 8, colour_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); u8* data = tex_get_data(t); - CHECK_ERR(tex_codec_alloc_rows(data, h, pitch, TEX_TOP_DOWN, rows)); + RETURN_ERR(tex_codec_alloc_rows(data, h, pitch, t->flags, TEX_TOP_DOWN, rows)); + + // PNG is native RGB. + const int png_transforms = (t->flags & TEX_BGR)? PNG_TRANSFORM_BGR : PNG_TRANSFORM_IDENTITY; png_set_rows(png_ptr, info_ptr, (png_bytepp)rows); png_write_png(png_ptr, info_ptr, png_transforms, 0); @@ -202,6 +196,7 @@ static int png_decode(u8* file, size_t file_size, Tex* t, const char** perr_msg) if(*(u32*)file != FOURCC('\x89','P','N','G')) return TEX_CODEC_CANNOT_HANDLE; + int err = -1; // freed when ret is reached: png_structp png_ptr = 0; png_infop info_ptr = 0; @@ -221,13 +216,13 @@ static int png_decode(u8* file, size_t file_size, Tex* t, const char** perr_msg) // setup error handling if(setjmp(png_jmpbuf(png_ptr))) { - // libpng longjmp-ed here after an error, or code below failed. + // libpng longjmps here after an error fail: mem_free_h(img_hm); goto ret; } - int err = png_decode_impl(t, file, file_size, png_ptr, info_ptr, img_hm, rows, perr_msg); + err = png_decode_impl(t, file, file_size, png_ptr, info_ptr, img_hm, rows, perr_msg); if(err < 0) goto fail; @@ -240,19 +235,17 @@ ret: // limitation: palette images aren't supported -static int png_encode(const char* ext, Tex* t, u8** out, size_t* UNUSED(out_size), const char** perr_msg) +static int png_encode(const char* ext, Tex* t, DynArray* da, const char** perr_msg) { if(stricmp(ext, "png")) return TEX_CODEC_CANNOT_HANDLE; + int err = -1; // freed when ret is reached: png_structp png_ptr = 0; png_infop info_ptr = 0; RowArray rows = 0; - // free when fail is reached: - // (mem buffer) - // allocate PNG structures; use default stderr and longjmp error handlers png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if(!png_ptr) @@ -264,21 +257,20 @@ static int png_encode(const char* ext, Tex* t, u8** out, size_t* UNUSED(out_size // setup error handling if(setjmp(png_jmpbuf(png_ptr))) { + // libpng longjmps here after an error fail: - // libjpg longjmp-ed here after an error, or code below failed. + // currently no cleanup to be done. goto ret; } - int err = png_encode_impl(t, png_ptr, info_ptr, rows, perr_msg); + err = png_encode_impl(t, png_ptr, info_ptr, rows, da, perr_msg); if(err < 0) goto fail; // shared cleanup ret: png_destroy_write_struct(&png_ptr, &info_ptr); - free(rows); - return err; } diff --git a/source/lib/res/graphics/tex_tga.cpp b/source/lib/res/graphics/tex_tga.cpp index b92d7988ab..ba11a2ab13 100644 --- a/source/lib/res/graphics/tex_tga.cpp +++ b/source/lib/res/graphics/tex_tga.cpp @@ -41,7 +41,7 @@ TgaHeader; #pragma pack(pop) -static int tga_transform(Tex* t, int new_flags) +static int tga_transform(Tex* UNUSED(t), uint UNUSED(transforms)) { return TEX_CODEC_CANNOT_HANDLE; } @@ -78,9 +78,7 @@ fail: const u8 alpha_bits = desc & 0x0f; const int orientation = (desc & TGA_TOP_DOWN)? TEX_TOP_DOWN : TEX_BOTTOM_UP; - u8* const img = file + hdr_size; - const size_t img_size = w * h * bpp/8; - + const size_t img_size = tex_img_size(t); int flags = 0; if(alpha_bits != 0) @@ -118,7 +116,7 @@ fail: } -static int tga_encode(const char* ext, Tex* t, u8** out, size_t* out_size, const char** perr_msg) +static int tga_encode(const char* ext, Tex* t, DynArray* da, const char** UNUSED(perr_msg)) { if(stricmp(ext, "tga")) return TEX_CODEC_CANNOT_HANDLE; @@ -130,11 +128,9 @@ static int tga_encode(const char* ext, Tex* t, u8** out, size_t* out_size, const img_desc |= 8; // size of alpha channel TgaImgType img_type = (t->flags & TEX_GREY)? TGA_GREY : TGA_TRUE_COLOUR; - // transform int transforms = t->flags; transforms &= ~TEX_ORIENTATION; // no flip needed - we can set top-down bit. transforms ^= TEX_BGR; // TGA is native BGR. - tex_transform(t, transforms); const TgaHeader hdr = { @@ -148,8 +144,8 @@ static int tga_encode(const char* ext, Tex* t, u8** out, size_t* out_size, const t->bpp, img_desc }; - - return 0; + const size_t hdr_size = sizeof(hdr); + return tex_codec_write(t, transforms, &hdr, hdr_size, da); } TEX_CODEC_REGISTER(tga); diff --git a/source/lib/sysdep/win/wdbg.cpp b/source/lib/sysdep/win/wdbg.cpp index 426c026605..2637b36d72 100755 --- a/source/lib/sysdep/win/wdbg.cpp +++ b/source/lib/sysdep/win/wdbg.cpp @@ -242,12 +242,15 @@ int debug_is_pointer_bogus(const void* p) return true; #endif - // note: we don't check alignment because nothing can be assumed about a - // pointer to the middle of a string and we mustn't reject valid pointers. - // nor do we bother checking the address against known stack/heap areas - // because that doesn't cover everything (e.g. DLLs, VirtualAlloc, etc.). + // notes: + // - we don't check alignment because nothing can be assumed about a + // string pointer and we mustn't reject any actually valid pointers. + // - nor do we bother checking the address against known stack/heap areas + // because that doesn't cover everything (e.g. DLLs, VirtualAlloc). + // - cannot use IsBadReadPtr because it accesses the mem + // (false alarm for reserved address space). - return IsBadReadPtr(p, 1) != 0; + return false; } diff --git a/source/lib/sysdep/win/wdetect.cpp b/source/lib/sysdep/win/wdetect.cpp index 4b00dda5ab..898d65f190 100755 --- a/source/lib/sysdep/win/wdetect.cpp +++ b/source/lib/sysdep/win/wdetect.cpp @@ -244,8 +244,8 @@ static int dll_list_add(const char* name) // didn't fit; complain sprintf(dll_list_pos, "..."); // (room was reserved above) - debug_warn("dll_list_add: not enough room"); dll_list_pos = 0; // poison pill, prevent further calls + debug_warn("dll_list_add: not enough room"); return ERR_BUF_SIZE; } @@ -376,7 +376,7 @@ int win_get_gfx_info() // ensures each OpenAL DLL is only listed once (even if present in several // directories on our search path). -typedef std::set DllSet; +typedef std::set StringSet; // if this directory entry is an OpenAL DLL, add it to our list. // (matches "*oal.dll" and "*OpenAL*", as with OpenAL router's search) @@ -385,7 +385,7 @@ typedef std::set DllSet; // note: we need the full DLL path for dll_list_add but DirEnt only gives us // the name. for efficiency, we append this in a PathPackage allocated by // add_oal_dlls_in_dir. -static void add_if_oal_dll(const DirEnt* ent, PathPackage* pp, DllSet* dlls) +static void add_if_oal_dll(const DirEnt* ent, PathPackage* pp, StringSet* dlls) { const char* fn = ent->name; @@ -400,13 +400,13 @@ static void add_if_oal_dll(const DirEnt* ent, PathPackage* pp, DllSet* dlls) if(!oal && !openal) return; - // skip if already in DllSet (i.e. has already been dll_list_add-ed) - std::pair ret = dlls->insert(fn); + // skip if already in StringSet (i.e. has already been dll_list_add-ed) + std::pair ret = dlls->insert(fn); if(!ret.second) // insert failed - element already there return; - WARN_ERR_RETURN(pp_append_file(pp, fn)); - dll_list_add(pp->path); + WARN_ERR_RETURN(pp_append_file(pp, fn)); // todo4 + (void)dll_list_add(pp->path); } @@ -416,7 +416,7 @@ static void add_if_oal_dll(const DirEnt* ent, PathPackage* pp, DllSet* dlls) // same name in the system directory. // // : no trailing. -static void add_oal_dlls_in_dir(const char* dir, DllSet* dlls) +static void add_oal_dlls_in_dir(const char* dir, StringSet* dlls) { int err; @@ -424,7 +424,7 @@ static void add_oal_dlls_in_dir(const char* dir, DllSet* dlls) (void)pp_set_dir(&pp, dir); DirIterator d; - WARN_ERR_RETURN(dir_open(dir, &d)); + WARN_ERR_RETURN(dir_open(dir, &d)); // TODO4 DirEnt ent; for(;;) // instead of while to avoid warning @@ -432,11 +432,10 @@ static void add_oal_dlls_in_dir(const char* dir, DllSet* dlls) err = dir_next_ent(&d, &ent); if(err == ERR_DIR_END) break; - debug_assert(err == 0); add_if_oal_dll(&ent, &pp, dlls); } - WARN_ERR(dir_close(&d)); + (void)dir_close(&d); } @@ -483,7 +482,7 @@ int win_get_snd_info() // and store in snd_drv_ver string. dll_list_init(snd_drv_ver, SND_DRV_VER_LEN); dll_list_add(ds_drv_path); - std::set dlls; // ensures uniqueness + StringSet dlls; // ensures uniqueness add_oal_dlls_in_dir(win_exe_dir, &dlls); add_oal_dlls_in_dir(win_sys_dir, &dlls); return 0; diff --git a/source/lib/sysdep/win/wposix.cpp b/source/lib/sysdep/win/wposix.cpp index a1303726aa..1814c682e2 100755 --- a/source/lib/sysdep/win/wposix.cpp +++ b/source/lib/sysdep/win/wposix.cpp @@ -615,12 +615,17 @@ int mprotect(void* addr, size_t len, int prot) const DWORD flNewProtect = win32_prot(prot); DWORD flOldProtect; // required by VirtualProtect BOOL ok = VirtualProtect(addr, len, flNewProtect, &flOldProtect); - return ok? 0 : -1; + if(!ok) + { + debug_warn("mprotect failed"); // todo4 + return -1; + } + return 0; } // called when flags & MAP_ANONYMOUS -static int map_mem(void* start, size_t len, int prot, int flags, int fd, void** pp) +static int mmap_mem(void* start, size_t len, int prot, int flags, int fd, void** pp) { // sanity checks. we don't care about these but enforce them to // ensure callers are compatible with mmap. @@ -631,9 +636,27 @@ static int map_mem(void* start, size_t len, int prot, int flags, int fd, void** debug_assert(flags & MAP_PRIVATE); // see explanation at MAP_NORESERVE definition. - DWORD flAllocationType = (flags & MAP_NORESERVE)? MEM_RESERVE : MEM_COMMIT; + bool want_commit = (prot != PROT_NONE && !(flags & MAP_NORESERVE)); + + if(!want_commit && start != 0 && flags & MAP_FIXED) + { + MEMORY_BASIC_INFORMATION mbi; + BOOL ok = VirtualQuery(start, &mbi, len); + debug_assert(ok); // todo4 + DWORD state = mbi.State; + if(state == MEM_COMMIT) + { + ok = VirtualFree(start, len, MEM_DECOMMIT); + debug_assert(ok); + *pp = 0; + return 0; + } + } + + DWORD op = want_commit? MEM_COMMIT : MEM_RESERVE; + DWORD flProtect = win32_prot(prot); - void* p = VirtualAlloc(start, len, flAllocationType, flProtect); + void* p = VirtualAlloc(start, len, op, flProtect); if(!p) return ERR_NO_MEM; *pp = p; @@ -645,7 +668,7 @@ static int map_mem(void* start, size_t len, int prot, int flags, int fd, void** // CreateFileMapping / MapViewOfFile. they only support read-only, // read/write and copy-on-write, so we dumb it down to that and later // set the correct (and more restrictive) permission via mprotect. -static int map_file_access(int prot, int flags, DWORD& flProtect, DWORD& dwAccess) +static int mmap_file_access(int prot, int flags, DWORD& flProtect, DWORD& dwAccess) { // assume read-only; other cases handled below. flProtect = PAGE_READONLY; @@ -678,7 +701,7 @@ static int map_file_access(int prot, int flags, DWORD& flProtect, DWORD& dwAcces } -static int map_file(void* start, size_t len, int prot, int flags, +static int mmap_file(void* start, size_t len, int prot, int flags, int fd, off_t ofs, void** pp) { debug_assert(fd != -1); // handled by mmap_mem @@ -698,7 +721,7 @@ static int map_file(void* start, size_t len, int prot, int flags, // MapViewOfFile. these are weaker than what PROT_* allows and // are augmented below by subsequently mprotect-ing. DWORD flProtect; DWORD dwAccess; - RETURN_ERR(map_file_access(prot, flags, flProtect, dwAccess)); + RETURN_ERR(mmap_file_access(prot, flags, flProtect, dwAccess)); // enough foreplay; now actually map. const HANDLE hMap = CreateFileMapping(hFile, 0, flProtect, 0, 0, (LPCSTR)0); @@ -718,7 +741,7 @@ static int map_file(void* start, size_t len, int prot, int flags, return ERR_NO_MEM; // slap on correct (more restrictive) permissions. - WARN_ERR(mprotect(p, len, prot)); + (void)mprotect(p, len, prot); WIN_RESTORE_LAST_ERROR; *pp = p; @@ -731,9 +754,9 @@ void* mmap(void* start, size_t len, int prot, int flags, int fd, off_t ofs) void* p; int err; if(flags & MAP_ANONYMOUS) - err = map_mem(start, len, prot, flags, fd, &p); + err = mmap_mem(start, len, prot, flags, fd, &p); else - err = map_file(start, len, prot, flags, fd, ofs, &p); + err = mmap_file(start, len, prot, flags, fd, ofs, &p); if(err < 0) { WARN_ERR(err); @@ -756,7 +779,7 @@ int munmap(void* start, size_t UNUSED(len)) // both failed if(!ok) { - debug_warn("munmap failed"); + debug_warn("munmap failed"); // todo4 return -1; } return 0; @@ -925,6 +948,8 @@ long sysconf(int name) switch(name) { case _SC_PAGESIZE: + // note: don't add _SC_PAGE_SIZE - they are different names but + // have the same value. return page_size; case _SC_PHYS_PAGES: diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index 47fe88729c..fe0c2d8d81 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -625,8 +625,10 @@ void Shutdown() delete &g_Mouseover; delete &g_Selection; + delete &g_BuildingPlacer; delete &g_Pathfinder; + // Managed by CWorld // delete &g_EntityManager; diff --git a/source/ps/Util.cpp b/source/ps/Util.cpp index 70a0f65344..047e192c3f 100644 --- a/source/ps/Util.cpp +++ b/source/ps/Util.cpp @@ -169,12 +169,12 @@ void WriteScreenshot(const char* extension) // could fix via enumerating all files, but it's not worth it ATM. char fn[VFS_MAX_PATH]; - const char* file_format_string = "screenshots/screenshot%04d.%s"; // %04d -> always 4 digits, so sorting by filename works correctly. + const char* file_format_string = "screenshots/screenshot%04d.%s"; static int next_num = 1; do - sprintf(fn, file_format_string, next_num++, extension); + sprintf(fn, file_format_string, next_num++, extension); while(vfs_exists(fn)); const int w = g_xres, h = g_yres; diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index abe5d89a62..459afc7504 100755 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -744,7 +744,7 @@ JSBool getGlobal( JSContext* cx, JSObject* globalObject, uint argc, jsval* argv, // Activates the building placement cursor for placing a building. // params: templateName - the name of the entity to place. // returns: true if cursor was activated, false if cursor was already active. -JSBool startPlacing( JSContext* cx, JSObject* globalObject, uint argc, jsval* argv, jsval* rval ) +JSBool startPlacing( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval* argv, jsval* rval ) { CStrW name; if(argc == 0) {